aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/cmd.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-02-22 14:44:50 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-02-22 14:44:50 -0500
commit8715d941b2fa8591474e7d0dad66589fce1892d2 (patch)
treeec228ec158bb5b4424f898d336279c29de4cf81f /drivers/net/wireless/wl12xx/cmd.c
parentca994a36f585432458ead9133fcfe05440edbb7b (diff)
parent51c4ed95a857ded6017537fd53fa00db64908954 (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.c143
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
996int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, 998int 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
1025int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, 1028int 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
1088out: 1096out:
@@ -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
1136out: 1145out:
@@ -1138,9 +1147,10 @@ out:
1138 return ret; 1147 return ret;
1139} 1148}
1140 1149
1141int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1150int 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
1167out: 1179out:
@@ -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
1202int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1216int 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);
1302out:
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
1746int wl12xx_cmd_channel_switch(struct wl1271 *wl, 1809int 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) {