예제 #1
0
static void global_close_pipe(struct wpa_global_dst *dst)
{
	wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);

	if (dst->overlap.hEvent) {
		eloop_unregister_event(dst->overlap.hEvent,
				       sizeof(dst->overlap.hEvent));
		CloseHandle(dst->overlap.hEvent);
	}

	if (dst->pipe != INVALID_HANDLE_VALUE) {
		/*
		 * Could use FlushFileBuffers() here to guarantee that all data
		 * gets delivered to the client, but that can block, so let's
		 * not do this for now.
		 * FlushFileBuffers(dst->pipe);
		 */
		CloseHandle(dst->pipe);
	}

	if (dst->prev)
		dst->prev->next = dst->next;
	else
		dst->priv->ctrl_dst = dst->next;
	if (dst->next)
		dst->next->prev = dst->prev;

	os_free(dst->rsp_buf);
	os_free(dst);
}
void l2_packet_deinit(struct l2_packet_data *l2)
{
	if (l2 == NULL)
		return;

	if (l2_ndisuio_global) {
		l2_ndisuio_global->refcount--;
		l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;
		if (l2_ndisuio_global->refcount) {
			wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "
				   "ethertype to %04x",
				   l2_ndisuio_global->first_proto);
			l2_ndisuio_set_ether_type(
				l2_ndisuio_global->first_proto);
			return;
		}

#ifdef _WIN32_WCE
		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "
			   "stop");
		SetEvent(l2_ndisuio_global->stop_request);
		/*
		 * Cancel pending ReadFile() in the RX thread (if we were still
		 * connected at this point).
		 */
		if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
				     IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,
				     NULL)) {
			wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "
				   "failed: %d", (int) GetLastError());
			/* RX thread will exit blocking ReadFile once NDISUIO
			 * notices that the adapter is disconnected. */
		}
		WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);
		wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");
		CloseHandle(l2_ndisuio_global->rx_thread);
		CloseHandle(l2_ndisuio_global->stop_request);
		CloseHandle(l2_ndisuio_global->ready_for_read);
		CloseHandle(l2_ndisuio_global->rx_processed);
#endif /* _WIN32_WCE */

		os_free(l2_ndisuio_global);
		l2_ndisuio_global = NULL;
	}

#ifndef _WIN32_WCE
	CancelIo(driver_ndis_get_ndisuio_handle());
#endif /* _WIN32_WCE */

	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
	CloseHandle(l2->rx_avail);
	os_free(l2);
}
static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
{
        struct l2_packet_data *l2 = eloop_ctx;

        if (l2->rx_thread_done &&
            WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
                wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
                           "exit - kill it\n");
                TerminateThread(l2->rx_thread, 0);
        }
        CloseHandle(l2->rx_thread_done);
        CloseHandle(l2->rx_thread);
        if (l2->pcap)
                pcap_close(l2->pcap);
        eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
        CloseHandle(l2->rx_avail);
        CloseHandle(l2->rx_done);
        CloseHandle(l2->rx_notify);
        os_free(l2);
}
struct l2_packet_data * l2_packet_init(
	const char *ifname, const u8 *own_addr, unsigned short protocol,
	void (*rx_callback)(void *ctx, const u8 *src_addr,
			    const u8 *buf, size_t len),
	void *rx_callback_ctx, int l2_hdr)
{
	struct l2_packet_data *l2;

	if (l2_ndisuio_global == NULL) {
		l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));
		if (l2_ndisuio_global == NULL)
			return NULL;
		l2_ndisuio_global->first_proto = protocol;
	}
	if (l2_ndisuio_global->refcount >= 2) {
		wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "
			   "simultaneous connections allowed");
		return NULL;
	}
	l2_ndisuio_global->refcount++;

	l2 = os_zalloc(sizeof(struct l2_packet_data));
	if (l2 == NULL)
		return NULL;
	l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;

	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
	l2->rx_callback = rx_callback;
	l2->rx_callback_ctx = rx_callback_ctx;
	l2->l2_hdr = l2_hdr;

	if (own_addr)
		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);

	if (l2_ndisuio_set_ether_type(protocol) < 0) {
		os_free(l2);
		return NULL;
	}

	if (l2_ndisuio_global->refcount > 1) {
		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "
			   "filtering ethertype to %04x", protocol);
		if (l2_ndisuio_global->l2[0])
			l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;
		return l2;
	}

	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (l2->rx_avail == NULL) {
		os_free(l2);
		return NULL;
	}

	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
			     l2_packet_rx_event, l2, NULL);

#ifdef _WIN32_WCE
	l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);
	/*
	 * This event is being set based on media connect/disconnect
	 * notifications in driver_ndis.c.
	 */
	l2_ndisuio_global->ready_for_read =
		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
	l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (l2_ndisuio_global->stop_request == NULL ||
	    l2_ndisuio_global->ready_for_read == NULL ||
	    l2_ndisuio_global->rx_processed == NULL) {
		if (l2_ndisuio_global->stop_request) {
			CloseHandle(l2_ndisuio_global->stop_request);
			l2_ndisuio_global->stop_request = NULL;
		}
		if (l2_ndisuio_global->ready_for_read) {
			CloseHandle(l2_ndisuio_global->ready_for_read);
			l2_ndisuio_global->ready_for_read = NULL;
		}
		if (l2_ndisuio_global->rx_processed) {
			CloseHandle(l2_ndisuio_global->rx_processed);
			l2_ndisuio_global->rx_processed = NULL;
		}
		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
		os_free(l2);
		return NULL;
	}

	l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,
						    l2_packet_rx_thread, l2, 0,
						    NULL);
	if (l2_ndisuio_global->rx_thread == NULL) {
		wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "
			   "thread: %d", (int) GetLastError());
		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
		CloseHandle(l2_ndisuio_global->stop_request);
		l2_ndisuio_global->stop_request = NULL;
		os_free(l2);
		return NULL;
	}
#else /* _WIN32_WCE */
	l2_ndisuio_start_read(l2, 0);
#endif /* _WIN32_WCE */

	return l2;
}