diff options
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 190 |
1 files changed, 185 insertions, 5 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 25550692dda6..3fc2df86278f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
141 | set_mandatory_flags_band(wiphy->bands[band], band); | 141 | set_mandatory_flags_band(wiphy->bands[band], band); |
142 | } | 142 | } |
143 | 143 | ||
144 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | 144 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
145 | struct key_params *params, int key_idx, | ||
145 | const u8 *mac_addr) | 146 | const u8 *mac_addr) |
146 | { | 147 | { |
148 | int i; | ||
149 | |||
147 | if (key_idx > 5) | 150 | if (key_idx > 5) |
148 | return -EINVAL; | 151 | return -EINVAL; |
149 | 152 | ||
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | |||
197 | } | 200 | } |
198 | } | 201 | } |
199 | 202 | ||
203 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) | ||
204 | if (params->cipher == rdev->wiphy.cipher_suites[i]) | ||
205 | break; | ||
206 | if (i == rdev->wiphy.n_cipher_suites) | ||
207 | return -EINVAL; | ||
208 | |||
200 | return 0; | 209 | return 0; |
201 | } | 210 | } |
202 | 211 | ||
@@ -265,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
265 | switch (ae) { | 274 | switch (ae) { |
266 | case 0: | 275 | case 0: |
267 | return 6; | 276 | return 6; |
268 | case 1: | 277 | case MESH_FLAGS_AE_A4: |
269 | return 12; | 278 | return 12; |
270 | case 2: | 279 | case MESH_FLAGS_AE_A5_A6: |
271 | return 18; | 280 | return 18; |
272 | case 3: | 281 | case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): |
273 | return 24; | 282 | return 24; |
274 | default: | 283 | default: |
275 | return 6; | 284 | return 6; |
@@ -324,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | |||
324 | } | 333 | } |
325 | break; | 334 | break; |
326 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
327 | if (iftype != NL80211_IFTYPE_STATION || | 336 | if ((iftype != NL80211_IFTYPE_STATION && |
337 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
328 | (is_multicast_ether_addr(dst) && | 338 | (is_multicast_ether_addr(dst) && |
329 | !compare_ether_addr(src, addr))) | 339 | !compare_ether_addr(src, addr))) |
330 | return -1; | 340 | return -1; |
341 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||
342 | struct ieee80211s_hdr *meshdr = | ||
343 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
344 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||
345 | if (meshdr->flags & MESH_FLAGS_AE_A4) | ||
346 | memcpy(src, meshdr->eaddr1, ETH_ALEN); | ||
347 | } | ||
331 | break; | 348 | break; |
332 | case cpu_to_le16(0): | 349 | case cpu_to_le16(0): |
333 | if (iftype != NL80211_IFTYPE_ADHOC) | 350 | if (iftype != NL80211_IFTYPE_ADHOC) |
@@ -502,3 +519,166 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb) | |||
502 | return dscp >> 5; | 519 | return dscp >> 5; |
503 | } | 520 | } |
504 | EXPORT_SYMBOL(cfg80211_classify8021d); | 521 | EXPORT_SYMBOL(cfg80211_classify8021d); |
522 | |||
523 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) | ||
524 | { | ||
525 | u8 *end, *pos; | ||
526 | |||
527 | pos = bss->information_elements; | ||
528 | if (pos == NULL) | ||
529 | return NULL; | ||
530 | end = pos + bss->len_information_elements; | ||
531 | |||
532 | while (pos + 1 < end) { | ||
533 | if (pos + 2 + pos[1] > end) | ||
534 | break; | ||
535 | if (pos[0] == ie) | ||
536 | return pos; | ||
537 | pos += 2 + pos[1]; | ||
538 | } | ||
539 | |||
540 | return NULL; | ||
541 | } | ||
542 | EXPORT_SYMBOL(ieee80211_bss_get_ie); | ||
543 | |||
544 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | ||
545 | { | ||
546 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
547 | struct net_device *dev = wdev->netdev; | ||
548 | int i; | ||
549 | |||
550 | if (!wdev->connect_keys) | ||
551 | return; | ||
552 | |||
553 | for (i = 0; i < 6; i++) { | ||
554 | if (!wdev->connect_keys->params[i].cipher) | ||
555 | continue; | ||
556 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | ||
557 | &wdev->connect_keys->params[i])) { | ||
558 | printk(KERN_ERR "%s: failed to set key %d\n", | ||
559 | dev->name, i); | ||
560 | continue; | ||
561 | } | ||
562 | if (wdev->connect_keys->def == i) | ||
563 | if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { | ||
564 | printk(KERN_ERR "%s: failed to set defkey %d\n", | ||
565 | dev->name, i); | ||
566 | continue; | ||
567 | } | ||
568 | if (wdev->connect_keys->defmgmt == i) | ||
569 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) | ||
570 | printk(KERN_ERR "%s: failed to set mgtdef %d\n", | ||
571 | dev->name, i); | ||
572 | } | ||
573 | |||
574 | kfree(wdev->connect_keys); | ||
575 | wdev->connect_keys = NULL; | ||
576 | } | ||
577 | |||
578 | static void cfg80211_process_wdev_events(struct wireless_dev *wdev) | ||
579 | { | ||
580 | struct cfg80211_event *ev; | ||
581 | unsigned long flags; | ||
582 | const u8 *bssid = NULL; | ||
583 | |||
584 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
585 | while (!list_empty(&wdev->event_list)) { | ||
586 | ev = list_first_entry(&wdev->event_list, | ||
587 | struct cfg80211_event, list); | ||
588 | list_del(&ev->list); | ||
589 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
590 | |||
591 | wdev_lock(wdev); | ||
592 | switch (ev->type) { | ||
593 | case EVENT_CONNECT_RESULT: | ||
594 | if (!is_zero_ether_addr(ev->cr.bssid)) | ||
595 | bssid = ev->cr.bssid; | ||
596 | __cfg80211_connect_result( | ||
597 | wdev->netdev, bssid, | ||
598 | ev->cr.req_ie, ev->cr.req_ie_len, | ||
599 | ev->cr.resp_ie, ev->cr.resp_ie_len, | ||
600 | ev->cr.status, | ||
601 | ev->cr.status == WLAN_STATUS_SUCCESS, | ||
602 | NULL); | ||
603 | break; | ||
604 | case EVENT_ROAMED: | ||
605 | __cfg80211_roamed(wdev, ev->rm.bssid, | ||
606 | ev->rm.req_ie, ev->rm.req_ie_len, | ||
607 | ev->rm.resp_ie, ev->rm.resp_ie_len); | ||
608 | break; | ||
609 | case EVENT_DISCONNECTED: | ||
610 | __cfg80211_disconnected(wdev->netdev, | ||
611 | ev->dc.ie, ev->dc.ie_len, | ||
612 | ev->dc.reason, true); | ||
613 | break; | ||
614 | case EVENT_IBSS_JOINED: | ||
615 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | ||
616 | break; | ||
617 | } | ||
618 | wdev_unlock(wdev); | ||
619 | |||
620 | kfree(ev); | ||
621 | |||
622 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
623 | } | ||
624 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
625 | } | ||
626 | |||
627 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | ||
628 | { | ||
629 | struct wireless_dev *wdev; | ||
630 | |||
631 | ASSERT_RTNL(); | ||
632 | ASSERT_RDEV_LOCK(rdev); | ||
633 | |||
634 | mutex_lock(&rdev->devlist_mtx); | ||
635 | |||
636 | list_for_each_entry(wdev, &rdev->netdev_list, list) | ||
637 | cfg80211_process_wdev_events(wdev); | ||
638 | |||
639 | mutex_unlock(&rdev->devlist_mtx); | ||
640 | } | ||
641 | |||
642 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | ||
643 | struct net_device *dev, enum nl80211_iftype ntype, | ||
644 | u32 *flags, struct vif_params *params) | ||
645 | { | ||
646 | int err; | ||
647 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; | ||
648 | |||
649 | ASSERT_RDEV_LOCK(rdev); | ||
650 | |||
651 | /* don't support changing VLANs, you just re-create them */ | ||
652 | if (otype == NL80211_IFTYPE_AP_VLAN) | ||
653 | return -EOPNOTSUPP; | ||
654 | |||
655 | if (!rdev->ops->change_virtual_intf || | ||
656 | !(rdev->wiphy.interface_modes & (1 << ntype))) | ||
657 | return -EOPNOTSUPP; | ||
658 | |||
659 | if (ntype != otype) { | ||
660 | switch (otype) { | ||
661 | case NL80211_IFTYPE_ADHOC: | ||
662 | cfg80211_leave_ibss(rdev, dev, false); | ||
663 | break; | ||
664 | case NL80211_IFTYPE_STATION: | ||
665 | cfg80211_disconnect(rdev, dev, | ||
666 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
667 | break; | ||
668 | case NL80211_IFTYPE_MESH_POINT: | ||
669 | /* mesh should be handled? */ | ||
670 | break; | ||
671 | default: | ||
672 | break; | ||
673 | } | ||
674 | |||
675 | cfg80211_process_rdev_events(rdev); | ||
676 | } | ||
677 | |||
678 | err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, | ||
679 | ntype, flags, params); | ||
680 | |||
681 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); | ||
682 | |||
683 | return err; | ||
684 | } | ||