diff options
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 101 |
1 files changed, 55 insertions, 46 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index cb362b086ff6..dc3083ba8380 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -2319,68 +2319,77 @@ static const struct iw_handler_def rndis_iw_handlers = { | |||
2319 | }; | 2319 | }; |
2320 | 2320 | ||
2321 | 2321 | ||
2322 | static void rndis_wlan_worker(struct work_struct *work) | 2322 | static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) |
2323 | { | 2323 | { |
2324 | struct rndis_wlan_private *priv = | ||
2325 | container_of(work, struct rndis_wlan_private, work); | ||
2326 | struct usbnet *usbdev = priv->usbdev; | ||
2327 | union iwreq_data evt; | ||
2328 | unsigned char bssid[ETH_ALEN]; | ||
2329 | struct ndis_80211_assoc_info *info; | 2324 | struct ndis_80211_assoc_info *info; |
2330 | int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32; | 2325 | union iwreq_data evt; |
2326 | u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; | ||
2327 | u8 bssid[ETH_ALEN]; | ||
2331 | int ret, offset; | 2328 | int ret, offset; |
2332 | 2329 | ||
2333 | if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) { | 2330 | memset(assoc_buf, 0, sizeof(assoc_buf)); |
2334 | netif_carrier_on(usbdev->net); | 2331 | info = (void *)assoc_buf; |
2335 | 2332 | ||
2336 | info = kzalloc(assoc_size, GFP_KERNEL); | 2333 | netif_carrier_on(usbdev->net); |
2337 | if (!info) | 2334 | |
2338 | goto get_bssid; | 2335 | /* Get association info IEs from device and send them back to |
2339 | 2336 | * userspace. */ | |
2340 | /* Get association info IEs from device and send them back to | 2337 | ret = get_association_info(usbdev, info, sizeof(assoc_buf)); |
2341 | * userspace. */ | 2338 | if (!ret) { |
2342 | ret = get_association_info(usbdev, info, assoc_size); | 2339 | evt.data.length = le32_to_cpu(info->req_ie_length); |
2343 | if (!ret) { | 2340 | if (evt.data.length > 0) { |
2344 | evt.data.length = le32_to_cpu(info->req_ie_length); | 2341 | offset = le32_to_cpu(info->offset_req_ies); |
2345 | if (evt.data.length > 0) { | 2342 | wireless_send_event(usbdev->net, |
2346 | offset = le32_to_cpu(info->offset_req_ies); | 2343 | IWEVASSOCREQIE, &evt, |
2347 | wireless_send_event(usbdev->net, | 2344 | (char *)info + offset); |
2348 | IWEVASSOCREQIE, &evt, | ||
2349 | (char *)info + offset); | ||
2350 | } | ||
2351 | |||
2352 | evt.data.length = le32_to_cpu(info->resp_ie_length); | ||
2353 | if (evt.data.length > 0) { | ||
2354 | offset = le32_to_cpu(info->offset_resp_ies); | ||
2355 | wireless_send_event(usbdev->net, | ||
2356 | IWEVASSOCRESPIE, &evt, | ||
2357 | (char *)info + offset); | ||
2358 | } | ||
2359 | } | 2345 | } |
2360 | 2346 | ||
2361 | kfree(info); | 2347 | evt.data.length = le32_to_cpu(info->resp_ie_length); |
2362 | 2348 | if (evt.data.length > 0) { | |
2363 | get_bssid: | 2349 | offset = le32_to_cpu(info->offset_resp_ies); |
2364 | ret = get_bssid(usbdev, bssid); | 2350 | wireless_send_event(usbdev->net, |
2365 | if (!ret) { | 2351 | IWEVASSOCRESPIE, &evt, |
2366 | evt.data.flags = 0; | 2352 | (char *)info + offset); |
2367 | evt.data.length = 0; | ||
2368 | memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); | ||
2369 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); | ||
2370 | } | 2353 | } |
2371 | 2354 | ||
2372 | usbnet_resume_rx(usbdev); | 2355 | usbnet_resume_rx(usbdev); |
2373 | } | 2356 | } |
2374 | 2357 | ||
2375 | if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { | 2358 | ret = get_bssid(usbdev, bssid); |
2376 | netif_carrier_off(usbdev->net); | 2359 | if (!ret) { |
2377 | |||
2378 | evt.data.flags = 0; | 2360 | evt.data.flags = 0; |
2379 | evt.data.length = 0; | 2361 | evt.data.length = 0; |
2380 | memset(evt.ap_addr.sa_data, 0, ETH_ALEN); | 2362 | memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); |
2381 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); | 2363 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); |
2382 | } | 2364 | } |
2383 | 2365 | ||
2366 | usbnet_resume_rx(usbdev); | ||
2367 | } | ||
2368 | |||
2369 | static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) | ||
2370 | { | ||
2371 | union iwreq_data evt; | ||
2372 | |||
2373 | netif_carrier_off(usbdev->net); | ||
2374 | |||
2375 | evt.data.flags = 0; | ||
2376 | evt.data.length = 0; | ||
2377 | memset(evt.ap_addr.sa_data, 0, ETH_ALEN); | ||
2378 | wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); | ||
2379 | } | ||
2380 | |||
2381 | static void rndis_wlan_worker(struct work_struct *work) | ||
2382 | { | ||
2383 | struct rndis_wlan_private *priv = | ||
2384 | container_of(work, struct rndis_wlan_private, work); | ||
2385 | struct usbnet *usbdev = priv->usbdev; | ||
2386 | |||
2387 | if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) | ||
2388 | rndis_wlan_do_link_up_work(usbdev); | ||
2389 | |||
2390 | if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) | ||
2391 | rndis_wlan_do_link_down_work(usbdev); | ||
2392 | |||
2384 | if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) | 2393 | if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) |
2385 | set_multicast_list(usbdev); | 2394 | set_multicast_list(usbdev); |
2386 | } | 2395 | } |