This patch reduces mdev usage by replacing struct net_device * arguments that are never used except for dereferencing to get struct ieee80211_local from ieee80211_ptr by struct ieee80211_local directly.
Also, this patch changes ieee80211_rx_mgmt to no longer be callable when local->apdev is NULL. All callers are updated accordingly, in most cases actually increasing performance by not allocating skbs when they won't be given to anyone anyway. Instead of abusing ieee80211_rx_mgmt also introduce ieee80211_rx_monitor. Signed-off-by: Johannes Berg <[EMAIL PROTECTED]> --- wireless-dev.orig/net/d80211/ieee80211.c 2006-11-19 20:13:56.079275208 +0100 +++ wireless-dev/net/d80211/ieee80211.c 2006-11-19 20:13:56.719275208 +0100 @@ -210,9 +210,16 @@ static void ieee80211_key_threshold_noti struct ieee80211_key *key, struct sta_info *sta) { + struct ieee80211_local *local = dev->ieee80211_ptr; struct sk_buff *skb; struct ieee80211_msg_key_notification *msg; + /* if no one will get it anyway, don't even allocate it. + * unlikely because this is only relevant for APs + * where the device must be open... */ + if (unlikely(!local->apdev)) + return; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + sizeof(struct ieee80211_msg_key_notification)); if (!skb) @@ -230,7 +237,7 @@ static void ieee80211_key_threshold_noti key->tx_rx_count = 0; - ieee80211_rx_mgmt(dev, skb, NULL, + ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_key_threshold_notification); } @@ -2526,45 +2533,11 @@ ieee80211_get_rate(struct ieee80211_loca return NULL; } - void -ieee80211_rx_mgmt(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *status, u32 msg_type) +ieee80211_fill_frame_info(struct ieee80211_local *local, + struct ieee80211_frame_info *fi, + struct ieee80211_rx_status *status) { - struct ieee80211_local *local = dev->ieee80211_ptr; - struct ieee80211_frame_info *fi; - size_t hlen; - struct ieee80211_sub_if_data *sdata; - - if (msg_type != ieee80211_msg_monitor) - dev = local->apdev; - if (!dev) { - dev_kfree_skb(skb); - return; - } - skb->dev = dev; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (skb_headroom(skb) < sizeof(struct ieee80211_frame_info)) { - I802_DEBUG_INC(local->rx_expand_skb_head); - if (pskb_expand_head(skb, sizeof(struct ieee80211_frame_info), - 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return; - } - } - - hlen = sizeof(struct ieee80211_frame_info); - if (msg_type == ieee80211_msg_monitor) - hlen -= sizeof(fi->msg_type); - - fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); - memset(fi, 0, hlen); - if (msg_type != ieee80211_msg_monitor) - fi->msg_type = htonl(msg_type); - fi->version = htonl(IEEE80211_FI_VERSION); - fi->length = htonl(hlen); if (status) { struct timespec ts; struct ieee80211_rate *rate; @@ -2615,27 +2588,104 @@ ieee80211_rx_mgmt(struct net_device *dev 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 ieee80211_sub_if_data *sdata; + + skb->dev = local->apdev; + + sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev); + + 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); - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; + ieee80211_fill_frame_info(local, fi, status); + fi->msg_type = htonl(msg_type); - skb->mac.raw = skb->data; + sdata->stats.rx_packets++; + sdata->stats.rx_bytes += skb->len; + + skb->mac.raw = skb->data; skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = __constant_htons(ETH_P_802_2); + skb->protocol = htons(ETH_P_802_2); memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); + netif_rx(skb); } +void +ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_local *local = dev->ieee80211_ptr; + struct ieee80211_frame_info *fi; + struct ieee80211_sub_if_data *sdata; + const size_t hlen = sizeof(struct ieee80211_frame_info) + - sizeof(fi->msg_type); + + skb->dev = dev; + + sdata = IEEE80211_DEV_TO_SUB_IF(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); + sdata->stats.rx_packets++; + sdata->stats.rx_bytes += skb->len; + + skb->mac.raw = skb->data; + 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); +} int ieee80211_radar_status(struct net_device *dev, int channel, int radar, int radar_type) { + struct ieee80211_local *local = dev->ieee80211_ptr; struct sk_buff *skb; struct ieee80211_radar_info *msg; + if (!local->apdev) + return 0; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + sizeof(struct ieee80211_radar_info)); @@ -2649,7 +2699,7 @@ int ieee80211_radar_status(struct net_de msg->radar = radar; msg->radar_type = radar_type; - ieee80211_rx_mgmt(dev, skb, NULL, ieee80211_msg_radar); + ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar); return 0; } EXPORT_SYMBOL(ieee80211_radar_status); @@ -2657,9 +2707,15 @@ EXPORT_SYMBOL(ieee80211_radar_status); int ieee80211_set_aid_for_sta(struct net_device *dev, u8 *peer_address, u16 aid) { + struct ieee80211_local *local = dev->ieee80211_ptr; struct sk_buff *skb; struct ieee80211_msg_set_aid_for_sta *msg; + /* unlikely because if this event only happens for APs, + * which require an open ap device. */ + if (unlikely(!local->apdev)) + return 0; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + sizeof(struct ieee80211_msg_set_aid_for_sta)); @@ -2672,7 +2728,7 @@ int ieee80211_set_aid_for_sta(struct net memcpy(msg->sta_address, peer_address, ETH_ALEN); msg->aid = aid; - ieee80211_rx_mgmt(dev, skb, NULL, ieee80211_msg_set_aid_for_sta); + ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta); return 0; } EXPORT_SYMBOL(ieee80211_set_aid_for_sta); @@ -3007,8 +3063,7 @@ static ieee80211_txrx_result ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx) { if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) { - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, - ieee80211_msg_monitor); + ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status); return TXRX_QUEUED; } @@ -3080,7 +3135,10 @@ ieee80211_rx_h_check(struct ieee80211_tx return TXRX_DROP; } - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, + 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; } @@ -3116,8 +3174,10 @@ ieee80211_rx_h_check(struct ieee80211_tx MAC_ARG(hdr->addr1), MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3)); + if (!rx->local->apdev) + return TXRX_DROP; ieee80211_rx_mgmt( - rx->dev, rx->skb, rx->u.rx.status, + rx->local, rx->skb, rx->u.rx.status, ieee80211_msg_wep_frame_unknown_key); return TXRX_QUEUED; } @@ -3267,7 +3327,9 @@ ieee80211_rx_h_802_1x_pae(struct ieee802 rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { /* Pass both encrypted and unencrypted EAPOL frames to user * space for processing. */ - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, ieee80211_msg_normal); return TXRX_QUEUED; } @@ -3328,7 +3390,9 @@ ieee80211_rx_h_mgmt(struct ieee80211_txr ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); } else { /* Management frames are sent to hostapd for processing */ - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, ieee80211_msg_normal); } return TXRX_QUEUED; @@ -3368,7 +3432,10 @@ ieee80211_rx_h_passive_scan(struct ieee8 rx->skb->len > FCS_LEN) skb_trim(rx->skb, rx->skb->len - FCS_LEN); - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, + if (!rx->local->apdev) + return TXRX_DROP; + ieee80211_rx_mgmt(rx->local, rx->skb, + rx->u.rx.status, ieee80211_msg_passive_scan); return TXRX_QUEUED; } else { @@ -3502,7 +3569,9 @@ static void ieee80211_rx_michael_mic_rep /* TODO: consider verifying the MIC error report with software * implementation if we get too many spurious reports from the * hardware. */ - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, + if (!rx->local->apdev) + goto ignore; + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, ieee80211_msg_michael_mic_failure); return; @@ -4148,7 +4217,8 @@ void ieee80211_tx_status(struct net_devi local->dot11FailedCount++; } - if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS)) { + if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) + || unlikely(!local->apdev)) { dev_kfree_skb(skb); return; } @@ -4167,7 +4237,7 @@ void ieee80211_tx_status(struct net_devi skb = skb2; /* Send frame to hostapd */ - ieee80211_rx_mgmt(dev, skb, NULL, msg_type); + ieee80211_rx_mgmt(local, skb, NULL, msg_type); } EXPORT_SYMBOL(ieee80211_tx_status); --- wireless-dev.orig/net/d80211/ieee80211_i.h 2006-11-19 20:13:56.069275208 +0100 +++ wireless-dev/net/d80211/ieee80211_i.h 2006-11-19 20:13:56.719275208 +0100 @@ -571,7 +571,7 @@ struct ieee80211_key *ieee80211_key_allo int idx, size_t key_len, gfp_t flags); void ieee80211_key_free(struct ieee80211_key *key); void ieee80211_key_release(struct kobject *kobj); -void ieee80211_rx_mgmt(struct net_device *dev, struct sk_buff *skb, +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); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); --- wireless-dev.orig/net/d80211/wpa.c 2006-11-19 20:13:51.199275208 +0100 +++ wireless-dev/net/d80211/wpa.c 2006-11-19 20:13:56.719275208 +0100 @@ -267,7 +267,10 @@ ieee80211_rx_h_michael_mic_verify(struct kfree(buf); } while (0); - ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, + if (!rx->local->apdev) + return TXRX_DROP; + + ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, ieee80211_msg_michael_mic_failure); return TXRX_QUEUED; --- wireless-dev.orig/include/net/d80211_common.h 2006-11-19 20:13:51.249275208 +0100 +++ wireless-dev/include/net/d80211_common.h 2006-11-19 20:13:56.719275208 +0100 @@ -50,7 +50,7 @@ enum ieee80211_msg_type { ieee80211_msg_passive_scan = 3, ieee80211_msg_wep_frame_unknown_key = 4, ieee80211_msg_michael_mic_failure = 5, - ieee80211_msg_monitor = 6, + /* hole at 6, was monitor but never sent to userspace */ ieee80211_msg_sta_not_assoc = 7, ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */, ieee80211_msg_key_threshold_notification = 9, - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html