static int r92su_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params, u64 *cookie) { struct r92su *r92su = wiphy_priv(wiphy); struct sk_buff *skb; if (params->len < sizeof(struct ieee80211_hdr)) return -EINVAL; skb = dev_alloc_skb(r92su->wdev.netdev->needed_headroom + params->len + r92su->wdev.netdev->needed_tailroom); if (!skb) return -ENOMEM; skb_reserve(skb, r92su->wdev.netdev->needed_headroom); memcpy(skb_put(skb, params->len), params->buf, params->len); r92su_tx(r92su, skb, true); return 0; }
static netdev_tx_t r92su_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct r92su *r92su = ndev->ml_priv; switch (r92su->wdev.iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: if (skb->len >= ETH_ALEN + ETH_ALEN + 2) r92su_tx(r92su, skb, false); break; case NL80211_IFTYPE_MONITOR: r92su_tx_monitor(r92su, skb); break; default: dev_kfree_skb_any(skb); break; } return NETDEV_TX_OK; }
static void r92su_survey_done_work(struct work_struct *work) { struct cfg80211_scan_request *req; struct r92su *r92su = container_of(work, struct r92su, survey_done_work.work); mutex_lock(&r92su->lock); if (!r92su_is_open(r92su)) goto out; req = r92su->scan_request; r92su->scan_request = NULL; if (req) { struct cfg80211_scan_info info = { .aborted = false, }; cfg80211_scan_done(req, &info); } r92su->scanned = true; complete(&r92su->scan_done); out: mutex_unlock(&r92su->lock); } static int r92su_stop(struct net_device *ndev) { struct r92su *r92su = ndev->ml_priv; struct cfg80211_bss *tmp_bss; struct llist_node *node; int err = -EINVAL, i; mutex_lock(&r92su->lock); if (r92su_is_connected(r92su)) { err = __r92su_disconnect(r92su); WARN_ONCE(err, "disconnect failed"); } r92su_set_power(r92su, false); if (r92su_is_initializing(r92su)) { err = r92su_hw_mac_deinit(r92su); WARN_ONCE(err, "failed to deinitilize MAC"); } if (r92su_is_initializing(r92su)) r92su_set_state(r92su, R92SU_STOP); if (r92su->scan_request) { struct cfg80211_scan_info info = { .aborted = true, }; cfg80211_scan_done(r92su->scan_request, &info); } tmp_bss = r92su->want_connect_bss; r92su->want_connect_bss = NULL; r92su_bss_free(r92su, tmp_bss); r92su->scan_request = NULL; for (i = 0; i < MAX_STA; i++) r92su_sta_del(r92su, i); mutex_unlock(&r92su->lock); cancel_delayed_work_sync(&r92su->survey_done_work); cancel_delayed_work_sync(&r92su->service_work); cancel_work_sync(&r92su->add_bss_work); cancel_work_sync(&r92su->connect_bss_work); cancel_work_sync(&r92su->disconnect_work); node = llist_del_all(&r92su->add_bss_list); while (node) { struct r92su_add_bss *bss_priv = llist_entry(node, struct r92su_add_bss, head); node = ACCESS_ONCE(node->next); kfree(bss_priv); } /* wait for keys and stas to be freed */ synchronize_rcu(); rcu_barrier(); return err; } static netdev_tx_t r92su_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct r92su *r92su = ndev->ml_priv; switch (r92su->wdev.iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: if (skb->len >= ETH_ALEN + ETH_ALEN + 2) r92su_tx(r92su, skb, false); break; case NL80211_IFTYPE_MONITOR: r92su_tx_monitor(r92su, skb); break; default: dev_kfree_skb_any(skb); break; } return NETDEV_TX_OK; } static const struct net_device_ops r92su_netdevice_ops = { .ndo_open = r92su_open, .ndo_stop = r92su_stop, .ndo_start_xmit = r92su_start_xmit, .ndo_set_mac_address = eth_mac_addr, .ndo_set_rx_mode = r92su_set_rx_mode, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, }; static void *devm_dup(struct device *dev, void *src, size_t len) { void *tmp; tmp = devm_kzalloc(dev, len, GFP_KERNEL); if (tmp) memcpy(tmp, src, len); return tmp; } static int r92su_init_band(struct r92su *r92su) { struct ieee80211_supported_band *band; band = &r92su->band_2GHZ; band->channels = devm_dup(&r92su->wdev.wiphy->dev, r92su_channeltable, sizeof(r92su_channeltable)); if (!band->channels) return -ENOMEM; band->bitrates = devm_dup(&r92su->wdev.wiphy->dev, r92su_ratetable, sizeof(r92su_ratetable)); if (!band->bitrates) return -ENOMEM; band->n_channels = ARRAY_SIZE(r92su_channeltable); band->n_bitrates = ARRAY_SIZE(r92su_ratetable); memcpy(&band->ht_cap, &r92su_ht_info, sizeof(r92su_ht_info)); band->ht_cap.ht_supported = !r92su->disable_ht; switch (r92su->rf_type) { case R92SU_1T1R: /* nothing needs to be done. The default ht_cap * contains all the necessary bits for just 1T1R * devices */ break; case R92SU_1T2R: case R92SU_2T2R: band->ht_cap.mcs.rx_mask[1] = 0xff; band->ht_cap.mcs.rx_highest = cpu_to_le16(300); break; } r92su->wdev.wiphy->bands[NL80211_BAND_2GHZ] = &r92su->band_2GHZ; return 0; } static const struct ieee80211_txrx_stypes r92su_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_ADHOC] = { .tx = 0xffff, .rx = 0, },