static status_t
compat_close(void *cookie)
{
	struct ifnet *ifp = cookie;

	if_printf(ifp, "compat_close()\n");

	atomic_or(&ifp->flags, DEVICE_CLOSED);

	wlan_close(cookie);

	release_sem_etc(ifp->receive_sem, 1, B_RELEASE_ALL);

	return B_OK;
}
Example #2
0
status_t
wlan_control(void* cookie, uint32 op, void* arg, size_t length)
{
	struct ifnet* ifp = (struct ifnet*)cookie;

	switch (op) {
		case BOSII_DEVICE:
			return B_OK;

		case BOSII_DETECT_NETWORKS:
		{
			struct ieee80211req request;
			struct ieee80211_scan_req scanRequest;

			if_printf(ifp, "%s: BOSII_DETECT_NETWORKS\n", __func__);
			memset(&scanRequest, 0, sizeof(scanRequest));
			scanRequest.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
				| IEEE80211_IOC_SCAN_NOPICK
				| IEEE80211_IOC_SCAN_ONCE;
			scanRequest.sr_duration = 10000; // 10 s
			scanRequest.sr_nssid = 0;

			memset(&request, 0, sizeof(request));
			request.i_type = IEEE80211_IOC_SCAN_REQ;
			request.i_data = &scanRequest;
			request.i_len = sizeof(scanRequest);

			ifp->if_ioctl(ifp, SIOCS80211, (caddr_t)&request);

			acquire_sem_etc(ifp->scan_done_sem, 1, B_RELATIVE_TIMEOUT,
				10000000); // 10 s

			return B_OK;
		}

		case BOSII_GET_DETECTED_NETWORKS:
		{
			struct ieee80211req request;
			struct ifreq ifRequest;
			struct route_entry* networkRequest = &ifRequest.ifr_route;

			if_printf(ifp, "%s: BOSII_GET_DETECTED_NETWORKS\n", __func__);

			if (length < sizeof(struct ieee80211req_scan_result))
				return B_BAD_VALUE;

			if (user_memcpy(&ifRequest, arg, sizeof(ifRequest)) < B_OK)
				return B_BAD_ADDRESS;

			memset(&request, 0, sizeof(request));
			request.i_type = IEEE80211_IOC_SCAN_RESULTS;
			request.i_len = length;
			request.i_data = networkRequest->destination;

			// After return value of request.i_data is copied into user
			// space, already.
			if (ifp->if_ioctl(ifp, SIOCG80211, (caddr_t)&request) < B_OK)
				return B_BAD_ADDRESS;

			// Tell the user space how much data was copied
			networkRequest->mtu = request.i_len;
			if (user_memcpy(&((struct ifreq*)arg)->ifr_route.mtu,
				&networkRequest->mtu, sizeof(networkRequest->mtu)) < B_OK)
				return B_BAD_ADDRESS;

			return B_OK;
		}

		case BOSII_JOIN_NETWORK:
		{
			struct ieee80211req request;
			struct ifreq ifRequest;
			struct route_entry* networkRequest = &ifRequest.ifr_route;
			struct ieee80211req_scan_result network;

			if_printf(ifp, "%s: BOSII_JOIN_NETWORK\n", __func__);

			if (length < sizeof(struct ifreq))
				return B_BAD_VALUE;

			if (user_memcpy(&ifRequest, arg, sizeof(ifRequest)) != B_OK
				|| user_memcpy(&network, networkRequest->source,
						sizeof(ieee80211req_scan_result)) != B_OK)
				return B_BAD_ADDRESS;

			memset(&request, 0, sizeof(ieee80211req));

			request.i_type = IEEE80211_IOC_SSID;
			request.i_val = 0;
			request.i_len = network.isr_ssid_len;
			request.i_data = (uint8*)networkRequest->source
				+ network.isr_ie_off;
			if (ifp->if_ioctl(ifp, SIOCS80211, (caddr_t)&request) < B_OK)
				return B_ERROR;

			// wait for network join

			return B_OK;
		}

		case BOSII_GET_ASSOCIATED_NETWORK:
		{
			struct ieee80211req request;
			struct ifreq ifRequest;
			struct route_entry* networkRequest = &ifRequest.ifr_route;

			if_printf(ifp, "%s: BOSII_GET_ASSOCIATED_NETWORK\n", __func__);

			if (length < sizeof(struct ieee80211req_sta_req))
				return B_BAD_VALUE;

			if (user_memcpy(&ifRequest, arg, sizeof(ifRequest)) < B_OK)
				return B_BAD_ADDRESS;

			// Only want station information about associated network.
			memset(&request, 0, sizeof(request));
			request.i_type = IEEE80211_IOC_BSSID;
			request.i_len = IEEE80211_ADDR_LEN;
			request.i_data = ((struct ieee80211req_sta_req*)networkRequest->
					destination)->is_u.macaddr;
			if (ifp->if_ioctl(ifp, SIOCG80211, (caddr_t)&request) < B_OK)
				return B_BAD_ADDRESS;

			request.i_type = IEEE80211_IOC_STA_INFO;
			request.i_len = length;
			request.i_data = networkRequest->destination;

			// After return value of request.i_data is copied into user
			// space, already.
			if (ifp->if_ioctl(ifp, SIOCG80211, (caddr_t)&request) < B_OK)
				return B_BAD_ADDRESS;

			// Tell the user space how much data was copied
			networkRequest->mtu = request.i_len;
			if (user_memcpy(&((struct ifreq*)arg)->ifr_route.mtu,
					&networkRequest->mtu, sizeof(networkRequest->mtu)) != B_OK)
				return B_BAD_ADDRESS;

			return B_OK;
		}

		case SIOCG80211:
		case SIOCS80211:
		{
			// Allowing FreeBSD based WLAN ioctls to pass, as those will become
			// the future Haiku WLAN ioctls anyway.

			// FreeBSD drivers assume that the request structure has already
			// been copied into kernel space
			struct ieee80211req request;
			if (user_memcpy(&request, arg, sizeof(struct ieee80211req)) != B_OK)
				return B_BAD_ADDRESS;

			if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_UP)
				return wlan_open(cookie);
			else if (request.i_type == IEEE80211_IOC_HAIKU_COMPAT_WLAN_DOWN)
				return wlan_close(cookie);

			TRACE("wlan_control: %ld, %d\n", op, request.i_type);
			status_t status = ifp->if_ioctl(ifp, op, (caddr_t)&request);
			if (status != B_OK)
				return status;

			if (op == SIOCG80211 && user_memcpy(arg, &request,
					sizeof(struct ieee80211req)) != B_OK)
				return B_BAD_ADDRESS;
			return B_OK;
		}

		case SIOCSIFFLAGS:
		case SIOCSIFMEDIA:
		case SIOCGIFMEDIA:
		case SIOCSIFMTU:
			// Requests that make it here always come from the kernel
			return ifp->if_ioctl(ifp, op, (caddr_t)arg);
	}

	return B_BAD_VALUE;
}