aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-12-18 20:03:35 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:09:39 -0500
commit4fd6931ebe24640bec72b91ba612325843a5e3cc (patch)
treeaf070ac140deaf7625a3d4d547b757924e6965a7 /net
parent5dfdaf58d61f06a458529430c24b1191ea4d1a27 (diff)
mac80211: implement cfg80211 station handling
This implements station handling from userspace via cfg80211 in mac80211. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5a4c6edd9348..22c9619ba776 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -14,6 +14,7 @@
14#include <net/cfg80211.h> 14#include <net/cfg80211.h>
15#include "ieee80211_i.h" 15#include "ieee80211_i.h"
16#include "cfg.h" 16#include "cfg.h"
17#include "ieee80211_rate.h"
17 18
18static enum ieee80211_if_types 19static enum ieee80211_if_types
19nl80211_type_to_mac80211_type(enum nl80211_iftype type) 20nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@@ -447,6 +448,194 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
447 return ieee80211_if_config_beacon(dev); 448 return ieee80211_if_config_beacon(dev);
448} 449}
449 450
451/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
452struct iapp_layer2_update {
453 u8 da[ETH_ALEN]; /* broadcast */
454 u8 sa[ETH_ALEN]; /* STA addr */
455 __be16 len; /* 6 */
456 u8 dsap; /* 0 */
457 u8 ssap; /* 0 */
458 u8 control;
459 u8 xid_info[3];
460} __attribute__ ((packed));
461
462static void ieee80211_send_layer2_update(struct sta_info *sta)
463{
464 struct iapp_layer2_update *msg;
465 struct sk_buff *skb;
466
467 /* Send Level 2 Update Frame to update forwarding tables in layer 2
468 * bridge devices */
469
470 skb = dev_alloc_skb(sizeof(*msg));
471 if (!skb)
472 return;
473 msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
474
475 /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
476 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
477
478 memset(msg->da, 0xff, ETH_ALEN);
479 memcpy(msg->sa, sta->addr, ETH_ALEN);
480 msg->len = htons(6);
481 msg->dsap = 0;
482 msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
483 msg->control = 0xaf; /* XID response lsb.1111F101.
484 * F=0 (no poll command; unsolicited frame) */
485 msg->xid_info[0] = 0x81; /* XID format identifier */
486 msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
487 msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
488
489 skb->dev = sta->dev;
490 skb->protocol = eth_type_trans(skb, sta->dev);
491 memset(skb->cb, 0, sizeof(skb->cb));
492 netif_rx(skb);
493}
494
495static void sta_apply_parameters(struct ieee80211_local *local,
496 struct sta_info *sta,
497 struct station_parameters *params)
498{
499 u32 rates;
500 int i, j;
501 struct ieee80211_hw_mode *mode;
502
503 if (params->station_flags & STATION_FLAG_CHANGED) {
504 sta->flags &= ~WLAN_STA_AUTHORIZED;
505 if (params->station_flags & STATION_FLAG_AUTHORIZED)
506 sta->flags |= WLAN_STA_AUTHORIZED;
507
508 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
509 if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
510 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
511
512 sta->flags &= ~WLAN_STA_WME;
513 if (params->station_flags & STATION_FLAG_WME)
514 sta->flags |= WLAN_STA_WME;
515 }
516
517 if (params->aid) {
518 sta->aid = params->aid;
519 if (sta->aid > IEEE80211_MAX_AID)
520 sta->aid = 0; /* XXX: should this be an error? */
521 }
522
523 if (params->listen_interval >= 0)
524 sta->listen_interval = params->listen_interval;
525
526 if (params->supported_rates) {
527 rates = 0;
528 mode = local->oper_hw_mode;
529 for (i = 0; i < params->supported_rates_len; i++) {
530 int rate = (params->supported_rates[i] & 0x7f) * 5;
531 for (j = 0; j < mode->num_rates; j++) {
532 if (mode->rates[j].rate == rate)
533 rates |= BIT(j);
534 }
535 }
536 sta->supp_rates = rates;
537 }
538}
539
540static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
541 u8 *mac, struct station_parameters *params)
542{
543 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
544 struct sta_info *sta;
545 struct ieee80211_sub_if_data *sdata;
546
547 /* Prevent a race with changing the rate control algorithm */
548 if (!netif_running(dev))
549 return -ENETDOWN;
550
551 /* XXX: get sta belonging to dev */
552 sta = sta_info_get(local, mac);
553 if (sta) {
554 sta_info_put(sta);
555 return -EEXIST;
556 }
557
558 if (params->vlan) {
559 sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
560
561 if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
562 sdata->vif.type != IEEE80211_IF_TYPE_AP)
563 return -EINVAL;
564 } else
565 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
566
567 sta = sta_info_add(local, dev, mac, GFP_KERNEL);
568 if (!sta)
569 return -ENOMEM;
570
571 sta->dev = sdata->dev;
572 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
573 sdata->vif.type == IEEE80211_IF_TYPE_AP)
574 ieee80211_send_layer2_update(sta);
575
576 sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
577
578 sta_apply_parameters(local, sta, params);
579
580 rate_control_rate_init(sta, local);
581
582 sta_info_put(sta);
583
584 return 0;
585}
586
587static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
588 u8 *mac)
589{
590 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
591 struct sta_info *sta;
592
593 if (mac) {
594 /* XXX: get sta belonging to dev */
595 sta = sta_info_get(local, mac);
596 if (!sta)
597 return -ENOENT;
598
599 sta_info_free(sta);
600 sta_info_put(sta);
601 } else
602 sta_info_flush(local, dev);
603
604 return 0;
605}
606
607static int ieee80211_change_station(struct wiphy *wiphy,
608 struct net_device *dev,
609 u8 *mac,
610 struct station_parameters *params)
611{
612 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
613 struct sta_info *sta;
614 struct ieee80211_sub_if_data *vlansdata;
615
616 /* XXX: get sta belonging to dev */
617 sta = sta_info_get(local, mac);
618 if (!sta)
619 return -ENOENT;
620
621 if (params->vlan && params->vlan != sta->dev) {
622 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
623
624 if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
625 vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
626 return -EINVAL;
627
628 sta->dev = params->vlan;
629 ieee80211_send_layer2_update(sta);
630 }
631
632 sta_apply_parameters(local, sta, params);
633
634 sta_info_put(sta);
635
636 return 0;
637}
638
450struct cfg80211_ops mac80211_config_ops = { 639struct cfg80211_ops mac80211_config_ops = {
451 .add_virtual_intf = ieee80211_add_iface, 640 .add_virtual_intf = ieee80211_add_iface,
452 .del_virtual_intf = ieee80211_del_iface, 641 .del_virtual_intf = ieee80211_del_iface,
@@ -458,5 +647,8 @@ struct cfg80211_ops mac80211_config_ops = {
458 .add_beacon = ieee80211_add_beacon, 647 .add_beacon = ieee80211_add_beacon,
459 .set_beacon = ieee80211_set_beacon, 648 .set_beacon = ieee80211_set_beacon,
460 .del_beacon = ieee80211_del_beacon, 649 .del_beacon = ieee80211_del_beacon,
650 .add_station = ieee80211_add_station,
651 .del_station = ieee80211_del_station,
652 .change_station = ieee80211_change_station,
461 .get_station = ieee80211_get_station, 653 .get_station = ieee80211_get_station,
462}; 654};