aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/cfg.c1
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/tx.c46
3 files changed, 50 insertions, 0 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 36d128ebbac8..f6b8d59a7ee8 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3791,4 +3791,5 @@ const struct cfg80211_ops mac80211_config_ops = {
3791 .add_nan_func = ieee80211_add_nan_func, 3791 .add_nan_func = ieee80211_add_nan_func,
3792 .del_nan_func = ieee80211_del_nan_func, 3792 .del_nan_func = ieee80211_del_nan_func,
3793 .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, 3793 .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
3794 .tx_control_port = ieee80211_tx_control_port,
3794}; 3795};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5b3d78362fb5..275d6269b4a7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1735,6 +1735,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta);
1735void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); 1735void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
1736void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); 1736void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
1737void ieee80211_clear_fast_xmit(struct sta_info *sta); 1737void ieee80211_clear_fast_xmit(struct sta_info *sta);
1738int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
1739 const u8 *buf, size_t len,
1740 const u8 *dest, __be16 proto, bool unencrypted);
1738 1741
1739/* HT */ 1742/* HT */
1740void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, 1743void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 933c67b5f845..535de3161a78 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4757,3 +4757,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
4757 ieee80211_xmit(sdata, NULL, skb); 4757 ieee80211_xmit(sdata, NULL, skb);
4758 local_bh_enable(); 4758 local_bh_enable();
4759} 4759}
4760
4761int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
4762 const u8 *buf, size_t len,
4763 const u8 *dest, __be16 proto, bool unencrypted)
4764{
4765 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
4766 struct ieee80211_local *local = sdata->local;
4767 struct sk_buff *skb;
4768 struct ethhdr *ehdr;
4769 u32 flags;
4770
4771 /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE
4772 * or Pre-Authentication
4773 */
4774 if (proto != sdata->control_port_protocol &&
4775 proto != cpu_to_be16(ETH_P_PREAUTH))
4776 return -EINVAL;
4777
4778 if (unencrypted)
4779 flags = IEEE80211_TX_INTFL_DONT_ENCRYPT;
4780 else
4781 flags = 0;
4782
4783 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
4784 sizeof(struct ethhdr) + len);
4785 if (!skb)
4786 return -ENOMEM;
4787
4788 skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr));
4789
4790 skb_put_data(skb, buf, len);
4791
4792 ehdr = skb_push(skb, sizeof(struct ethhdr));
4793 memcpy(ehdr->h_dest, dest, ETH_ALEN);
4794 memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
4795 ehdr->h_proto = proto;
4796
4797 skb->dev = dev;
4798 skb->protocol = htons(ETH_P_802_3);
4799 skb_reset_network_header(skb);
4800 skb_reset_mac_header(skb);
4801
4802 __ieee80211_subif_start_xmit(skb, skb->dev, flags);
4803
4804 return 0;
4805}