From: Ahmad Masri <amasri@xxxxxxxxxxxxxx> Send L2UF (Level 2 Update Frame) to update forwarding tables in layer 2 in AP mode. Wil6210 driver creates and sends this frame once a new station connects to the AP. Signed-off-by: Ahmad Masri <amasri@xxxxxxxxxxxxxx> Signed-off-by: Maya Erez <merez@xxxxxxxxxxxxxx> --- drivers/net/wireless/ath/wil6210/txrx.c | 48 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ drivers/net/wireless/ath/wil6210/wmi.c | 2 ++ 3 files changed, 52 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 6a7943e..08d61a5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -43,6 +43,15 @@ module_param(rx_large_buf, bool, 0444); MODULE_PARM_DESC(rx_large_buf, " allocate 8KB RX buffers, default - no"); +/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ +struct l2_update_frame { + struct ethhdr eh; + u8 dsap; + u8 ssap; + u8 control; + u8 xid_info[3]; +} __packed; + static inline uint wil_rx_snaplen(void) { return rx_align_2 ? 6 : 0; @@ -72,6 +81,45 @@ static inline int wil_ring_avail_high(struct wil_ring *ring) return wil_ring_avail_tx(ring) > wil_ring_wmark_high(ring); } +/** + * Send Level 2 Update Frame to update forwarding tables in + * layer 2 bridge devices + */ +void wil_indicate_layer2_update(struct wil6210_vif *vif, + struct wil_sta_info *sta) +{ + struct l2_update_frame *msg; + struct sk_buff *skb; + struct net_device *ndev = vif_to_ndev(vif); + + skb = dev_alloc_skb(sizeof(*msg)); + if (!skb) + return; + + msg = (struct l2_update_frame *)skb_put(skb, sizeof(*msg)); + + /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) + * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 + */ + eth_broadcast_addr(msg->eh.h_dest); + ether_addr_copy(msg->eh.h_source, sta->addr); + msg->eh.h_proto = htons(skb->len - sizeof(struct ethhdr)); + msg->dsap = 0; + msg->ssap = 0; /* NULL LSAP, CR Bit: Response */ + + /* XID response lsb.1111F101. + * F=0 (no poll command; unsolicited frame) + */ + msg->control = 0xaf; + msg->xid_info[0] = 0x81; /* XID format identifier */ + msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ + msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ + + skb->dev = ndev; + skb->protocol = eth_type_trans(skb, ndev); + netif_rx_ni(skb); +} + /* returns true when all tx vrings are empty */ bool wil_is_tx_idle(struct wil6210_priv *wil) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e87c889..1857fb2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1308,6 +1308,8 @@ void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif, void wil_rx_handle(struct wil6210_priv *wil, int *quota); void wil6210_unmask_irq_rx(struct wil6210_priv *wil); void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil); +void wil_indicate_layer2_update(struct wil6210_vif *vif, + struct wil_sta_info *sta); int wil_iftype_nl2wmi(enum nl80211_iftype type); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 45a71fd..7fee674 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1047,6 +1047,8 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) } cfg80211_new_sta(ndev, evt->bssid, sinfo, GFP_KERNEL); + if (wdev->iftype == NL80211_IFTYPE_AP) + wil_indicate_layer2_update(vif, &wil->sta[evt->cid]); kfree(sinfo); } else { -- 1.9.1