aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r--net/wireless/util.c190
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
144int cfg80211_validate_key_settings(struct key_params *params, int key_idx, 144int 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}
504EXPORT_SYMBOL(cfg80211_classify8021d); 521EXPORT_SYMBOL(cfg80211_classify8021d);
522
523const 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}
542EXPORT_SYMBOL(ieee80211_bss_get_ie);
543
544void 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
578static 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
627void 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
642int 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}