/* * CFG802.11 operation handler for association request. * * This function does not work when the current mode is set to Ad-Hoc, or * when there is already an association procedure going on. The given BSS * information is used to associate. */ static int mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret = 0; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "received infra assoc request " "when station is in ibss mode\n"); goto done; } wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, priv->bss_mode, sme->channel, sme, 0); done: if (!ret) { cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0, NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL); dev_dbg(priv->adapter->dev, "info: associated to bssid %pM successfully\n", priv->cfg_bssid); } else { dev_dbg(priv->adapter->dev, "info: association to bssid %pM failed\n", priv->cfg_bssid); memset(priv->cfg_bssid, 0, ETH_ALEN); } return ret; }
/* * del_virtual_intf: remove the virtual interface determined by dev */ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); #endif if (!netif_queue_stopped(priv->netdev)) netif_stop_queue(priv->netdev); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); if (dev->reg_state == NETREG_REGISTERED) unregister_netdevice(dev); if (dev->reg_state == NETREG_UNREGISTERED) free_netdev(dev); /* Clear the priv in adapter */ priv->netdev = NULL; priv->media_connected = false; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; return 0; }
/* * CFG802.11 network device handler for data transmission. */ static int mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; struct timeval tv; dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", jiffies, priv->bss_type, priv->bss_num); if (priv->adapter->surprise_removed) { kfree_skb(skb); priv->stats.tx_dropped++; return 0; } if (!skb->len || (skb->len > ETH_FRAME_LEN)) { dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); kfree_skb(skb); priv->stats.tx_dropped++; return 0; } if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { dev_dbg(priv->adapter->dev, "data: Tx: insufficient skb headroom %d\n", skb_headroom(skb)); /* Insufficient skb headroom - allocate a new skb */ new_skb = skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); if (unlikely(!new_skb)) { dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); kfree_skb(skb); priv->stats.tx_dropped++; return 0; } kfree_skb(skb); skb = new_skb; dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", skb_headroom(skb)); } tx_info = MWIFIEX_SKB_TXCB(skb); memset(tx_info, 0, sizeof(*tx_info)); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; /* Record the current time the packet was queued; used to * determine the amount of time the packet was queued in * the driver before it was sent to the firmware. * The delay is then sent along with the packet to the * firmware for aggregate delay calculation for stats and * MSDU lifetime expiry. */ do_gettimeofday(&tv); skb->tstamp = timeval_to_ktime(tv); mwifiex_queue_tx_pkt(priv, skb); return 0; }
/* * CFG802.11 operation handler for association request. * * This function does not work when the current mode is set to Ad-Hoc, or * when there is already an association procedure going on. The given BSS * information is used to associate. */ static int mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret = 0; if (priv->assoc_request) return -EBUSY; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "received infra assoc request " "when station is in ibss mode\n"); goto done; } priv->assoc_request = -EINPROGRESS; wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, priv->bss_mode, sme->channel, sme, 0); priv->assoc_request = 1; done: priv->assoc_result = ret; queue_work(priv->workqueue, &priv->cfg_workqueue); return ret; }
/* * CFG802.11 operation handler to join an IBSS. * * This function does not work in any mode other than Ad-Hoc, or if * a join operation is already in progress. */ static int mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret = 0; if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "request to join ibss received " "when station is not in ibss mode\n"); goto done; } wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", (char *) params->ssid, params->bssid); ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, params->channel, NULL, params->privacy); done: if (!ret) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); dev_dbg(priv->adapter->dev, "info: joined/created adhoc network with bssid" " %pM successfully\n", priv->cfg_bssid); } else { dev_dbg(priv->adapter->dev, "info: failed creating/joining adhoc network\n"); } return ret; }
/* * CFG802.11 operation handler for connection quality monitoring. * * This function subscribes/unsubscribes HIGH_RSSI and LOW_RSSI * events to FW. */ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, s32 rssi_thold, u32 rssi_hyst) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_ds_misc_subsc_evt subsc_evt; priv->cqm_rssi_thold = rssi_thold; priv->cqm_rssi_hyst = rssi_hyst; memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt)); subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; /* Subscribe/unsubscribe low and high rssi events */ if (rssi_thold && rssi_hyst) { subsc_evt.action = HostCmd_ACT_BITWISE_SET; subsc_evt.bcn_l_rssi_cfg.abs_value = abs(rssi_thold); subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold); subsc_evt.bcn_l_rssi_cfg.evt_freq = 1; subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 0, 0, &subsc_evt); } else { subsc_evt.action = HostCmd_ACT_BITWISE_CLR; return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 0, 0, &subsc_evt); } return 0; }
/* * CFG802.11 network device handler for transmission timeout. */ static void mwifiex_tx_timeout(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_type-num = %d-%d\n", jiffies, priv->bss_type, priv->bss_num); mwifiex_set_trans_start(dev); priv->num_tx_timeout++; }
/* * CFG802.11 operation handler to dump station information. */ static int mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (!priv->media_connected || idx) return -ENOENT; memcpy(mac, priv->cfg_bssid, ETH_ALEN); return mwifiex_dump_station_info(priv, sinfo); }
/* * CFG802.11 network device handler for close. */ static int mwifiex_close(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->scan_request) { dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n"); cfg80211_scan_done(priv->scan_request, 1); priv->scan_request = NULL; } return 0; }
/* * CFG802.11 operation handler to leave an IBSS. * * This function does not work if a leave operation is * already in progress. */ static int mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", priv->cfg_bssid); if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; memset(priv->cfg_bssid, 0, ETH_ALEN); return 0; }
/* * CFG802.11 operation handler to delete a network key. */ static int mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) { wiphy_err(wiphy, "deleting the crypto keys\n"); return -EFAULT; } wiphy_dbg(wiphy, "info: crypto keys deleted\n"); return 0; }
/* * CFG802.11 operation handler to add a network key. */ static int mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); if (mwifiex_set_encode(priv, params->key, params->key_len, key_index, 0)) { wiphy_err(wiphy, "crypto keys added\n"); return -EFAULT; } return 0; }
/* cfg80211 operation handler for stop ap. * Function stops BSS running at uAP interface. */ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (mwifiex_del_mgmt_ies(priv)) wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "Failed to stop the BSS\n"); return -1; } return 0; }
/* * CFG802.11 operation handler to set Power Save option. * * The timeout value, if provided, is currently ignored. */ static int mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); u32 ps_mode; if (timeout) wiphy_dbg(wiphy, "info: ignore timeout value for IEEE Power Save\n"); ps_mode = enabled; return mwifiex_drv_set_power(priv, &ps_mode); }
/* * CFG802.11 operation handler for disconnection request. * * This function does not work when there is already a disconnection * procedure going on. */ static int mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" " reason code %d\n", priv->cfg_bssid, reason_code); memset(priv->cfg_bssid, 0, ETH_ALEN); return 0; }
/* * CFG802.11 operation handler for scan request. * * This function issues a scan request to the firmware based upon * the user specified scan configuration. On successfull completion, * it also informs the results. */ static int mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); if (priv->scan_request && priv->scan_request != request) return -EBUSY; priv->scan_request = request; queue_work(priv->workqueue, &priv->cfg_workqueue); return 0; }
/* * CFG802.11 operation handler for setting bit rates. * * Function selects legacy bang B/G/BG from corresponding bitrates selection. * Currently only 2.4GHz band is supported. */ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, const struct cfg80211_bitrate_mask *mask) { struct mwifiex_ds_band_cfg band_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int index = 0, mode = 0, i; /* Currently only 2.4GHz is supported */ for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { /* * Rates below 6 Mbps in the table are CCK rates; 802.11b * and from 6 they are OFDM; 802.11G */ if (mwifiex_rates[i].bitrate == 60) { index = 1 << i; break; } } if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) { mode = BAND_B; } else { mode = BAND_G; if (mask->control[IEEE80211_BAND_2GHZ].legacy % index) mode |= BAND_B; } memset(&band_cfg, 0, sizeof(band_cfg)); band_cfg.config_bands = mode; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) band_cfg.adhoc_start_band = mode; band_cfg.sec_chan_offset = NO_SEC_CHANNEL; if (mwifiex_set_radio_band_cfg(priv, &band_cfg)) return -EFAULT; wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n", (mode & BAND_B) ? "b" : "", (mode & BAND_G) ? "g" : ""); return 0; }
/* * CFG802.11 network device handler for setting multicast list. */ static void mwifiex_set_multicast_list(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_multicast_list mcast_list; if (dev->flags & IFF_PROMISC) { mcast_list.mode = MWIFIEX_PROMISC_MODE; } else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; } else { mcast_list.mode = MWIFIEX_MULTICAST_MODE; mcast_list.num_multicast_addr = mwifiex_copy_mcast_addr(&mcast_list, dev); } mwifiex_request_set_multicast_list(priv, &mcast_list); }
/* * CFG802.11 operation handler to set the default network key. */ static int mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool unicast, bool multicast) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); /* Return if WEP key not configured */ if (!priv->sec_info.wep_enabled) return 0; if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) { wiphy_err(wiphy, "set default Tx key index\n"); return -EFAULT; } return 0; }
/* * CFG802.11 operation handler for setting bit rates. * * Function selects legacy bang B/G/BG from corresponding bitrates selection. * Currently only 2.4GHz band is supported. */ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, const struct cfg80211_bitrate_mask *mask) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int index = 0, mode = 0, i; struct mwifiex_adapter *adapter = priv->adapter; /* Currently only 2.4GHz is supported */ for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { /* * Rates below 6 Mbps in the table are CCK rates; 802.11b * and from 6 they are OFDM; 802.11G */ if (mwifiex_rates[i].bitrate == 60) { index = 1 << i; break; } } if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) { mode = BAND_B; } else { mode = BAND_G; if (mask->control[IEEE80211_BAND_2GHZ].legacy % index) mode |= BAND_B; } if (!((mode | adapter->fw_bands) & ~adapter->fw_bands)) { adapter->config_bands = mode; if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { adapter->adhoc_start_band = mode; adapter->adhoc_11n_enabled = false; } } adapter->sec_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; adapter->channel_type = NL80211_CHAN_NO_HT; wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n", (mode & BAND_B) ? "b" : "", (mode & BAND_G) ? "g" : ""); return 0; }
/* * CFG802.11 operation handler to change interface type. */ static int mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->bss_mode == type) { wiphy_warn(wiphy, "already set to required type\n"); return 0; } priv->bss_mode = type; switch (type) { case NL80211_IFTYPE_ADHOC: dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); break; case NL80211_IFTYPE_STATION: dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; wiphy_dbg(wiphy, "info: setting interface type to managed\n"); break; case NL80211_IFTYPE_UNSPECIFIED: dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; wiphy_dbg(wiphy, "info: setting interface type to auto\n"); return 0; default: wiphy_err(wiphy, "unknown interface type: %d\n", type); return -EINVAL; } mwifiex_deauthenticate(priv, NULL); priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, NULL); return ret; }
/* * CFG802.11 network device handler for transmission timeout. */ static void mwifiex_tx_timeout(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); priv->num_tx_timeout++; priv->tx_timeout_cnt++; dev_err(priv->adapter->dev, "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n", jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num); mwifiex_set_trans_start(dev); if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD && priv->adapter->if_ops.card_reset) { dev_err(priv->adapter->dev, "tx_timeout_cnt exceeds threshold. Triggering card reset!\n"); priv->adapter->if_ops.card_reset(priv->adapter); } }
/* * CFG802.11 operation handler to set channel. * * This function can only be used when station is not connected. */ static int mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { struct mwifiex_private *priv; if (dev) priv = mwifiex_netdev_get_priv(dev); else priv = mwifiex_cfg80211_get_priv(wiphy); if (priv->media_connected) { wiphy_err(wiphy, "This setting is valid only when station " "is not connected\n"); return -EINVAL; } return mwifiex_set_rf_channel(priv, chan, channel_type); }
/* * CFG802.11 operation handler for disconnection request. * * This function does not work when there is already a disconnection * procedure going on. */ static int mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->disconnect) return -EBUSY; priv->disconnect = 1; if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" " reason code %d\n", priv->cfg_bssid, reason_code); queue_work(priv->workqueue, &priv->cfg_workqueue); return 0; }
static void mwifiex_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); u32 conditions = le32_to_cpu(priv->adapter->hs_cfg.conditions); wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY; if (conditions == HS_CFG_COND_DEF) return; if (conditions & HS_CFG_COND_UNICAST_DATA) wol->wolopts |= WAKE_UCAST; if (conditions & HS_CFG_COND_MULTICAST_DATA) wol->wolopts |= WAKE_MCAST; if (conditions & HS_CFG_COND_BROADCAST_DATA) wol->wolopts |= WAKE_BCAST; if (conditions & HS_CFG_COND_MAC_EVENT) wol->wolopts |= WAKE_PHY; }
/* * CFG802.11 operation handler for scan request. * * This function issues a scan request to the firmware based upon * the user specified scan configuration. On successfull completion, * it also informs the results. */ static int mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int i; struct ieee80211_channel *chan; wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); priv->scan_request = request; priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); if (!priv->user_scan_cfg) { dev_err(priv->adapter->dev, "failed to alloc scan_req\n"); return -ENOMEM; } priv->user_scan_cfg->num_ssids = request->n_ssids; priv->user_scan_cfg->ssid_list = request->ssids; for (i = 0; i < request->n_channels; i++) { chan = request->channels[i]; priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value; priv->user_scan_cfg->chan_list[i].radio_type = chan->band; if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) priv->user_scan_cfg->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_PASSIVE; else priv->user_scan_cfg->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_ACTIVE; priv->user_scan_cfg->chan_list[i].scan_time = 0; } if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg)) return -EFAULT; return 0; }
/* * CFG802.11 network device handler for close. */ static int mwifiex_close(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->scan_request) { mwifiex_dbg(priv->adapter, INFO, "aborting scan on ndo_stop\n"); cfg80211_scan_done(priv->scan_request, 1); priv->scan_request = NULL; priv->scan_aborting = true; } if (priv->sched_scanning) { mwifiex_dbg(priv->adapter, INFO, "aborting bgscan on ndo_stop\n"); mwifiex_stop_bg_scan(priv); cfg80211_sched_scan_stopped(priv->wdev.wiphy); } return 0; }
/* * CFG802.11 network device handler for setting MAC address. */ static int mwifiex_set_mac_address(struct net_device *dev, void *addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sockaddr *hw_addr = addr; int ret; memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS, HostCmd_ACT_GEN_SET, 0, NULL); if (!ret) memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); else dev_err(priv->adapter->dev, "set mac address failed: ret=%d\n", ret); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); return ret; }
static int mwifiex_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); u32 conditions = 0; if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY)) return -EOPNOTSUPP; if (wol->wolopts & WAKE_UCAST) conditions |= HS_CFG_COND_UNICAST_DATA; if (wol->wolopts & WAKE_MCAST) conditions |= HS_CFG_COND_MULTICAST_DATA; if (wol->wolopts & WAKE_BCAST) conditions |= HS_CFG_COND_BROADCAST_DATA; if (wol->wolopts & WAKE_PHY) conditions |= HS_CFG_COND_MAC_EVENT; if (wol->wolopts == 0) conditions |= HS_CFG_COND_DEF; priv->adapter->hs_cfg.conditions = cpu_to_le32(conditions); return 0; }
/* * CFG802.11 network device handler for statistics retrieval. */ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); return &priv->stats; }