Commit a621fa4d authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: allow changing port control protocol

Some vendor specified mechanisms for 802.1X-style
functionality use a different protocol than EAP
(even if EAP is vendor-extensible). Support this
in mac80211 via the cfg80211 API for it.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c0692b8f
...@@ -509,6 +509,8 @@ struct ieee80211_sub_if_data { ...@@ -509,6 +509,8 @@ struct ieee80211_sub_if_data {
struct ieee80211_key *default_mgmt_key; struct ieee80211_key *default_mgmt_key;
u16 sequence_number; u16 sequence_number;
__be16 control_port_protocol;
bool control_port_no_encrypt;
struct work_struct work; struct work_struct work;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
......
...@@ -855,6 +855,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, ...@@ -855,6 +855,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->dev->netdev_ops = &ieee80211_dataif_ops; sdata->dev->netdev_ops = &ieee80211_dataif_ops;
sdata->wdev.iftype = type; sdata->wdev.iftype = type;
sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
sdata->control_port_no_encrypt = false;
/* only monitor differs */ /* only monitor differs */
sdata->dev->type = ARPHRD_ETHER; sdata->dev->type = ARPHRD_ETHER;
......
...@@ -627,6 +627,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -627,6 +627,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
#endif #endif
/* mac80211 supports control port protocol changing */
local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
......
...@@ -2262,6 +2262,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ...@@ -2262,6 +2262,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
else else
ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
sdata->control_port_protocol = req->crypto.control_port_ethertype;
sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
ieee80211_add_work(wk); ieee80211_add_work(wk);
return 0; return 0;
} }
......
...@@ -1527,7 +1527,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) ...@@ -1527,7 +1527,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
* Allow EAPOL frames to us/the PAE group address regardless * Allow EAPOL frames to us/the PAE group address regardless
* of whether the frame was encrypted or not. * of whether the frame was encrypted or not.
*/ */
if (ehdr->h_proto == htons(ETH_P_PAE) && if (ehdr->h_proto == rx->sdata->control_port_protocol &&
(compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 || (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
return true; return true;
......
...@@ -508,6 +508,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) ...@@ -508,6 +508,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
return ieee80211_tx_h_multicast_ps_buf(tx); return ieee80211_tx_h_multicast_ps_buf(tx);
} }
static ieee80211_tx_result debug_noinline
ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol &&
tx->sdata->control_port_no_encrypt))
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
return TX_CONTINUE;
}
static ieee80211_tx_result debug_noinline static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{ {
...@@ -527,7 +539,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) ...@@ -527,7 +539,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
else if ((key = rcu_dereference(tx->sdata->default_key))) else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key; tx->key = key;
else if (tx->sdata->drop_unencrypted && else if (tx->sdata->drop_unencrypted &&
(tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) && (tx->skb->protocol != tx->sdata->control_port_protocol) &&
!(info->flags & IEEE80211_TX_CTL_INJECTED) && !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!ieee80211_is_robust_mgmt_frame(hdr) || (!ieee80211_is_robust_mgmt_frame(hdr) ||
(ieee80211_is_action(hdr->frame_control) && (ieee80211_is_action(hdr->frame_control) &&
...@@ -1349,6 +1361,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) ...@@ -1349,6 +1361,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
CALL_TXH(ieee80211_tx_h_dynamic_ps); CALL_TXH(ieee80211_tx_h_dynamic_ps);
CALL_TXH(ieee80211_tx_h_check_assoc); CALL_TXH(ieee80211_tx_h_check_assoc);
CALL_TXH(ieee80211_tx_h_ps_buf); CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
CALL_TXH(ieee80211_tx_h_select_key); CALL_TXH(ieee80211_tx_h_select_key);
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
CALL_TXH(ieee80211_tx_h_rate_ctrl); CALL_TXH(ieee80211_tx_h_rate_ctrl);
...@@ -1826,7 +1839,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1826,7 +1839,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
#endif #endif
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { if (sdata->u.mgd.use_4addr &&
cpu_to_be16(ethertype) != sdata->control_port_protocol) {
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */ /* RA TA DA SA */
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
...@@ -1879,7 +1893,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1879,7 +1893,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (!ieee80211_vif_is_mesh(&sdata->vif) && if (!ieee80211_vif_is_mesh(&sdata->vif) &&
unlikely(!is_multicast_ether_addr(hdr.addr1) && unlikely(!is_multicast_ether_addr(hdr.addr1) &&
!(sta_flags & WLAN_STA_AUTHORIZED) && !(sta_flags & WLAN_STA_AUTHORIZED) &&
!(ethertype == ETH_P_PAE && !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
compare_ether_addr(sdata->vif.addr, compare_ether_addr(sdata->vif.addr,
skb->data + ETH_ALEN) == 0))) { skb->data + ETH_ALEN) == 0))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment