diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-01-03 10:52:18 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-04 14:46:14 -0500 |
commit | cc72128750700d01c31f583a355c5f8f809498bb (patch) | |
tree | aaa811a3d9c704b9bf94707e2043fe700bb2b3be /drivers | |
parent | a8851d10aadb46b25db4459aa0d1150c957d2bc1 (diff) |
ath9k_htc: Fix packet injection
To inject a packet in monitor mode, a dummy station has
to be associated with the monitor interface in the target.
Failing to do this would result in a firmware crash on the device.
Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 72 |
1 files changed, 64 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ad3dd3186ad2..845b4c938d16 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -235,16 +235,38 @@ err: | |||
235 | return ret; | 235 | return ret; |
236 | } | 236 | } |
237 | 237 | ||
238 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | ||
239 | { | ||
240 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
241 | struct ath9k_htc_target_vif hvif; | ||
242 | int ret = 0; | ||
243 | u8 cmd_rsp; | ||
244 | |||
245 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
246 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
247 | hvif.index = 0; /* Should do for now */ | ||
248 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
249 | priv->nvifs--; | ||
250 | } | ||
251 | |||
238 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | 252 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) |
239 | { | 253 | { |
240 | struct ath_common *common = ath9k_hw_common(priv->ah); | 254 | struct ath_common *common = ath9k_hw_common(priv->ah); |
241 | struct ath9k_htc_target_vif hvif; | 255 | struct ath9k_htc_target_vif hvif; |
256 | struct ath9k_htc_target_sta tsta; | ||
242 | int ret = 0; | 257 | int ret = 0; |
243 | u8 cmd_rsp; | 258 | u8 cmd_rsp; |
244 | 259 | ||
245 | if (priv->nvifs > 0) | 260 | if (priv->nvifs > 0) |
246 | return -ENOBUFS; | 261 | return -ENOBUFS; |
247 | 262 | ||
263 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | ||
264 | return -ENOBUFS; | ||
265 | |||
266 | /* | ||
267 | * Add an interface. | ||
268 | */ | ||
269 | |||
248 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 270 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
249 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 271 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
250 | 272 | ||
@@ -257,23 +279,57 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | |||
257 | return ret; | 279 | return ret; |
258 | 280 | ||
259 | priv->nvifs++; | 281 | priv->nvifs++; |
282 | |||
283 | /* | ||
284 | * Associate a station with the interface for packet injection. | ||
285 | */ | ||
286 | |||
287 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | ||
288 | |||
289 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); | ||
290 | |||
291 | tsta.is_vif_sta = 1; | ||
292 | tsta.sta_index = priv->nstations; | ||
293 | tsta.vif_index = hvif.index; | ||
294 | tsta.maxampdu = 0xffff; | ||
295 | |||
296 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); | ||
297 | if (ret) { | ||
298 | ath_err(common, "Unable to add station entry for monitor mode\n"); | ||
299 | goto err_vif; | ||
300 | } | ||
301 | |||
302 | priv->nstations++; | ||
303 | |||
260 | return 0; | 304 | return 0; |
305 | |||
306 | err_vif: | ||
307 | /* | ||
308 | * Remove the interface from the target. | ||
309 | */ | ||
310 | __ath9k_htc_remove_monitor_interface(priv); | ||
311 | return ret; | ||
261 | } | 312 | } |
262 | 313 | ||
263 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | 314 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) |
264 | { | 315 | { |
265 | struct ath_common *common = ath9k_hw_common(priv->ah); | 316 | struct ath_common *common = ath9k_hw_common(priv->ah); |
266 | struct ath9k_htc_target_vif hvif; | ||
267 | int ret = 0; | 317 | int ret = 0; |
268 | u8 cmd_rsp; | 318 | u8 cmd_rsp, sta_idx; |
269 | 319 | ||
270 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 320 | __ath9k_htc_remove_monitor_interface(priv); |
271 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
272 | hvif.index = 0; /* Should do for now */ | ||
273 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
274 | priv->nvifs--; | ||
275 | 321 | ||
276 | return ret; | 322 | sta_idx = 0; /* Only single interface, for now */ |
323 | |||
324 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | ||
325 | if (ret) { | ||
326 | ath_err(common, "Unable to remove station entry for monitor mode\n"); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | priv->nstations--; | ||
331 | |||
332 | return 0; | ||
277 | } | 333 | } |
278 | 334 | ||
279 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | 335 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, |