int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret; u32 rate; skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie, ie_len); if (!skb) { ret = -ENOMEM; goto out; } wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, role_id, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, role_id, CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); return ret; }
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct sk_buff *skb) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); int ret; u32 rate; if (!skb) skb = ieee80211_ap_probereq_get(wl->hw, vif); if (!skb) goto out; wl1271_debug(DEBUG_SCAN, "set ap probe request template"); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); if (wlvif->band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_CFG_PROBE_REQ_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_CFG_PROBE_REQ_5, skb->data, skb->len, 0, rate); if (ret < 0) wl1271_error("Unable to set ap probe request template."); out: return skb; }
int wl1271_cmd_build_null_data(struct wl1271 *wl) { struct sk_buff *skb = NULL; int size; void *ptr; int ret = -ENOMEM; if (wl->bss_type == BSS_TYPE_IBSS) { size = sizeof(struct wl12xx_null_data_template); ptr = NULL; } else { skb = ieee80211_nullfunc_get(wl->hw, wl->vif); if (!skb) goto out; size = skb->len; ptr = skb->data; } ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, WL1271_RATE_AUTOMATIC); out: dev_kfree_skb(skb); if (ret) wl1271_warning("cmd buld null data failed %d", ret); return ret; }
static int wl1271_ap_init_null_template(struct wl1271 *wl) { struct ieee80211_hdr_3addr *nullfunc; int ret; nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); if (!nullfunc) { ret = -ENOMEM; goto out; } nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_FROMDS); /* nullfunc->addr1 is filled by FW */ memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, sizeof(*nullfunc), 0, wl1271_tx_min_rate_get(wl)); out: kfree(nullfunc); return ret; }
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) { struct ieee80211_qos_hdr *qosnull; int ret; qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); if (!qosnull) { ret = -ENOMEM; goto out; } qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC | IEEE80211_FCTL_FROMDS); /* qosnull->addr1 is filled by FW */ memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, sizeof(*qosnull), 0, wl1271_tx_min_rate_get(wl)); out: kfree(qosnull); return ret; }
static int wl1271_ap_init_null_template(struct wl1271 *wl, struct ieee80211_vif *vif) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct ieee80211_hdr_3addr *nullfunc; int ret; u32 rate; nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); if (!nullfunc) { ret = -ENOMEM; goto out; } nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_FROMDS); /* nullfunc->addr1 is filled by FW */ memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_NULL_DATA, nullfunc, sizeof(*nullfunc), 0, rate); out: kfree(nullfunc); return ret; }
static int wl1271_ap_init_deauth_template(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_disconn_template *tmpl; int ret; u32 rate; tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); if (!tmpl) { ret = -ENOMEM; goto out; } tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_DEAUTH_AP, tmpl, sizeof(*tmpl), 0, rate); out: kfree(tmpl); return ret; }
int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, const u8 *ie0, size_t ie0_len, const u8 *ie1, size_t ie1_len, bool sched_scan) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret; u32 rate; u16 template_id_2_4 = wl->scan_templ_id_2_4; u16 template_id_5 = wl->scan_templ_id_5; wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); skb = ieee80211_probereq_get(wl->hw, vif->addr, ssid, ssid_len, ie0_len + ie1_len); if (!skb) { ret = -ENOMEM; goto out; } if (ie0_len) memcpy(skb_put(skb, ie0_len), ie0, ie0_len); if (ie1_len) memcpy(skb_put(skb, ie1_len), ie1, ie1_len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { template_id_2_4 = wl->sched_scan_templ_id_2_4; template_id_5 = wl->sched_scan_templ_id_5; } rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, role_id, template_id_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, role_id, template_id_5, skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); return ret; }
static int wl1271_ap_init_templates_config(struct wl1271 *wl) { int ret; /* * Put very large empty placeholders for all templates. These * reserve memory for later. */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, sizeof (struct wl12xx_probe_resp_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, sizeof (struct wl12xx_beacon_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, sizeof (struct wl12xx_disconn_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, sizeof (struct wl12xx_qos_null_data_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; return 0; }
static int wl1271_event_scan_complete(struct wl1271 *wl, struct event_mailbox *mbox) { int size = sizeof(struct wl12xx_probe_req_template); wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); if (wl->scanning) { if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); /* 2.4 GHz band scanned, scan 5 GHz band, pretend * to the wl1271_cmd_scan function that we are not * scanning as it checks that. */ wl->scanning = false; wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.active, wl->scan.high_prio, WL1271_SCAN_BAND_5_GHZ, wl->scan.probe_requests); } else { if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ) wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); else wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, NULL, size); mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); wl->scanning = false; } } return 0; }
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) { struct sk_buff *skb; int ret = 0; skb = ieee80211_pspoll_get(wl->hw, wl->vif); if (!skb) goto out; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, skb->len, 0, wl->basic_rate_set); out: dev_kfree_skb(skb); return ret; }
static int wl1271_init_templates_config(struct wl1271 *wl) { int ret; /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, sizeof(struct wl12xx_probe_req_template)); if (ret < 0) return ret; if (wl1271_11a_enabled()) { ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, NULL, sizeof(struct wl12xx_probe_req_template)); if (ret < 0) return ret; } ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template)); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, sizeof(struct wl12xx_ps_poll_template)); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, sizeof (struct wl12xx_qos_null_data_template)); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, sizeof (struct wl12xx_probe_resp_template)); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, sizeof (struct wl12xx_beacon_template)); if (ret < 0) return ret; return 0; }
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) { int ret; struct wl12xx_arp_rsp_template tmpl; struct ieee80211_hdr_3addr *hdr; struct arphdr *arp_hdr; memset(&tmpl, 0, sizeof(tmpl)); /* mac80211 header */ hdr = &tmpl.hdr; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_TODS); memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN); memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN); memset(hdr->addr3, 0xff, ETH_ALEN); /* llc layer */ memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); tmpl.llc_type = htons(ETH_P_ARP); /* arp header */ arp_hdr = &tmpl.arp_hdr; arp_hdr->ar_hrd = htons(ARPHRD_ETHER); arp_hdr->ar_pro = htons(ETH_P_IP); arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(ARPOP_REPLY); /* arp payload */ memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); tmpl.sender_ip = ip_addr; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, &tmpl, sizeof(tmpl), 0, wl->basic_rate); return ret; }
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl) { struct sk_buff *skb = NULL; int ret = -ENOMEM; skb = ieee80211_nullfunc_get(wl->hw, wl->vif); if (!skb) goto out; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, skb->data, skb->len, CMD_TEMPL_KLV_IDX_NULL_DATA, WL1271_RATE_AUTOMATIC); out: dev_kfree_skb(skb); if (ret) wl1271_warning("cmd build klv null data failed %d", ret); return ret; }
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb = NULL; int ret = -ENOMEM; skb = ieee80211_nullfunc_get(wl->hw, vif); if (!skb) goto out; ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, skb->data, skb->len, wlvif->sta.klv_template_id, wlvif->basic_rate); out: dev_kfree_skb(skb); if (ret) wl1271_warning("cmd build klv null data failed %d", ret); return ret; }
int wl1271_sta_init_templates_config(struct wl1271 *wl) { int ret, i; /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, sizeof(struct wl12xx_ps_poll_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, sizeof (struct wl12xx_qos_null_data_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, sizeof (struct wl12xx_probe_resp_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, sizeof (struct wl12xx_beacon_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL, sizeof (struct wl12xx_arp_rsp_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, WL1271_CMD_TEMPL_MAX_SIZE, i, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; } return 0; }
int wl1271_init_templates_config(struct wl1271 *wl) { int ret, i; size_t max_size; /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_CFG_PROBE_REQ_5, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_APP_PROBE_REQ_2_4, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_APP_PROBE_REQ_5, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_PS_POLL, NULL, sizeof(struct wl12xx_ps_poll_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_QOS_NULL_DATA, NULL, sizeof (struct ieee80211_qos_hdr), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_PROBE_RESPONSE, NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_BEACON, NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; max_size = sizeof(struct wl12xx_arp_rsp_template) + WL1271_EXTRA_SPACE_MAX; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_ARP_RSP, NULL, max_size, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; /* * Put very large empty placeholders for all templates. These * reserve memory for later. */ ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_AP_BEACON, NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_DEAUTH_AP, NULL, sizeof (struct wl12xx_disconn_template), 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_KLV, NULL, sizeof(struct ieee80211_qos_hdr), i, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; } return 0; }
static int wl1271_op_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct wl1271 *wl = hw->priv; struct sk_buff *beacon; int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM", conf->bssid); wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, conf->ssid_len); mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; memcpy(wl->bssid, conf->bssid, ETH_ALEN); ret = wl1271_cmd_build_null_data(wl); if (ret < 0) goto out_sleep; wl->ssid_len = conf->ssid_len; if (wl->ssid_len) memcpy(wl->ssid, conf->ssid, wl->ssid_len); if (wl->bss_type != BSS_TYPE_IBSS) { ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1); if (ret < 0) goto out_sleep; } if (conf->changed & IEEE80211_IFCC_BEACON) { beacon = ieee80211_beacon_get(hw, vif); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, beacon->data, beacon->len); if (ret < 0) { dev_kfree_skb(beacon); goto out_sleep; } ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, beacon->data, beacon->len); dev_kfree_skb(beacon); if (ret < 0) goto out_sleep; ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; } out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); return ret; }
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret, extra = 0; u16 fc; struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; struct wl12xx_arp_rsp_template *tmpl; struct ieee80211_hdr_3addr *hdr; struct arphdr *arp_hdr; skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + WL1271_EXTRA_SPACE_MAX); if (!skb) { wl1271_error("failed to allocate buffer for arp rsp template"); return -ENOMEM; } skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); memset(tmpl, 0, sizeof(*tmpl)); /* llc layer */ memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); tmpl->llc_type = cpu_to_be16(ETH_P_ARP); /* arp header */ arp_hdr = &tmpl->arp_hdr; arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); tmpl->sender_ip = wlvif->ip_addr; /* encryption space */ switch (wlvif->encryption_type) { case KEY_TKIP: if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) extra = WL1271_EXTRA_SPACE_TKIP; break; case KEY_AES: extra = WL1271_EXTRA_SPACE_AES; break; case KEY_NONE: case KEY_WEP: case KEY_GEM: extra = 0; break; default: wl1271_warning("Unknown encryption type: %d", wlvif->encryption_type); ret = -EINVAL; goto out; } if (extra) { u8 *space = skb_push(skb, extra); memset(space, 0, extra); } /* QoS header - BE */ if (wlvif->sta.qos) memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); /* mac80211 header */ hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; if (wlvif->sta.qos) fc |= IEEE80211_STYPE_QOS_DATA; else fc |= IEEE80211_STYPE_DATA; if (wlvif->encryption_type != KEY_NONE) fc |= IEEE80211_FCTL_PROTECTED; hdr->frame_control = cpu_to_le16(fc); memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); memcpy(hdr->addr2, vif->addr, ETH_ALEN); memset(hdr->addr3, 0xff, ETH_ALEN); ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, skb->data, skb->len, 0, wlvif->basic_rate); out: dev_kfree_skb(skb); return ret; }