--- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -19,6 +19,13 @@ comment "CFG80211 needs to be enabled fo if MAC80211 != n +config MAC80211_NSS_SUPPORT + bool "Enable NSS support for IPQ platform" + default n + ---help--- + This option enables support for NSS in boards + like AP148. + config MAC80211_HAS_RC bool --- a/local-symbols +++ b/local-symbols @@ -31,6 +31,7 @@ LIB80211_CRYPT_CCMP= LIB80211_CRYPT_TKIP= LIB80211_DEBUG= MAC80211= +MAC80211_NSS_SUPPORT= MAC80211_HAS_RC= MAC80211_RC_MINSTREL= MAC80211_RC_DEFAULT_MINSTREL= --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -36,6 +36,10 @@ extern const struct cfg80211_ops mac80211_config_ops; +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +#include +#endif + struct ieee80211_local; struct ieee80211_mesh_fast_tx; @@ -1118,6 +1122,12 @@ struct ieee80211_sub_if_data { } debugfs; #endif +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + struct nss_virt_if_handle *nssctx; + struct sk_buff_head rx_queue; + struct work_struct rx_work; +#endif + /* must be last, dynamically sized area in this! */ struct ieee80211_vif vif; }; --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,12 @@ #include "wme.h" #include "rate.h" +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +bool nss_redirect = true; +module_param(nss_redirect, bool, 0644); +MODULE_PARM_DESC(nss_redirect, "module param to enable NSS Redirect; 1-enable, 0-disable"); +#endif + /** * DOC: Interface list locking * @@ -441,6 +448,64 @@ static int ieee80211_open(struct net_dev return err; } +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +/* This callback is registered for nss redirect to receive packet exceptioned from nss in Rx path. + * When packet does not match any of the ecm rules is redirected back here. + */ +void receive_from_nss(struct net_device *dev, struct sk_buff *sk_buff, struct napi_struct *napi) +{ + struct net_device *netdev; + struct sk_buff *skb; + struct ieee80211_sub_if_data *sdata; + + if (!dev) { + kfree(sk_buff); + return; + } + + netdev = (struct net_device *)dev; + sdata = netdev_priv(netdev); + if (sdata->dev != dev) { + kfree(sk_buff); + return; + } + skb = (struct sk_buff *)sk_buff; + skb->dev = netdev; + skb->protocol = eth_type_trans(skb, netdev); + napi_gro_receive(napi, skb); +} + +static int ieee80211_create_nss_virtif(struct ieee80211_sub_if_data *sdata, struct net_device *dev) +{ + if (sdata->nssctx != NULL) { + sdata_err(sdata, "Cannot create a NSS virtual interface. Already exists[n2h:%d, h2n:%d]!\n", + sdata->nssctx->if_num_n2h, sdata->nssctx->if_num_h2n); + return 1; + } + + sdata->nssctx = NULL; + if (nss_redirect) { + sdata->nssctx = nss_virt_if_create_sync(dev); + if (sdata->nssctx) { + sdata_info(sdata, "Created a NSS virtual interface\n"); + nss_virt_if_register(sdata->nssctx, receive_from_nss, sdata->dev); + } + else + sdata_err(sdata, "Failed to create a NSS virtual interface\n"); + } + + return 0; +} + +static void ieee80211_destroy_nss_virtif(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->nssctx) { + nss_virt_if_destroy_sync(sdata->nssctx); + sdata_info(sdata, "Destroyed NSS virtual interface\n"); + } +} +#endif + static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down) { struct ieee80211_local *local = sdata->local; @@ -802,8 +867,24 @@ static void ieee80211_teardown_sdata(str ieee80211_link_stop(&sdata->deflink); } +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +static int ieee80211_init(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + ieee80211_create_nss_virtif(sdata, dev); + + return 0; +} +#endif + static void ieee80211_uninit(struct net_device *dev) { +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + ieee80211_destroy_nss_virtif(sdata); +#endif ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); } @@ -831,6 +912,9 @@ static int ieee80211_netdev_setup_tc(str static const struct net_device_ops ieee80211_dataif_ops = { .ndo_open = ieee80211_open, .ndo_stop = ieee80211_stop, +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + .ndo_init = ieee80211_init, +#endif .ndo_uninit = ieee80211_uninit, .ndo_start_xmit = ieee80211_subif_start_xmit, .ndo_set_rx_mode = ieee80211_set_multicast_list, --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -33,6 +33,60 @@ #include "wme.h" #include "rate.h" +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +extern bool nss_redirect; + +#define case_rtn_string(val) case val: return #val + +static const char *nss_tx_status_str(nss_tx_status_t status) +{ + switch (status) { + case_rtn_string(NSS_TX_SUCCESS); + case_rtn_string(NSS_TX_FAILURE); + case_rtn_string(NSS_TX_FAILURE_QUEUE); + case_rtn_string(NSS_TX_FAILURE_NOT_READY); + case_rtn_string(NSS_TX_FAILURE_TOO_LARGE); + case_rtn_string(NSS_TX_FAILURE_TOO_SHORT); + case_rtn_string(NSS_TX_FAILURE_NOT_SUPPORTED); + case_rtn_string(NSS_TX_FAILURE_BAD_PARAM); + case_rtn_string(NSS_TX_FAILURE_NOT_ENABLED); + case_rtn_string(NSS_TX_FAILURE_SYNC_BAD_PARAM); + case_rtn_string(NSS_TX_FAILURE_SYNC_TIMEOUT); + case_rtn_string(NSS_TX_FAILURE_SYNC_FW_ERR); + default: + return "Unknown NSS TX status"; + } +} + +static void netif_rx_nss(struct ieee80211_rx_data *rx, + struct sk_buff *skb) +{ + struct ieee80211_sub_if_data *sdata = rx->sdata; + int ret; + + if (!sdata->nssctx) + goto out; + + /* NSS expects ethernet header in skb data so resetting here */ + skb_push(skb, ETH_HLEN); + ret = nss_virt_if_tx_buf(sdata->nssctx, skb); + if (ret) { + if (net_ratelimit() && ret != NSS_TX_FAILURE_TOO_SHORT) { + sdata_err(sdata, "NSS TX failed with error: %s\n", + nss_tx_status_str(ret)); + } + goto out; + } + + return; +out: + if (rx->list) + list_add_tail(&skb->list, rx->list); + else + netif_receive_skb(skb); +} +#endif + /* * monitor mode reception * @@ -2611,14 +2665,16 @@ static void ieee80211_deliver_skb_to_loc ether_addr_copy(ehdr->h_dest, sdata->vif.addr); /* deliver to local stack */ +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + if (likely(nss_redirect)) { + netif_rx_nss(rx, skb); + } +#else if (rx->list) -#if LINUX_VERSION_IS_GEQ(4,19,0) list_add_tail(&skb->list, rx->list); -#else - __skb_queue_tail(rx->list, skb); -#endif else netif_receive_skb(skb); +#endif } } --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -36,6 +36,11 @@ #include "wme.h" #include "rate.h" +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +#include +#include +#endif + /* misc utils */ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, @@ -1734,6 +1739,16 @@ static bool ieee80211_tx_frags(struct ie return true; } } else { +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + if (skb_queue_len(&local->pending[q]) >= 1000) { + spin_unlock_irqrestore( + &local->queue_stop_reason_lock, + flags); + ieee80211_purge_tx_queue(&local->hw, + skbs); + return false; + } +#endif /* * Since queue is stopped, queue up frames for @@ -4477,6 +4492,35 @@ static void ieee80211_mlo_multicast_tx(s kfree_skb(skb); } +#ifdef CPTCFG_MAC80211_NSS_SUPPORT +void ieee80211_xmit_nss_fixup(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + /* Packets from NSS does not have valid protocol, priority and other + * network stack values. Derive required parameters (priority + * and network_header) from payload for QoS header. + * XXX: Here the assumption is that packet are in 802.3 format. + * As of now priority is handled only for IPv4 and IPv6. + */ + + if (sdata->nssctx && likely(!skb->protocol)) { + skb_set_network_header(skb, 14); + switch (((struct ethhdr *)skb->data)->h_proto) { + case htons(ETH_P_IP): + skb->priority = (ipv4_get_dsfield(ip_hdr(skb)) & + 0xfc) >> 5; + break; + case htons(ETH_P_IPV6): + skb->priority = (ipv6_get_dsfield(ipv6_hdr(skb)) & + 0xfc) >> 5; + break; + } + } +} +#endif + /** * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs * @skb: packet to be sent @@ -4490,6 +4534,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); const struct ethhdr *eth = (void *)skb->data; +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + ieee80211_xmit_nss_fixup(skb, dev); +#endif + if (likely(!is_multicast_ether_addr(eth->h_dest))) goto normal; @@ -4675,6 +4723,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8 struct ieee80211_key *key; struct sta_info *sta; +#ifdef CPTCFG_MAC80211_NSS_SUPPORT + ieee80211_xmit_nss_fixup(skb, dev); +#endif + if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) { kfree_skb(skb); return NETDEV_TX_OK;