static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { struct orinoco_private *priv = wiphy_priv(wiphy); int err = 0; unsigned long lock; if (orinoco_lock(priv, &lock) != 0) return -EBUSY; switch (type) { case NL80211_IFTYPE_ADHOC: if (!priv->has_ibss && !priv->has_port3) err = -EINVAL; break; case NL80211_IFTYPE_STATION: break; case NL80211_IFTYPE_MONITOR: if (priv->broken_monitor && !force_monitor) { <<<<<<< HEAD wiphy_warn(wiphy, "Monitor mode support is buggy in this firmware, not enabling\n"); ======= printk(KERN_WARNING "%s: Monitor mode support is " "buggy in this firmware, not enabling\n", wiphy_name(wiphy)); >>>>>>> 296c66da8a02d52243f45b80521febece5ed498a
void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); #ifdef CONFIG_INET unregister_inetaddr_notifier(&local->ifa_notifier); #endif rtnl_lock(); /* * At this point, interface list manipulations are fine * because the driver cannot be handing us frames any * more and the tasklet is killed. */ ieee80211_remove_interfaces(local); rtnl_unlock(); /* * Now all work items will be gone, but the * timer might still be armed, so delete it */ del_timer_sync(&local->work_timer); cancel_work_sync(&local->restart_work); cancel_work_sync(&local->reconfig_filter); ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); skb_queue_purge(&local->rx_skb_queue); destroy_workqueue(local->workqueue); wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); kfree(local->int_scan_req); }
static void mwl_mac80211_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mwl_priv *priv = hw->priv; if (!priv->radio_on) { wiphy_warn(hw->wiphy, "dropped TX frame since radio is disabled\n"); dev_kfree_skb_any(skb); return; } mwl_tx_xmit(hw, control, skb); }
void cw1200_scan_timeout(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, scan.timeout.work); if (atomic_xchg(&priv->scan.in_progress, 0)) { if (priv->scan.status > 0) { priv->scan.status = 0; } else if (!priv->scan.status) { wiphy_warn(priv->hw->wiphy, "Timeout waiting for scan complete notification.\n"); priv->scan.status = -ETIMEDOUT; priv->scan.curr = priv->scan.end; wsm_stop_scan(priv); } cw1200_scan_complete(priv); } }
static int mwl_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, unsigned long throttle_state) { struct mwl_priv *priv = cdev->devdata; if (throttle_state > SYSADPT_THERMAL_THROTTLE_MAX) { wiphy_warn(priv->hw->wiphy, "throttle state %ld is exceeding the limit %d\n", throttle_state, SYSADPT_THERMAL_THROTTLE_MAX); return -EINVAL; } priv->throttle_state = throttle_state; mwl_thermal_set_throttling(priv); return 0; }
void mwl_thermal_set_throttling(struct mwl_priv *priv) { u32 period, duration, enabled; int ret; period = priv->quiet_period; duration = (period * priv->throttle_state) / 100; enabled = duration ? 1 : 0; ret = mwl_fwcmd_quiet_mode(priv->hw, enabled, period, duration, SYSADPT_QUIET_START_OFFSET); if (ret) { wiphy_warn(priv->hw->wiphy, "failed: period %u duarion %u enabled %u ret %d\n", period, duration, enabled, ret); } }
/* * 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; }
static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { struct orinoco_private *priv = wiphy_priv(wiphy); int err = 0; unsigned long lock; if (orinoco_lock(priv, &lock) != 0) return -EBUSY; switch (type) { case NL80211_IFTYPE_ADHOC: if (!priv->has_ibss && !priv->has_port3) err = -EINVAL; break; case NL80211_IFTYPE_STATION: break; case NL80211_IFTYPE_MONITOR: if (priv->broken_monitor && !force_monitor) { wiphy_warn(wiphy, "Monitor mode support is buggy in this firmware, not enabling\n"); err = -EINVAL; } break; default: err = -EINVAL; } if (!err) { priv->iw_mode = type; set_port_type(priv); err = orinoco_commit(priv); } orinoco_unlock(priv, &lock); return err; }
static ssize_t mwl_thermal_show_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct mwl_priv *priv = dev_get_drvdata(dev); int ret, temperature; ret = mwl_fwcmd_get_temp(priv->hw, &priv->temperature); if (ret) { wiphy_warn(priv->hw->wiphy, "failed: can't get temperature\n"); goto out; } temperature = priv->temperature; /* display in millidegree celcius */ ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); out: return ret; }
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; struct eeprom_pda_wrap *wrap; struct pda_entry *entry; unsigned int data_len, entry_len; void *tmp; int err; u8 *end = (u8 *)eeprom + len; u16 synth = 0; u16 crc16 = ~0; wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); /* verify that at least the entry length/code fits */ while ((u8 *)entry <= end - sizeof(*entry)) { entry_len = le16_to_cpu(entry->len); data_len = ((entry_len - 1) << 1); /* abort if entry exceeds whole structure */ if ((u8 *)entry + sizeof(*entry) + data_len > end) break; switch (le16_to_cpu(entry->code)) { case PDR_MAC_ADDRESS: if (data_len != ETH_ALEN) break; SET_IEEE80211_PERM_ADDR(dev, entry->data); break; case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: if (priv->output_limit) break; err = p54_convert_output_limits(dev, entry->data, data_len); if (err) goto err; break; case PDR_PRISM_PA_CAL_CURVE_DATA: { struct pda_pa_curve_data *curve_data = (struct pda_pa_curve_data *)entry->data; if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; } switch (curve_data->cal_method_rev) { case 0: err = p54_convert_rev0(dev, curve_data); break; case 1: err = p54_convert_rev1(dev, curve_data); break; default: wiphy_err(dev->wiphy, "unknown curve data revision %d\n", curve_data->cal_method_rev); err = -ENODEV; break; } if (err) goto err; } break; case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: priv->iq_autocal = kmemdup(entry->data, data_len, GFP_KERNEL); if (!priv->iq_autocal) { err = -ENOMEM; goto err; } priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); break; case PDR_DEFAULT_COUNTRY: p54_parse_default_country(dev, entry->data, data_len); break; case PDR_INTERFACE_LIST: tmp = entry->data; while ((u8 *)tmp < entry->data + data_len) { struct exp_if *exp_if = tmp; if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000)) synth = le16_to_cpu(exp_if->variant); tmp += sizeof(*exp_if); } break; case PDR_HARDWARE_PLATFORM_COMPONENT_ID: if (data_len < 2) break; priv->version = *(u8 *)(entry->data + 1); break; case PDR_RSSI_LINEAR_APPROXIMATION: case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: err = p54_parse_rssical(dev, entry->data, data_len, le16_to_cpu(entry->code)); if (err) goto err; break; case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: { struct pda_custom_wrapper *pda = (void *) entry->data; __le16 *src; u16 *dst; int i; if (priv->rssi_db || data_len < sizeof(*pda)) break; priv->rssi_db = p54_convert_db(pda, data_len); if (!priv->rssi_db) break; src = (void *) priv->rssi_db->data; dst = (void *) priv->rssi_db->data; for (i = 0; i < priv->rssi_db->entries; i++) *(dst++) = (s16) le16_to_cpu(*(src++)); } break; case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { struct pda_custom_wrapper *pda = (void *) entry->data; if (priv->output_limit || data_len < sizeof(*pda)) break; priv->output_limit = p54_convert_db(pda, data_len); } break; case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: { struct pda_custom_wrapper *pda = (void *) entry->data; if (priv->curve_data || data_len < sizeof(*pda)) break; priv->curve_data = p54_convert_db(pda, data_len); } break; case PDR_END: crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry)); if (crc16 != le16_to_cpup((__le16 *)entry->data)) { wiphy_err(dev->wiphy, "eeprom failed checksum " "test!\n"); err = -ENOMSG; goto err; } else { goto good_eeprom; } break; default: break; } crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2); entry = (void *)entry + (entry_len + 1) * 2; } wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n"); err = -ENODATA; goto err; good_eeprom: if (!synth || !priv->iq_autocal || !priv->output_limit || !priv->curve_data) { wiphy_err(dev->wiphy, "not all required entries found in eeprom!\n"); err = -EINVAL; goto err; } err = p54_generate_channel_lists(dev); if (err) goto err; priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) p54_init_xbow_synth(priv); if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = priv->band_table[IEEE80211_BAND_2GHZ]; if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_5GHZ] = priv->band_table[IEEE80211_BAND_5GHZ]; if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) priv->rx_diversity_mask = 3; if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) priv->tx_diversity_mask = 3; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { u8 perm_addr[ETH_ALEN]; wiphy_warn(dev->wiphy, "Invalid hwaddr! Using randomly generated MAC addr\n"); random_ether_addr(perm_addr); SET_IEEE80211_PERM_ADDR(dev, perm_addr); } priv->cur_rssi = &p54_rssi_default; wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n", dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); return 0; err: kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); kfree(priv->rssi_db); priv->iq_autocal = NULL; priv->output_limit = NULL; priv->curve_data = NULL; priv->rssi_db = NULL; wiphy_err(dev->wiphy, "eeprom parse failed!\n"); return err; }
/* * 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); switch (dev->ieee80211_ptr->iftype) { case NL80211_IFTYPE_ADHOC: switch (type) { case NL80211_IFTYPE_STATION: break; case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ return 0; case NL80211_IFTYPE_AP: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); return -EOPNOTSUPP; } break; case NL80211_IFTYPE_STATION: switch (type) { case NL80211_IFTYPE_ADHOC: break; case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); case NL80211_IFTYPE_STATION: /* This shouldn't happen */ return 0; case NL80211_IFTYPE_AP: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); return -EOPNOTSUPP; } break; case NL80211_IFTYPE_AP: switch (type) { case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); case NL80211_IFTYPE_AP: /* This shouldn't happen */ return 0; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); return -EOPNOTSUPP; } break; default: wiphy_err(wiphy, "%s: unknown iftype: %d\n", dev->name, dev->ieee80211_ptr->iftype); return -EOPNOTSUPP; } dev->ieee80211_ptr->iftype = type; priv->bss_mode = type; 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; }
int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); int result, i; enum ieee80211_band band; int channels, max_bitrates; bool supp_ht; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, /* keep last -- depends on hw flags! */ WLAN_CIPHER_SUITE_AES_CMAC }; if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) #ifdef CONFIG_PM && (!local->ops->suspend || !local->ops->resume) #endif ) return -EINVAL; if (hw->max_report_rates == 0) hw->max_report_rates = hw->max_rates; /* * generic code guarantees at least one band, * set this very early because much code assumes * that hw.conf.channel is assigned */ channels = 0; max_bitrates = 0; supp_ht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; sband = local->hw.wiphy->bands[band]; if (!sband) continue; if (!local->oper_channel) { /* init channel we're on */ local->hw.conf.channel = local->oper_channel = &sband->channels[0]; local->hw.conf.channel_type = NL80211_CHAN_NO_HT; } channels += sband->n_channels; if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + sizeof(void *) * channels, GFP_KERNEL); if (!local->int_scan_req) return -ENOMEM; /* if low-level driver supports AP, we also support VLAN */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); } /* mac80211 always supports monitor */ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); /* * mac80211 doesn't support more than 1 channel, and also not more * than one IBSS interface */ for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { const struct ieee80211_iface_combination *c; int j; c = &hw->wiphy->iface_combinations[i]; if (c->num_different_channels > 1) return -EINVAL; for (j = 0; j < c->n_limits; j++) if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && c->limits[j].max > 1) return -EINVAL; } #ifndef CONFIG_MAC80211_MESH /* mesh depends on Kconfig, but drivers should set it if they want */ local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); #endif /* if the underlying driver supports mesh, mac80211 will (at least) * provide routing of mesh authentication frames to userspace */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; /* mac80211 supports control port protocol changing */ local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); /* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It * includes the DS Params, (extended) supported rates, and HT * information -- SSID is the driver's responsibility. */ local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ + 3 /* DS Params */; if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; } /* * If the driver supports any scan IEs, then assume the * limit includes the IEs mac80211 will add, otherwise * leave it at zero and let the driver sort it out; we * still pass our IEs to the driver but userspace will * not be allowed to in that case. */ if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; /* Set up cipher suites unless driver already did */ if (!local->hw.wiphy->cipher_suites) { local->hw.wiphy->cipher_suites = cipher_suites; local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) local->hw.wiphy->n_cipher_suites--; } if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { if (local->hw.wiphy->cipher_suites == cipher_suites) { local->hw.wiphy->cipher_suites += 2; local->hw.wiphy->n_cipher_suites -= 2; } else { u32 *suites; int r, w = 0; /* Filter out WEP */ suites = kmemdup( local->hw.wiphy->cipher_suites, sizeof(u32) * local->hw.wiphy->n_cipher_suites, GFP_KERNEL); if (!suites) return -ENOMEM; for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { u32 suite = local->hw.wiphy->cipher_suites[r]; if (suite == WLAN_CIPHER_SUITE_WEP40 || suite == WLAN_CIPHER_SUITE_WEP104) continue; suites[w++] = suite; } local->hw.wiphy->cipher_suites = suites; local->hw.wiphy->n_cipher_suites = w; local->wiphy_ciphers_allocated = true; } } if (!local->ops->remain_on_channel) local->hw.wiphy->max_remain_on_channel_duration = 5000; if (local->ops->sched_scan_start) local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; result = wiphy_register(local->hw.wiphy); if (result < 0) goto fail_wiphy_register; /* * We use the number of queues for feature tests (QoS, HT) internally * so restrict them appropriately. */ if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; local->workqueue = alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0); if (!local->workqueue) { result = -ENOMEM; goto fail_workqueue; } /* * The hardware needs headroom for sending the frame, * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time. */ #ifndef __CHECKER__ BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != sizeof(struct ieee80211_tx_status_rtap_hdr)); #endif local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, sizeof(struct ieee80211_tx_status_rtap_hdr)); debugfs_hw_add(local); /* * if the driver doesn't specify a max listen interval we * use 5 which should be a safe default */ if (local->hw.max_listen_interval == 0) local->hw.max_listen_interval = 5; local->hw.conf.listen_interval = local->hw.max_listen_interval; local->dynamic_ps_forced_timeout = -1; result = ieee80211_wep_init(local); if (result < 0) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", result); rtnl_lock(); result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); if (result < 0) { wiphy_debug(local->hw.wiphy, "Failed to initialize rate control algorithm\n"); goto fail_rate; } /* add one default STA interface if supported */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { result = ieee80211_if_add(local, "wlan%d", NULL, NL80211_IFTYPE_STATION, NULL); if (result) wiphy_warn(local->hw.wiphy, "Failed to add default virtual iface\n"); } rtnl_unlock(); ieee80211_led_init(local); local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); if (result) { rtnl_lock(); goto fail_pm_qos; } #ifdef CONFIG_INET local->ifa_notifier.notifier_call = ieee80211_ifa_changed; result = register_inetaddr_notifier(&local->ifa_notifier); if (result) goto fail_ifa; #endif netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, local->hw.napi_weight); return 0; #ifdef CONFIG_INET fail_ifa: pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, &local->network_latency_notifier); rtnl_lock(); #endif fail_pm_qos: ieee80211_led_exit(local); ieee80211_remove_interfaces(local); fail_rate: rtnl_unlock(); ieee80211_wep_free(local); sta_info_stop(local); destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: if (local->wiphy_ciphers_allocated) kfree(local->hw.wiphy->cipher_suites); kfree(local->int_scan_req); return result; }
static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, bool amsdu) #endif { int rc = 0; struct mwl_priv *priv = hw->priv; struct mwl_ampdu_stream *stream; u8 *addr = sta->addr, idx; struct mwl_sta *sta_info; sta_info = mwl_dev_get_sta(sta); spin_lock_bh(&priv->stream_lock); stream = mwl_fwcmd_lookup_stream(hw, addr, tid); switch (action) { case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: if (!sta_info->is_ampdu_allowed) { wiphy_warn(hw->wiphy, "ampdu not allowed\n"); rc = -EPERM; break; } if (!stream) { stream = mwl_fwcmd_add_stream(hw, sta, tid); if (!stream) { wiphy_warn(hw->wiphy, "no stream found\n"); rc = -EPERM; break; } } spin_unlock_bh(&priv->stream_lock); rc = mwl_fwcmd_check_ba(hw, stream, vif); spin_lock_bh(&priv->stream_lock); if (rc) { mwl_fwcmd_remove_stream(hw, stream); wiphy_err(hw->wiphy, "ampdu start error code: %d\n", rc); rc = -EPERM; break; } stream->state = AMPDU_STREAM_IN_PROGRESS; *ssn = 0; ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: if (stream) { if (stream->state == AMPDU_STREAM_ACTIVE) { mwl_tx_del_ampdu_pkts(hw, sta, tid); idx = stream->idx; spin_unlock_bh(&priv->stream_lock); mwl_fwcmd_destroy_ba(hw, idx); spin_lock_bh(&priv->stream_lock); } mwl_fwcmd_remove_stream(hw, stream); ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); } else { rc = -EPERM; } break; case IEEE80211_AMPDU_TX_OPERATIONAL: if (stream) { if (WARN_ON(stream->state != AMPDU_STREAM_IN_PROGRESS)) { rc = -EPERM; break; } spin_unlock_bh(&priv->stream_lock); rc = mwl_fwcmd_create_ba(hw, stream, buf_size, vif); spin_lock_bh(&priv->stream_lock); if (!rc) { stream->state = AMPDU_STREAM_ACTIVE; } else { idx = stream->idx; spin_unlock_bh(&priv->stream_lock); mwl_fwcmd_destroy_ba(hw, idx); spin_lock_bh(&priv->stream_lock); mwl_fwcmd_remove_stream(hw, stream); wiphy_err(hw->wiphy, "ampdu operation error code: %d\n", rc); } } else { rc = -EPERM; } break; default: rc = -ENOTSUPP; break; } spin_unlock_bh(&priv->stream_lock); return rc; }
static int mwl_mac80211_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mwl_priv *priv = hw->priv; struct mwl_vif *mwl_vif; u32 macids_supported; int macid; switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: macids_supported = priv->ap_macids_supported; break; case NL80211_IFTYPE_STATION: macids_supported = priv->sta_macids_supported; break; default: return -EINVAL; } macid = ffs(macids_supported & ~priv->macids_used); if (!macid) { wiphy_warn(hw->wiphy, "no macid can be allocated\n"); return -EBUSY; } macid--; /* Setup driver private area. */ mwl_vif = mwl_dev_get_vif(vif); memset(mwl_vif, 0, sizeof(*mwl_vif)); mwl_vif->macid = macid; mwl_vif->seqno = 0; mwl_vif->is_hw_crypto_enabled = false; mwl_vif->beacon_info.valid = false; mwl_vif->iv16 = 1; mwl_vif->iv32 = 0; mwl_vif->keyidx = 0; switch (vif->type) { case NL80211_IFTYPE_AP: ether_addr_copy(mwl_vif->bssid, vif->addr); mwl_fwcmd_set_new_stn_add_self(hw, vif); break; case NL80211_IFTYPE_MESH_POINT: ether_addr_copy(mwl_vif->bssid, vif->addr); mwl_fwcmd_set_new_stn_add_self(hw, vif); break; case NL80211_IFTYPE_STATION: ether_addr_copy(mwl_vif->sta_mac, vif->addr); mwl_fwcmd_bss_start(hw, vif, true); mwl_fwcmd_set_infra_mode(hw, vif); mwl_fwcmd_set_mac_addr_client(hw, vif, vif->addr); break; default: return -EINVAL; } priv->macids_used |= 1 << mwl_vif->macid; spin_lock_bh(&priv->vif_lock); list_add_tail(&mwl_vif->list, &priv->vif_list); spin_unlock_bh(&priv->vif_lock); return 0; }
void cw1200_scan_work(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, scan.work); struct ieee80211_channel **it; struct wsm_scan scan = { .type = WSM_SCAN_TYPE_FOREGROUND, .flags = WSM_SCAN_FLAG_SPLIT_METHOD, }; bool first_run = (priv->scan.begin == priv->scan.curr && priv->scan.begin != priv->scan.end); int i; if (first_run) { /* Firmware gets crazy if scan request is sent * when STA is joined but not yet associated. * Force unjoin in this case. */ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) cw1200_join_timeout(&priv->join_timeout.work); } mutex_lock(&priv->conf_mutex); if (first_run) { if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.mode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.mode = WSM_PSM_PS; cw1200_set_pm(priv, &pm); } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { /* FW bug: driver has to restart p2p-dev mode * after scan */ cw1200_disable_listening(priv); } } if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { struct cfg80211_scan_info info = { .aborted = priv->scan.status ? 1 : 0, }; if (priv->scan.output_power != priv->output_power) wsm_set_output_power(priv, priv->output_power * 10); if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.mode & WSM_PSM_PS)) cw1200_set_pm(priv, &priv->powersave_mode); if (priv->scan.status < 0) wiphy_warn(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", priv->scan.status); else if (priv->scan.req) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan completed.\n"); else wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan canceled.\n"); priv->scan.req = NULL; cw1200_scan_restart_delayed(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); ieee80211_scan_completed(priv->hw, &info); up(&priv->scan.lock); return; } else { struct ieee80211_channel *first = *priv->scan.curr; for (it = priv->scan.curr + 1, i = 1; it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; ++it, ++i) { if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_NO_IR) break; if (!(first->flags & IEEE80211_CHAN_NO_IR) && (*it)->max_power != first->max_power) break; } scan.band = first->band; if (priv->scan.req->no_cck) scan.max_tx_rate = WSM_TRANSMIT_RATE_6; else scan.max_tx_rate = WSM_TRANSMIT_RATE_1; scan.num_probes = (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; scan.num_ssids = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.num_channels = it - priv->scan.curr; /* TODO: Is it optimal? */ scan.probe_delay = 100; /* It is not stated in WSM specification, however * FW team says that driver may not use FG scan * when joined. */ if (priv->join_status == CW1200_JOIN_STATUS_STA) { scan.type = WSM_SCAN_TYPE_BACKGROUND; scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } scan.ch = kcalloc(it - priv->scan.curr, sizeof(struct wsm_scan_ch), GFP_KERNEL); if (!scan.ch) { priv->scan.status = -ENOMEM; goto fail; } for (i = 0; i < scan.num_channels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { scan.ch[i].min_chan_time = 50; scan.ch[i].max_chan_time = 100; } else { scan.ch[i].min_chan_time = 10; scan.ch[i].max_chan_time = 25; } } if (!(first->flags & IEEE80211_CHAN_NO_IR) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; wsm_set_output_power(priv, priv->scan.output_power * 10); } priv->scan.status = cw1200_scan_start(priv, &scan); kfree(scan.ch); if (priv->scan.status) goto fail; priv->scan.curr = it; } mutex_unlock(&priv->conf_mutex); return; fail: priv->scan.curr = priv->scan.end; mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return; }
int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel) { int ret; struct mwifiex_bss_info bss_info; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; struct cfg80211_bss *bss = NULL; struct ieee80211_channel *chan; enum ieee80211_band band; memset(&bss_info, 0, sizeof(bss_info)); if (mwifiex_get_bss_info(priv, &bss_info)) return -1; ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET, &curr_chan); if (curr_chan == channel) { ret = 0; goto done; } dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", curr_chan, channel); if (!bss_info.media_connected) { ret = 0; goto done; } memset(&ssid_bssid, 0, ETH_ALEN); ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid); ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET, &channel); if (mwifiex_request_scan(priv, &bss_info.ssid)) { ret = -1; goto done; } band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); chan = __ieee80211_get_channel(priv->wdev->wiphy, ieee80211_channel_to_frequency(channel, band)); bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, bss_info.ssid.ssid, bss_info.ssid.ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!bss) wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", bss_info.bssid); ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); done: return ret; }