[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 <johannes@sipsolutions.net> Signed-off-by: Jiri Benc <jbenc@suse.cz> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Родитель
333af2f071
Коммит
40f7cac9f8
|
@ -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
|
* ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
|
||||||
* subinterfaces (wlan#, WDS, and VLAN interfaces)
|
* 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
|
* encapsulated packet will then be passed to master interface, wlan#.11, for
|
||||||
* transmission (through low-level driver).
|
* transmission (through low-level driver).
|
||||||
*/
|
*/
|
||||||
static int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||||
struct ieee80211_tx_packet_data *pkt_data;
|
struct ieee80211_tx_packet_data *pkt_data;
|
||||||
|
@ -1710,51 +1760,6 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||||
goto fail;
|
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;
|
nh_pos = skb_network_header(skb) - skb->data;
|
||||||
h_pos = skb_transport_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;
|
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
|
||||||
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
|
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->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
|
||||||
pkt_data->do_not_encrypt = no_encrypt;
|
pkt_data->do_not_encrypt = no_encrypt;
|
||||||
|
|
||||||
|
|
|
@ -720,6 +720,8 @@ void ieee80211_prepare_rates(struct ieee80211_local *local,
|
||||||
struct ieee80211_hw_mode *mode);
|
struct ieee80211_hw_mode *mode);
|
||||||
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
|
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
|
||||||
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
|
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_setup(struct net_device *dev);
|
||||||
void ieee80211_if_mgmt_setup(struct net_device *dev);
|
void ieee80211_if_mgmt_setup(struct net_device *dev);
|
||||||
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
|
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
|
||||||
|
|
|
@ -157,6 +157,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
|
||||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||||
int oldtype = sdata->type;
|
int oldtype = sdata->type;
|
||||||
|
|
||||||
|
dev->hard_start_xmit = ieee80211_subif_start_xmit;
|
||||||
|
|
||||||
sdata->type = type;
|
sdata->type = type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IEEE80211_IF_TYPE_WDS:
|
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:
|
case IEEE80211_IF_TYPE_MNTR:
|
||||||
dev->type = ARPHRD_IEEE80211_RADIOTAP;
|
dev->type = ARPHRD_IEEE80211_RADIOTAP;
|
||||||
|
dev->hard_start_xmit = ieee80211_monitor_start_xmit;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
|
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче