--- include/net/mac80211.h | 1 net/mac80211/ieee80211.c | 198 ++++++++++++++++++++++++++++++++++++++-- net/mac80211/ieee80211_common.h | 64 ++++++++++++ net/mac80211/ieee80211_i.h | 9 + net/mac80211/ieee80211_iface.c | 66 +++++++++++++ net/mac80211/ieee80211_ioctl.c | 21 ++++ net/mac80211/ieee80211_rate.c | 3 net/mac80211/ieee80211_rate.h | 2 net/mac80211/ieee80211_sta.c | 2 net/mac80211/rx.c | 29 ++++- net/mac80211/tx.c | 14 ++ net/mac80211/wme.c | 10 +- 12 files changed, 399 insertions(+), 20 deletions(-) Index: mac80211/include/net/mac80211.h =================================================================== --- mac80211.orig/include/net/mac80211.h 2007-11-11 15:15:42.824034853 +0100 +++ mac80211/include/net/mac80211.h 2007-11-11 15:15:53.784659457 +0100 @@ -472,6 +472,7 @@ enum ieee80211_if_types { IEEE80211_IF_TYPE_INVALID, IEEE80211_IF_TYPE_AP, + IEEE80211_IF_TYPE_MGMT, IEEE80211_IF_TYPE_STA, IEEE80211_IF_TYPE_IBSS, IEEE80211_IF_TYPE_MNTR, Index: mac80211/net/mac80211/ieee80211.c =================================================================== --- mac80211.orig/net/mac80211/ieee80211.c 2007-11-11 15:15:51.536531354 +0100 +++ mac80211/net/mac80211/ieee80211.c 2007-11-11 15:16:22.214279577 +0100 @@ -23,6 +23,7 @@ #include #include +#include "ieee80211_common.h" #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "wep.h" @@ -121,6 +122,152 @@ ieee80211_configure_filter(local); } +/* management interface */ + +static void +ieee80211_fill_frame_info(struct ieee80211_local *local, + struct ieee80211_frame_info *fi, + struct ieee80211_rx_status *status) +{ + if (status) { + struct timespec ts; + struct ieee80211_rate *rate; + + jiffies_to_timespec(jiffies, &ts); + fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 + + ts.tv_nsec / 1000); + fi->mactime = cpu_to_be64(status->mactime); + switch (status->phymode) { + case MODE_IEEE80211A: + fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a); + break; + case MODE_IEEE80211B: + fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b); + break; + case MODE_IEEE80211G: + fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); + break; + default: + fi->phytype = htonl(0xAAAAAAAA); + break; + } + fi->channel = htonl(status->channel); + rate = ieee80211_get_rate(local, status->phymode, + status->rate); + if (rate) { + fi->datarate = htonl(rate->rate); + if (rate->flags & IEEE80211_RATE_PREAMBLE2) { + if (status->rate == rate->val) + fi->preamble = htonl(2); /* long */ + else if (status->rate == rate->val2) + fi->preamble = htonl(1); /* short */ + } else + fi->preamble = htonl(0); + } else { + fi->datarate = htonl(0); + fi->preamble = htonl(0); + } + + fi->antenna = htonl(status->antenna); + fi->priority = htonl(0xffffffff); /* no clue */ + fi->ssi_type = htonl(ieee80211_ssi_raw); + fi->ssi_signal = htonl(status->ssi); + fi->ssi_noise = 0x00000000; + fi->encoding = 0; + } else { + /* clear everything because we really don't know. + * the msg_type field isn't present on monitor frames + * so we don't know whether it will be present or not, + * but it's ok to not clear it since it'll be assigned + * anyway */ + memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type)); + + fi->ssi_type = htonl(ieee80211_ssi_none); + } + fi->version = htonl(IEEE80211_FI_VERSION); + fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type)); +} + +/* this routine is actually not just for this, but also + * for pushing fake 'management' frames into userspace. + * it shall be replaced by a netlink-based system. */ +void +ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, + struct ieee80211_rx_status *status, u32 msg_type) +{ + struct ieee80211_frame_info *fi; + const size_t hlen = sizeof(struct ieee80211_frame_info); + struct net_device *dev = local->apdev; + + skb->dev = dev; + + if (skb_headroom(skb) < hlen) { + I802_DEBUG_INC(local->rx_expand_skb_head); + if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return; + } + } + + fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); + + ieee80211_fill_frame_info(local, fi, status); + fi->msg_type = htonl(msg_type); + + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + +static int ieee80211_mgmt_open(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (!netif_running(local->mdev)) + return -EOPNOTSUPP; + return 0; +} + +static int ieee80211_mgmt_stop(struct net_device *dev) +{ + return 0; +} + +static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) +{ + /* FIX: what would be proper limits for MTU? + * This interface uses 802.11 frames. */ + if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { + printk(KERN_WARNING "%s: invalid MTU %d\n", + dev->name, new_mtu); + return -EINVAL; + } + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + dev->mtu = new_mtu; + return 0; +} + +void ieee80211_if_mgmt_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->hard_start_xmit = ieee80211_mgmt_start_xmit; + dev->change_mtu = ieee80211_change_mtu_apdev; + dev->open = ieee80211_mgmt_open; + dev->stop = ieee80211_mgmt_stop; + dev->type = ARPHRD_IEEE80211_PRISM; + dev->hard_header_parse = &header_parse_80211; + dev->destructor = ieee80211_if_free; +} + /* regular interfaces */ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) @@ -198,6 +345,7 @@ return -ENOLINK; break; case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_MGMT: case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_IBSS: @@ -262,6 +410,10 @@ if (local->open_count == 0) { res = dev_open(local->mdev); WARN_ON(res); + if (local->apdev) { + res = dev_open(local->apdev); + WARN_ON(res); + } tasklet_enable(&local->tx_pending_tasklet); tasklet_enable(&local->tasklet); } @@ -347,6 +499,9 @@ if (netif_running(local->mdev)) dev_close(local->mdev); + if (local->apdev) + dev_close(local->apdev); + if (local->ops->stop) local->ops->stop(local_to_hw(local)); @@ -646,6 +801,8 @@ pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; if (control->flags & IEEE80211_TXCTL_REQUEUE) pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + if (control->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -698,6 +855,7 @@ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); u16 frag, type; + u32 msg_type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; int monitors; @@ -812,9 +970,29 @@ local->dot11FailedCount++; } + msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? + ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail; + /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); + if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) && + local->apdev) { + if (local->monitors) { + skb2 = skb_clone(skb, GFP_ATOMIC); + } else { + skb2 = skb; + skb = NULL; + } + + if (skb2) + /* Send frame to hostapd */ + ieee80211_rx_mgmt(local, skb2, NULL, msg_type); + + if (!skb) + return; + } + if (!local->monitors) { dev_kfree_skb(skb); return; @@ -1161,6 +1339,8 @@ BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); local->reg_state = IEEE80211_DEV_UNREGISTERED; + if (local->apdev) + ieee80211_if_del_mgmt(local); /* * At this point, interface list manipulations are fine Index: mac80211/net/mac80211/ieee80211_i.h =================================================================== --- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:42.840035769 +0100 +++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100 @@ -142,6 +142,7 @@ * when using CTS protection with IEEE 802.11g. */ struct ieee80211_rate *last_frag_rate; int last_frag_hwrate; + int mgmt_interface; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -163,6 +164,7 @@ #define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) #define IEEE80211_TXPD_REQUEUE BIT(2) +#define IEEE80211_TXPD_MGMT_IFACE BIT(3) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; @@ -408,6 +410,7 @@ struct list_head modes_list; struct net_device *mdev; /* wmaster# - "master" 802.11 device */ + struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; int monitors; unsigned int filter_flags; /* FIF_* */ @@ -701,11 +704,14 @@ int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); +void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, + struct ieee80211_rx_status *status, u32 msg_type); void ieee80211_prepare_rates(struct ieee80211_local *local, struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); +void ieee80211_if_mgmt_setup(struct net_device *dev); struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hwrate); @@ -772,6 +778,8 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); +int ieee80211_if_add_mgmt(struct ieee80211_local *local); +void ieee80211_if_del_mgmt(struct ieee80211_local *local); /* regdomain.c */ void ieee80211_regdomain_init(void); @@ -788,6 +796,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); +int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); /* utility functions/constants */ extern void *mac80211_wiphy_privid; /* for wiphy privid */ Index: mac80211/net/mac80211/ieee80211_iface.c =================================================================== --- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:42.848036222 +0100 +++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100 @@ -96,6 +96,66 @@ return ret; } +int ieee80211_if_add_mgmt(struct ieee80211_local *local) +{ + struct net_device *ndev; + struct ieee80211_sub_if_data *nsdata; + int ret; + + ASSERT_RTNL(); + + ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d", + ieee80211_if_mgmt_setup); + if (!ndev) + return -ENOMEM; + ret = dev_alloc_name(ndev, ndev->name); + if (ret < 0) + goto fail; + + memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); + SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); + + nsdata = IEEE80211_DEV_TO_SUB_IF(ndev); + ndev->ieee80211_ptr = &nsdata->wdev; + nsdata->wdev.wiphy = local->hw.wiphy; + nsdata->type = IEEE80211_IF_TYPE_MGMT; + nsdata->dev = ndev; + nsdata->local = local; + ieee80211_if_sdata_init(nsdata); + + ret = register_netdevice(ndev); + if (ret) + goto fail; + + /* + * Called even when register_netdevice fails, it would + * oops if assigned before initialising the rest. + */ + ndev->uninit = ieee80211_if_reinit; + + ieee80211_debugfs_add_netdev(nsdata); + + if (local->open_count > 0) + dev_open(ndev); + local->apdev = ndev; + return 0; + +fail: + free_netdev(ndev); + return ret; +} + +void ieee80211_if_del_mgmt(struct ieee80211_local *local) +{ + struct net_device *apdev; + + ASSERT_RTNL(); + apdev = local->apdev; + ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev)); + local->apdev = NULL; + unregister_netdevice(apdev); +} + void ieee80211_if_set_type(struct net_device *dev, int type) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -183,6 +243,9 @@ ieee80211_if_sdata_deinit(sdata); switch (sdata->type) { + case IEEE80211_IF_TYPE_MGMT: + /* nothing to do */ + break; case IEEE80211_IF_TYPE_INVALID: /* cannot happen */ WARN_ON(1); @@ -294,8 +357,11 @@ void ieee80211_if_free(struct net_device *dev) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + /* local->apdev must be NULL when freeing management interface */ + BUG_ON(dev == local->apdev); ieee80211_if_sdata_deinit(sdata); free_netdev(dev); } Index: mac80211/net/mac80211/ieee80211_rate.c =================================================================== --- mac80211.orig/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:42.852036451 +0100 +++ mac80211/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:53.800660386 +0100 @@ -145,7 +145,8 @@ struct rate_control_ref *ref, *old; ASSERT_RTNL(); - if (local->open_count || netif_running(local->mdev)) + if (local->open_count || netif_running(local->mdev) || + (local->apdev && netif_running(local->apdev))) return -EBUSY; ref = rate_control_alloc(name, local); Index: mac80211/net/mac80211/ieee80211_rate.h =================================================================== --- mac80211.orig/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:42.860036908 +0100 +++ mac80211/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:53.800660386 +0100 @@ -30,6 +30,8 @@ /* parameters from the caller to rate_control_get_rate(): */ struct ieee80211_hw_mode *mode; + int mgmt_data; /* this is data frame that is used for management + * (e.g., IEEE 802.1X EAPOL) */ u16 ethertype; }; Index: mac80211/net/mac80211/ieee80211_sta.c =================================================================== --- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:42.868037362 +0100 +++ mac80211/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:53.800660386 +0100 @@ -475,6 +475,8 @@ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; if (!encrypt) pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; Index: mac80211/net/mac80211/rx.c =================================================================== --- mac80211.orig/net/mac80211/rx.c 2007-11-11 15:15:42.872037591 +0100 +++ mac80211/net/mac80211/rx.c 2007-11-11 15:15:53.804660611 +0100 @@ -19,6 +19,7 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" +#include "ieee80211_common.h" #include "wep.h" #include "wpa.h" #include "tkip.h" @@ -411,7 +412,12 @@ return TXRX_DROP; } - return TXRX_DROP; + if (!rx->local->apdev) + return TXRX_DROP; + + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_sta_not_assoc); + return TXRX_QUEUED; } return TXRX_CONTINUE; @@ -953,8 +959,15 @@ { if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && rx->sdata->type != IEEE80211_IF_TYPE_STA && - (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { + /* Pass both encrypted and unencrypted EAPOL frames to user + * space for processing. */ + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_normal); + return TXRX_QUEUED; + } if (unlikely(rx->sdata->ieee802_1x && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && @@ -1196,8 +1209,13 @@ sdata->type == IEEE80211_IF_TYPE_IBSS) && !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); - else - return TXRX_DROP; + else { + /* Management frames are sent to hostapd for processing */ + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, + ieee80211_msg_normal); + } return TXRX_QUEUED; } @@ -1407,6 +1425,7 @@ /* take everything */ break; case IEEE80211_IF_TYPE_INVALID: + case IEEE80211_IF_TYPE_MGMT: /* should never get here */ WARN_ON(1); break; Index: mac80211/net/mac80211/tx.c =================================================================== --- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:42.880038048 +0100 +++ mac80211/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100 @@ -258,7 +258,7 @@ return TXRX_CONTINUE; } - if (unlikely(/* !injected && */ tx->sdata->ieee802_1x && + if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && !(sta_flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT @@ -568,6 +568,8 @@ memset(&extra, 0, sizeof(extra)); extra.mode = tx->u.tx.mode; extra.ethertype = tx->ethertype; + extra.mgmt_data = tx->sdata && + tx->sdata->type == IEEE80211_IF_TYPE_MGMT; tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, &extra); @@ -1076,7 +1078,7 @@ } static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control) + struct ieee80211_tx_control *control, int mgmt) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; @@ -1107,6 +1109,7 @@ rcu_read_lock(); sta = tx.sta; + tx.u.tx.mgmt_interface = mgmt; tx.u.tx.mode = local->hw.conf.mode; for (handler = local->tx_handlers; *handler != NULL; @@ -1253,7 +1256,8 @@ control.flags |= IEEE80211_TXCTL_REQUEUE; control.queue = pkt_data->queue; - ret = ieee80211_tx(odev, skb, &control); + ret = ieee80211_tx(odev, skb, &control, + control.type == IEEE80211_IF_TYPE_MGMT); dev_put(odev); return ret; @@ -1498,6 +1502,8 @@ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = dev->ifindex; + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->dev = local->mdev; dev->stats.tx_packets++; @@ -1555,6 +1561,8 @@ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; + if (sdata->type == IEEE80211_IF_TYPE_MGMT) + pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE; skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ skb->dev = sdata->local->mdev; Index: mac80211/net/mac80211/wme.c =================================================================== --- mac80211.orig/net/mac80211/wme.c 2007-11-11 15:15:42.888038502 +0100 +++ mac80211/net/mac80211/wme.c 2007-11-11 15:15:53.804660611 +0100 @@ -94,6 +94,8 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); + struct ieee80211_tx_packet_data *pkt_data = + (struct ieee80211_tx_packet_data *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); int qos; @@ -106,8 +108,12 @@ return IEEE80211_TX_QUEUE_DATA0; } - if (0 /* injected */) { - /* use AC from radiotap */ + if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) { + /* Data frames from hostapd (mainly, EAPOL) use AC_VO + * and they will include QoS control fields if + * the target STA is using WME. */ + skb->priority = 7; + return ieee802_1d_to_ac[skb->priority]; } /* is this a QoS frame? */ Index: mac80211/net/mac80211/ieee80211_ioctl.c =================================================================== --- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:51.532531127 +0100 +++ mac80211/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:53.808660833 +0100 @@ -840,16 +840,29 @@ void *wrqu, char *extra) { struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; int *i = (int *) extra; int param = *i; + int value = *(i + 1); int ret = 0; if (!capable(CAP_NET_ADMIN)) return -EPERM; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + local = sdata->local; switch (param) { + case PRISM2_PARAM_MGMT_IF: + if (value == 1) { + if (!local->apdev) + ret = ieee80211_if_add_mgmt(local); + } else if (value == 0) { + if (local->apdev) + ieee80211_if_del_mgmt(local); + } else + ret = -EINVAL; + break; default: ret = -EOPNOTSUPP; break; @@ -864,12 +877,20 @@ void *wrqu, char *extra) { struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; int *param = (int *) extra; int ret = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + local = sdata->local; switch (*param) { + case PRISM2_PARAM_MGMT_IF: + if (local->apdev) + *param = local->apdev->ifindex; + else + ret = -ENOENT; + break; default: ret = -EOPNOTSUPP; break;