From 40f7cac9f8dd662c1dd02334afdceef0be03e34f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 Jul 2007 19:32:08 +0200 Subject: [PATCH] [PATCH] mac80211: separate monitor/subif_start_xmit This patch separates the monitor interface start_xmit from the subif start xmit (those other devices have 802.3 framing, monitor interfaces have radiotap framing) Signed-off-by: Johannes Berg Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 101 +++++++++++++++++---------------- net/mac80211/ieee80211_i.h | 2 + net/mac80211/ieee80211_iface.c | 3 + 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 4bcf18097e53..e91698308f31 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1673,6 +1673,56 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb, } +int ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_radiotap_header *prthdr = + (struct ieee80211_radiotap_header *)skb->data; + u16 len; + + /* + * there must be a radiotap header at the + * start in this case + */ + if (unlikely(prthdr->it_version)) { + /* only version 0 is supported */ + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + skb->dev = local->mdev; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(pkt_data, 0, sizeof(*pkt_data)); + pkt_data->ifindex = dev->ifindex; + pkt_data->mgmt_iface = 0; + pkt_data->do_not_encrypt = 1; + + /* above needed because we set skb device to master */ + + /* + * fix up the pointers accounting for the radiotap + * header still being in there. We are being given + * a precooked IEEE80211 header so no need for + * normal processing + */ + len = le16_to_cpu(get_unaligned(&prthdr->it_len)); + skb_set_mac_header(skb, len); + skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); + skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); + + /* + * pass the radiotap header up to + * the next stage intact + */ + dev_queue_xmit(skb); + + return NETDEV_TX_OK; +} + + /** * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type * subinterfaces (wlan#, WDS, and VLAN interfaces) @@ -1688,8 +1738,8 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb, * encapsulated packet will then be passed to master interface, wlan#.11, for * transmission (through low-level driver). */ -static int ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev) +int ieee80211_subif_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_tx_packet_data *pkt_data; @@ -1710,51 +1760,6 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { - struct ieee80211_radiotap_header *prthdr = - (struct ieee80211_radiotap_header *)skb->data; - u16 len; - - /* - * there must be a radiotap header at the - * start in this case - */ - if (unlikely(prthdr->it_version)) { - /* only version 0 is supported */ - ret = 0; - goto fail; - } - - skb->dev = local->mdev; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(*pkt_data)); - pkt_data->ifindex = sdata->dev->ifindex; - pkt_data->mgmt_iface = 0; - pkt_data->do_not_encrypt = 1; - - /* above needed because we set skb device to master */ - - /* - * fix up the pointers accounting for the radiotap - * header still being in there. We are being given - * a precooked IEEE80211 header so no need for - * normal processing - */ - len = le16_to_cpu(get_unaligned(&prthdr->it_len)); - skb_set_mac_header(skb, len); - skb_set_network_header(skb, len + sizeof(hdr)); - skb_set_transport_header(skb, len + sizeof(hdr)); - - /* - * pass the radiotap header up to - * the next stage intact - */ - dev_queue_xmit(skb); - - return 0; - } - nh_pos = skb_network_header(skb) - skb->data; h_pos = skb_transport_header(skb) - skb->data; @@ -1882,7 +1887,7 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb, 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; + pkt_data->ifindex = dev->ifindex; pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); pkt_data->do_not_encrypt = no_encrypt; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5a91e179efa0..fadcbccc0da2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -720,6 +720,8 @@ 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); +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); void ieee80211_if_setup(struct net_device *dev); void ieee80211_if_mgmt_setup(struct net_device *dev); int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index cf0f32e8c2a2..8532a5ccdd1e 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -157,6 +157,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int oldtype = sdata->type; + dev->hard_start_xmit = ieee80211_subif_start_xmit; + sdata->type = type; switch (type) { case IEEE80211_IF_TYPE_WDS: @@ -196,6 +198,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) } case IEEE80211_IF_TYPE_MNTR: dev->type = ARPHRD_IEEE80211_RADIOTAP; + dev->hard_start_xmit = ieee80211_monitor_start_xmit; break; default: printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",