diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-02-22 14:44:50 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-02-22 14:44:50 -0500 |
commit | 8715d941b2fa8591474e7d0dad66589fce1892d2 (patch) | |
tree | ec228ec158bb5b4424f898d336279c29de4cf81f /drivers/net/wireless/wl12xx/cmd.c | |
parent | ca994a36f585432458ead9133fcfe05440edbb7b (diff) | |
parent | 51c4ed95a857ded6017537fd53fa00db64908954 (diff) |
Merge branch 'for-linville' of git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
Diffstat (limited to 'drivers/net/wireless/wl12xx/cmd.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 143 |
1 files changed, 105 insertions, 38 deletions
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 25990bd38be6..b776d9d5efe8 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c | |||
@@ -566,7 +566,7 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, | |||
566 | goto out_free; | 566 | goto out_free; |
567 | } | 567 | } |
568 | 568 | ||
569 | ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); | 569 | ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); |
570 | if (ret < 0) { | 570 | if (ret < 0) { |
571 | wl1271_error("cmd role stop dev event completion error"); | 571 | wl1271_error("cmd role stop dev event completion error"); |
572 | goto out_free; | 572 | goto out_free; |
@@ -715,6 +715,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
715 | cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); | 715 | cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); |
716 | cmd->ap.dtim_interval = bss_conf->dtim_period; | 716 | cmd->ap.dtim_interval = bss_conf->dtim_period; |
717 | cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; | 717 | cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; |
718 | /* FIXME: Change when adding DFS */ | ||
719 | cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ | ||
718 | cmd->channel = wlvif->channel; | 720 | cmd->channel = wlvif->channel; |
719 | 721 | ||
720 | if (!bss_conf->hidden_ssid) { | 722 | if (!bss_conf->hidden_ssid) { |
@@ -994,7 +996,7 @@ out: | |||
994 | } | 996 | } |
995 | 997 | ||
996 | int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 998 | int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
997 | u8 ps_mode) | 999 | u8 ps_mode, u16 auto_ps_timeout) |
998 | { | 1000 | { |
999 | struct wl1271_cmd_ps_params *ps_params = NULL; | 1001 | struct wl1271_cmd_ps_params *ps_params = NULL; |
1000 | int ret = 0; | 1002 | int ret = 0; |
@@ -1009,6 +1011,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1009 | 1011 | ||
1010 | ps_params->role_id = wlvif->role_id; | 1012 | ps_params->role_id = wlvif->role_id; |
1011 | ps_params->ps_mode = ps_mode; | 1013 | ps_params->ps_mode = ps_mode; |
1014 | ps_params->auto_ps_timeout = auto_ps_timeout; | ||
1012 | 1015 | ||
1013 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | 1016 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, |
1014 | sizeof(*ps_params), 0); | 1017 | sizeof(*ps_params), 0); |
@@ -1022,13 +1025,15 @@ out: | |||
1022 | return ret; | 1025 | return ret; |
1023 | } | 1026 | } |
1024 | 1027 | ||
1025 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | 1028 | int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, |
1026 | void *buf, size_t buf_len, int index, u32 rates) | 1029 | u16 template_id, void *buf, size_t buf_len, |
1030 | int index, u32 rates) | ||
1027 | { | 1031 | { |
1028 | struct wl1271_cmd_template_set *cmd; | 1032 | struct wl1271_cmd_template_set *cmd; |
1029 | int ret = 0; | 1033 | int ret = 0; |
1030 | 1034 | ||
1031 | wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); | 1035 | wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)", |
1036 | template_id, role_id); | ||
1032 | 1037 | ||
1033 | WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); | 1038 | WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); |
1034 | buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); | 1039 | buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); |
@@ -1039,6 +1044,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | |||
1039 | goto out; | 1044 | goto out; |
1040 | } | 1045 | } |
1041 | 1046 | ||
1047 | /* during initialization wlvif is NULL */ | ||
1048 | cmd->role_id = role_id; | ||
1042 | cmd->len = cpu_to_le16(buf_len); | 1049 | cmd->len = cpu_to_le16(buf_len); |
1043 | cmd->template_type = template_id; | 1050 | cmd->template_type = template_id; |
1044 | cmd->enabled_rates = cpu_to_le32(rates); | 1051 | cmd->enabled_rates = cpu_to_le32(rates); |
@@ -1082,7 +1089,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
1082 | ptr = skb->data; | 1089 | ptr = skb->data; |
1083 | } | 1090 | } |
1084 | 1091 | ||
1085 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, | 1092 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, |
1093 | CMD_TEMPL_NULL_DATA, ptr, size, 0, | ||
1086 | wlvif->basic_rate); | 1094 | wlvif->basic_rate); |
1087 | 1095 | ||
1088 | out: | 1096 | out: |
@@ -1105,7 +1113,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, | |||
1105 | if (!skb) | 1113 | if (!skb) |
1106 | goto out; | 1114 | goto out; |
1107 | 1115 | ||
1108 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, | 1116 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, |
1109 | skb->data, skb->len, | 1117 | skb->data, skb->len, |
1110 | CMD_TEMPL_KLV_IDX_NULL_DATA, | 1118 | CMD_TEMPL_KLV_IDX_NULL_DATA, |
1111 | wlvif->basic_rate); | 1119 | wlvif->basic_rate); |
@@ -1130,7 +1138,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1130 | if (!skb) | 1138 | if (!skb) |
1131 | goto out; | 1139 | goto out; |
1132 | 1140 | ||
1133 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, | 1141 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, |
1142 | CMD_TEMPL_PS_POLL, skb->data, | ||
1134 | skb->len, 0, wlvif->basic_rate_set); | 1143 | skb->len, 0, wlvif->basic_rate_set); |
1135 | 1144 | ||
1136 | out: | 1145 | out: |
@@ -1138,9 +1147,10 @@ out: | |||
1138 | return ret; | 1147 | return ret; |
1139 | } | 1148 | } |
1140 | 1149 | ||
1141 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 1150 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1151 | u8 role_id, u8 band, | ||
1142 | const u8 *ssid, size_t ssid_len, | 1152 | const u8 *ssid, size_t ssid_len, |
1143 | const u8 *ie, size_t ie_len, u8 band) | 1153 | const u8 *ie, size_t ie_len) |
1144 | { | 1154 | { |
1145 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 1155 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
1146 | struct sk_buff *skb; | 1156 | struct sk_buff *skb; |
@@ -1158,10 +1168,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1158 | 1168 | ||
1159 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | 1169 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); |
1160 | if (band == IEEE80211_BAND_2GHZ) | 1170 | if (band == IEEE80211_BAND_2GHZ) |
1161 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | 1171 | ret = wl1271_cmd_template_set(wl, role_id, |
1172 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
1162 | skb->data, skb->len, 0, rate); | 1173 | skb->data, skb->len, 0, rate); |
1163 | else | 1174 | else |
1164 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | 1175 | ret = wl1271_cmd_template_set(wl, role_id, |
1176 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
1165 | skb->data, skb->len, 0, rate); | 1177 | skb->data, skb->len, 0, rate); |
1166 | 1178 | ||
1167 | out: | 1179 | out: |
@@ -1186,10 +1198,12 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | |||
1186 | 1198 | ||
1187 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); | 1199 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); |
1188 | if (wlvif->band == IEEE80211_BAND_2GHZ) | 1200 | if (wlvif->band == IEEE80211_BAND_2GHZ) |
1189 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | 1201 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, |
1202 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
1190 | skb->data, skb->len, 0, rate); | 1203 | skb->data, skb->len, 0, rate); |
1191 | else | 1204 | else |
1192 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | 1205 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, |
1206 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
1193 | skb->data, skb->len, 0, rate); | 1207 | skb->data, skb->len, 0, rate); |
1194 | 1208 | ||
1195 | if (ret < 0) | 1209 | if (ret < 0) |
@@ -1199,32 +1213,34 @@ out: | |||
1199 | return skb; | 1213 | return skb; |
1200 | } | 1214 | } |
1201 | 1215 | ||
1202 | int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 1216 | int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
1203 | __be32 ip_addr) | ||
1204 | { | 1217 | { |
1205 | int ret; | 1218 | int ret, extra; |
1219 | u16 fc; | ||
1206 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 1220 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
1207 | struct wl12xx_arp_rsp_template tmpl; | 1221 | struct sk_buff *skb; |
1222 | struct wl12xx_arp_rsp_template *tmpl; | ||
1208 | struct ieee80211_hdr_3addr *hdr; | 1223 | struct ieee80211_hdr_3addr *hdr; |
1209 | struct arphdr *arp_hdr; | 1224 | struct arphdr *arp_hdr; |
1210 | 1225 | ||
1211 | memset(&tmpl, 0, sizeof(tmpl)); | 1226 | skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + |
1227 | WL1271_EXTRA_SPACE_MAX); | ||
1228 | if (!skb) { | ||
1229 | wl1271_error("failed to allocate buffer for arp rsp template"); | ||
1230 | return -ENOMEM; | ||
1231 | } | ||
1212 | 1232 | ||
1213 | /* mac80211 header */ | 1233 | skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); |
1214 | hdr = &tmpl.hdr; | 1234 | |
1215 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | 1235 | tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); |
1216 | IEEE80211_STYPE_DATA | | 1236 | memset(tmpl, 0, sizeof(tmpl)); |
1217 | IEEE80211_FCTL_TODS); | ||
1218 | memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); | ||
1219 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||
1220 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
1221 | 1237 | ||
1222 | /* llc layer */ | 1238 | /* llc layer */ |
1223 | memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); | 1239 | memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); |
1224 | tmpl.llc_type = cpu_to_be16(ETH_P_ARP); | 1240 | tmpl->llc_type = cpu_to_be16(ETH_P_ARP); |
1225 | 1241 | ||
1226 | /* arp header */ | 1242 | /* arp header */ |
1227 | arp_hdr = &tmpl.arp_hdr; | 1243 | arp_hdr = &tmpl->arp_hdr; |
1228 | arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); | 1244 | arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); |
1229 | arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); | 1245 | arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); |
1230 | arp_hdr->ar_hln = ETH_ALEN; | 1246 | arp_hdr->ar_hln = ETH_ALEN; |
@@ -1232,13 +1248,59 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1232 | arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); | 1248 | arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); |
1233 | 1249 | ||
1234 | /* arp payload */ | 1250 | /* arp payload */ |
1235 | memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); | 1251 | memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); |
1236 | tmpl.sender_ip = ip_addr; | 1252 | tmpl->sender_ip = wlvif->ip_addr; |
1237 | 1253 | ||
1238 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, | 1254 | /* encryption space */ |
1239 | &tmpl, sizeof(tmpl), 0, | 1255 | switch (wlvif->encryption_type) { |
1240 | wlvif->basic_rate); | 1256 | case KEY_TKIP: |
1257 | extra = WL1271_EXTRA_SPACE_TKIP; | ||
1258 | break; | ||
1259 | case KEY_AES: | ||
1260 | extra = WL1271_EXTRA_SPACE_AES; | ||
1261 | break; | ||
1262 | case KEY_NONE: | ||
1263 | case KEY_WEP: | ||
1264 | case KEY_GEM: | ||
1265 | extra = 0; | ||
1266 | break; | ||
1267 | default: | ||
1268 | wl1271_warning("Unknown encryption type: %d", | ||
1269 | wlvif->encryption_type); | ||
1270 | ret = -EINVAL; | ||
1271 | goto out; | ||
1272 | } | ||
1273 | |||
1274 | if (extra) { | ||
1275 | u8 *space = skb_push(skb, extra); | ||
1276 | memset(space, 0, extra); | ||
1277 | } | ||
1278 | |||
1279 | /* QoS header - BE */ | ||
1280 | if (wlvif->sta.qos) | ||
1281 | memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); | ||
1241 | 1282 | ||
1283 | /* mac80211 header */ | ||
1284 | hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); | ||
1285 | memset(hdr, 0, sizeof(hdr)); | ||
1286 | fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; | ||
1287 | if (wlvif->sta.qos) | ||
1288 | fc |= IEEE80211_STYPE_QOS_DATA; | ||
1289 | else | ||
1290 | fc |= IEEE80211_STYPE_DATA; | ||
1291 | if (wlvif->encryption_type != KEY_NONE) | ||
1292 | fc |= IEEE80211_FCTL_PROTECTED; | ||
1293 | |||
1294 | hdr->frame_control = cpu_to_le16(fc); | ||
1295 | memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); | ||
1296 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||
1297 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
1298 | |||
1299 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, | ||
1300 | skb->data, skb->len, 0, | ||
1301 | wlvif->basic_rate); | ||
1302 | out: | ||
1303 | dev_kfree_skb(skb); | ||
1242 | return ret; | 1304 | return ret; |
1243 | } | 1305 | } |
1244 | 1306 | ||
@@ -1260,7 +1322,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) | |||
1260 | /* FIXME: not sure what priority to use here */ | 1322 | /* FIXME: not sure what priority to use here */ |
1261 | template.qos_ctrl = cpu_to_le16(0); | 1323 | template.qos_ctrl = cpu_to_le16(0); |
1262 | 1324 | ||
1263 | return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, | 1325 | return wl1271_cmd_template_set(wl, wlvif->role_id, |
1326 | CMD_TEMPL_QOS_NULL_DATA, &template, | ||
1264 | sizeof(template), 0, | 1327 | sizeof(template), 0, |
1265 | wlvif->basic_rate); | 1328 | wlvif->basic_rate); |
1266 | } | 1329 | } |
@@ -1744,6 +1807,7 @@ out: | |||
1744 | } | 1807 | } |
1745 | 1808 | ||
1746 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | 1809 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, |
1810 | struct wl12xx_vif *wlvif, | ||
1747 | struct ieee80211_channel_switch *ch_switch) | 1811 | struct ieee80211_channel_switch *ch_switch) |
1748 | { | 1812 | { |
1749 | struct wl12xx_cmd_channel_switch *cmd; | 1813 | struct wl12xx_cmd_channel_switch *cmd; |
@@ -1757,10 +1821,13 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl, | |||
1757 | goto out; | 1821 | goto out; |
1758 | } | 1822 | } |
1759 | 1823 | ||
1824 | cmd->role_id = wlvif->role_id; | ||
1760 | cmd->channel = ch_switch->channel->hw_value; | 1825 | cmd->channel = ch_switch->channel->hw_value; |
1761 | cmd->switch_time = ch_switch->count; | 1826 | cmd->switch_time = ch_switch->count; |
1762 | cmd->tx_suspend = ch_switch->block_tx; | 1827 | cmd->stop_tx = ch_switch->block_tx; |
1763 | cmd->flush = 0; /* this value is ignored by the FW */ | 1828 | |
1829 | /* FIXME: control from mac80211 in the future */ | ||
1830 | cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ | ||
1764 | 1831 | ||
1765 | ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); | 1832 | ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); |
1766 | if (ret < 0) { | 1833 | if (ret < 0) { |