diff options
author | David Kilroy <kilroyd@googlemail.com> | 2010-05-04 17:54:41 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-05-07 14:55:49 -0400 |
commit | bac6fafd4d6a0af26aeb37277a39607f7ce0be77 (patch) | |
tree | 4535874fa3b58249cf4936bb1656fb5759ed28a2 /drivers/net/wireless/orinoco | |
parent | 3ef83d745bf5220bef3a0fd11b96eb9ac64c8e8e (diff) |
orinoco: refactor xmit path
... so orinoco_usb can share some common functionality.
Handle 802.2 encapsulation and MIC calculation in that function.
The 802.3 header is prepended to the SKB. The calculated MIC is written
to a specified buffer. Also modify the transmit control word that will
be passed onto the hardware to specify whether the MIC is present, and
the key used.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/orinoco')
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 169 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/orinoco.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/orinoco_usb.c | 91 |
3 files changed, 155 insertions, 111 deletions
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 7c9faa4c079..86f268cd89e 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -339,18 +339,109 @@ EXPORT_SYMBOL(orinoco_change_mtu); | |||
339 | /* Tx path */ | 339 | /* Tx path */ |
340 | /********************************************************************/ | 340 | /********************************************************************/ |
341 | 341 | ||
342 | /* Add encapsulation and MIC to the existing SKB. | ||
343 | * The main xmit routine will then send the whole lot to the card. | ||
344 | * Need 8 bytes headroom | ||
345 | * Need 8 bytes tailroom | ||
346 | * | ||
347 | * With encapsulated ethernet II frame | ||
348 | * -------- | ||
349 | * 803.3 header (14 bytes) | ||
350 | * dst[6] | ||
351 | * -------- src[6] | ||
352 | * 803.3 header (14 bytes) len[2] | ||
353 | * dst[6] 803.2 header (8 bytes) | ||
354 | * src[6] encaps[6] | ||
355 | * len[2] <- leave alone -> len[2] | ||
356 | * -------- -------- <-- 0 | ||
357 | * Payload Payload | ||
358 | * ... ... | ||
359 | * | ||
360 | * -------- -------- | ||
361 | * MIC (8 bytes) | ||
362 | * -------- | ||
363 | * | ||
364 | * returns 0 on success, -ENOMEM on error. | ||
365 | */ | ||
366 | int orinoco_process_xmit_skb(struct sk_buff *skb, | ||
367 | struct net_device *dev, | ||
368 | struct orinoco_private *priv, | ||
369 | int *tx_control, | ||
370 | u8 *mic_buf) | ||
371 | { | ||
372 | struct orinoco_tkip_key *key; | ||
373 | struct ethhdr *eh; | ||
374 | int do_mic; | ||
375 | |||
376 | key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; | ||
377 | |||
378 | do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && | ||
379 | (key != NULL)); | ||
380 | |||
381 | if (do_mic) | ||
382 | *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | | ||
383 | HERMES_TXCTRL_MIC; | ||
384 | |||
385 | eh = (struct ethhdr *)skb->data; | ||
386 | |||
387 | /* Encapsulate Ethernet-II frames */ | ||
388 | if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ | ||
389 | struct header_struct { | ||
390 | struct ethhdr eth; /* 802.3 header */ | ||
391 | u8 encap[6]; /* 802.2 header */ | ||
392 | } __attribute__ ((packed)) hdr; | ||
393 | int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN); | ||
394 | |||
395 | if (skb_headroom(skb) < ENCAPS_OVERHEAD) { | ||
396 | if (net_ratelimit()) | ||
397 | printk(KERN_ERR | ||
398 | "%s: Not enough headroom for 802.2 headers %d\n", | ||
399 | dev->name, skb_headroom(skb)); | ||
400 | return -ENOMEM; | ||
401 | } | ||
402 | |||
403 | /* Fill in new header */ | ||
404 | memcpy(&hdr.eth, eh, 2 * ETH_ALEN); | ||
405 | hdr.eth.h_proto = htons(len); | ||
406 | memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); | ||
407 | |||
408 | /* Make room for the new header, and copy it in */ | ||
409 | eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD); | ||
410 | memcpy(eh, &hdr, sizeof(hdr)); | ||
411 | } | ||
412 | |||
413 | /* Calculate Michael MIC */ | ||
414 | if (do_mic) { | ||
415 | size_t len = skb->len - ETH_HLEN; | ||
416 | u8 *mic = &mic_buf[0]; | ||
417 | |||
418 | /* Have to write to an even address, so copy the spare | ||
419 | * byte across */ | ||
420 | if (skb->len % 2) { | ||
421 | *mic = skb->data[skb->len - 1]; | ||
422 | mic++; | ||
423 | } | ||
424 | |||
425 | orinoco_mic(priv->tx_tfm_mic, key->tx_mic, | ||
426 | eh->h_dest, eh->h_source, 0 /* priority */, | ||
427 | skb->data + ETH_HLEN, | ||
428 | len, mic); | ||
429 | } | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | EXPORT_SYMBOL(orinoco_process_xmit_skb); | ||
434 | |||
342 | static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | 435 | static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) |
343 | { | 436 | { |
344 | struct orinoco_private *priv = ndev_priv(dev); | 437 | struct orinoco_private *priv = ndev_priv(dev); |
345 | struct net_device_stats *stats = &priv->stats; | 438 | struct net_device_stats *stats = &priv->stats; |
346 | struct orinoco_tkip_key *key; | ||
347 | hermes_t *hw = &priv->hw; | 439 | hermes_t *hw = &priv->hw; |
348 | int err = 0; | 440 | int err = 0; |
349 | u16 txfid = priv->txfid; | 441 | u16 txfid = priv->txfid; |
350 | struct ethhdr *eh; | ||
351 | int tx_control; | 442 | int tx_control; |
352 | unsigned long flags; | 443 | unsigned long flags; |
353 | int do_mic; | 444 | u8 mic_buf[MICHAEL_MIC_LEN+1]; |
354 | 445 | ||
355 | if (!netif_running(dev)) { | 446 | if (!netif_running(dev)) { |
356 | printk(KERN_ERR "%s: Tx on stopped device!\n", | 447 | printk(KERN_ERR "%s: Tx on stopped device!\n", |
@@ -382,16 +473,12 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
382 | if (skb->len < ETH_HLEN) | 473 | if (skb->len < ETH_HLEN) |
383 | goto drop; | 474 | goto drop; |
384 | 475 | ||
385 | key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; | ||
386 | |||
387 | do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && | ||
388 | (key != NULL)); | ||
389 | |||
390 | tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; | 476 | tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; |
391 | 477 | ||
392 | if (do_mic) | 478 | err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, |
393 | tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | | 479 | &mic_buf[0]); |
394 | HERMES_TXCTRL_MIC; | 480 | if (err) |
481 | goto drop; | ||
395 | 482 | ||
396 | if (priv->has_alt_txcntl) { | 483 | if (priv->has_alt_txcntl) { |
397 | /* WPA enabled firmwares have tx_cntl at the end of | 484 | /* WPA enabled firmwares have tx_cntl at the end of |
@@ -434,34 +521,6 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
434 | HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); | 521 | HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); |
435 | } | 522 | } |
436 | 523 | ||
437 | eh = (struct ethhdr *)skb->data; | ||
438 | |||
439 | /* Encapsulate Ethernet-II frames */ | ||
440 | if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ | ||
441 | struct header_struct { | ||
442 | struct ethhdr eth; /* 802.3 header */ | ||
443 | u8 encap[6]; /* 802.2 header */ | ||
444 | } __attribute__ ((packed)) hdr; | ||
445 | |||
446 | /* Strip destination and source from the data */ | ||
447 | skb_pull(skb, 2 * ETH_ALEN); | ||
448 | |||
449 | /* And move them to a separate header */ | ||
450 | memcpy(&hdr.eth, eh, 2 * ETH_ALEN); | ||
451 | hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len); | ||
452 | memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); | ||
453 | |||
454 | /* Insert the SNAP header */ | ||
455 | if (skb_headroom(skb) < sizeof(hdr)) { | ||
456 | printk(KERN_ERR | ||
457 | "%s: Not enough headroom for 802.2 headers %d\n", | ||
458 | dev->name, skb_headroom(skb)); | ||
459 | goto drop; | ||
460 | } | ||
461 | eh = (struct ethhdr *) skb_push(skb, sizeof(hdr)); | ||
462 | memcpy(eh, &hdr, sizeof(hdr)); | ||
463 | } | ||
464 | |||
465 | err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len, | 524 | err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len, |
466 | txfid, HERMES_802_3_OFFSET); | 525 | txfid, HERMES_802_3_OFFSET); |
467 | if (err) { | 526 | if (err) { |
@@ -470,32 +529,16 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
470 | goto busy; | 529 | goto busy; |
471 | } | 530 | } |
472 | 531 | ||
473 | /* Calculate Michael MIC */ | 532 | if (tx_control & HERMES_TXCTRL_MIC) { |
474 | if (do_mic) { | 533 | size_t offset = HERMES_802_3_OFFSET + skb->len; |
475 | u8 mic_buf[MICHAEL_MIC_LEN + 1]; | 534 | size_t len = MICHAEL_MIC_LEN; |
476 | u8 *mic; | ||
477 | size_t offset; | ||
478 | size_t len; | ||
479 | 535 | ||
480 | if (skb->len % 2) { | 536 | if (offset % 2) { |
481 | /* MIC start is on an odd boundary */ | 537 | offset--; |
482 | mic_buf[0] = skb->data[skb->len - 1]; | 538 | len++; |
483 | mic = &mic_buf[1]; | ||
484 | offset = skb->len - 1; | ||
485 | len = MICHAEL_MIC_LEN + 1; | ||
486 | } else { | ||
487 | mic = &mic_buf[0]; | ||
488 | offset = skb->len; | ||
489 | len = MICHAEL_MIC_LEN; | ||
490 | } | 539 | } |
491 | |||
492 | orinoco_mic(priv->tx_tfm_mic, key->tx_mic, | ||
493 | eh->h_dest, eh->h_source, 0 /* priority */, | ||
494 | skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); | ||
495 | |||
496 | /* Write the MIC */ | ||
497 | err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len, | 540 | err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len, |
498 | txfid, HERMES_802_3_OFFSET + offset); | 541 | txfid, offset); |
499 | if (err) { | 542 | if (err) { |
500 | printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", | 543 | printk(KERN_ERR "%s: Error %d writing MIC to BAP\n", |
501 | dev->name, err); | 544 | dev->name, err); |
@@ -2234,7 +2277,7 @@ int orinoco_if_add(struct orinoco_private *priv, | |||
2234 | /* we use the default eth_mac_addr for setting the MAC addr */ | 2277 | /* we use the default eth_mac_addr for setting the MAC addr */ |
2235 | 2278 | ||
2236 | /* Reserve space in skb for the SNAP header */ | 2279 | /* Reserve space in skb for the SNAP header */ |
2237 | dev->hard_header_len += ENCAPS_OVERHEAD; | 2280 | dev->needed_headroom = ENCAPS_OVERHEAD; |
2238 | 2281 | ||
2239 | netif_carrier_off(dev); | 2282 | netif_carrier_off(dev); |
2240 | 2283 | ||
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index e9f415a56d4..a6da86e0a70 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h | |||
@@ -200,6 +200,12 @@ extern irqreturn_t orinoco_interrupt(int irq, void *dev_id); | |||
200 | extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); | 200 | extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); |
201 | extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); | 201 | extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); |
202 | 202 | ||
203 | int orinoco_process_xmit_skb(struct sk_buff *skb, | ||
204 | struct net_device *dev, | ||
205 | struct orinoco_private *priv, | ||
206 | int *tx_control, | ||
207 | u8 *mic); | ||
208 | |||
203 | /* Common ndo functions exported for reuse by orinoco_usb */ | 209 | /* Common ndo functions exported for reuse by orinoco_usb */ |
204 | int orinoco_open(struct net_device *dev); | 210 | int orinoco_open(struct net_device *dev); |
205 | int orinoco_stop(struct net_device *dev); | 211 | int orinoco_stop(struct net_device *dev); |
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index e22093359f3..78f089baa8c 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include <linux/wireless.h> | 67 | #include <linux/wireless.h> |
68 | #include <linux/firmware.h> | 68 | #include <linux/firmware.h> |
69 | 69 | ||
70 | #include "mic.h" | ||
70 | #include "orinoco.h" | 71 | #include "orinoco.h" |
71 | 72 | ||
72 | #ifndef URB_ASYNC_UNLINK | 73 | #ifndef URB_ASYNC_UNLINK |
@@ -1198,11 +1199,9 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1198 | struct orinoco_private *priv = ndev_priv(dev); | 1199 | struct orinoco_private *priv = ndev_priv(dev); |
1199 | struct net_device_stats *stats = &priv->stats; | 1200 | struct net_device_stats *stats = &priv->stats; |
1200 | struct ezusb_priv *upriv = priv->card; | 1201 | struct ezusb_priv *upriv = priv->card; |
1202 | u8 mic[MICHAEL_MIC_LEN+1]; | ||
1201 | int err = 0; | 1203 | int err = 0; |
1202 | char *p; | 1204 | int tx_control; |
1203 | struct ethhdr *eh; | ||
1204 | int len, data_len, data_off; | ||
1205 | __le16 tx_control; | ||
1206 | unsigned long flags; | 1205 | unsigned long flags; |
1207 | struct request_context *ctx; | 1206 | struct request_context *ctx; |
1208 | u8 *buf; | 1207 | u8 *buf; |
@@ -1222,7 +1221,7 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1222 | 1221 | ||
1223 | if (orinoco_lock(priv, &flags) != 0) { | 1222 | if (orinoco_lock(priv, &flags) != 0) { |
1224 | printk(KERN_ERR | 1223 | printk(KERN_ERR |
1225 | "%s: orinoco_xmit() called while hw_unavailable\n", | 1224 | "%s: ezusb_xmit() called while hw_unavailable\n", |
1226 | dev->name); | 1225 | dev->name); |
1227 | return NETDEV_TX_BUSY; | 1226 | return NETDEV_TX_BUSY; |
1228 | } | 1227 | } |
@@ -1232,53 +1231,46 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1232 | /* Oops, the firmware hasn't established a connection, | 1231 | /* Oops, the firmware hasn't established a connection, |
1233 | silently drop the packet (this seems to be the | 1232 | silently drop the packet (this seems to be the |
1234 | safest approach). */ | 1233 | safest approach). */ |
1235 | stats->tx_errors++; | 1234 | goto drop; |
1236 | orinoco_unlock(priv, &flags); | ||
1237 | dev_kfree_skb(skb); | ||
1238 | return NETDEV_TX_OK; | ||
1239 | } | 1235 | } |
1240 | 1236 | ||
1237 | /* Check packet length */ | ||
1238 | if (skb->len < ETH_HLEN) | ||
1239 | goto drop; | ||
1240 | |||
1241 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0); | 1241 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0); |
1242 | if (!ctx) | 1242 | if (!ctx) |
1243 | goto fail; | 1243 | goto busy; |
1244 | 1244 | ||
1245 | memset(ctx->buf, 0, BULK_BUF_SIZE); | 1245 | memset(ctx->buf, 0, BULK_BUF_SIZE); |
1246 | buf = ctx->buf->data; | 1246 | buf = ctx->buf->data; |
1247 | 1247 | ||
1248 | /* Length of the packet body */ | 1248 | tx_control = 0; |
1249 | /* FIXME: what if the skb is smaller than this? */ | 1249 | |
1250 | len = max_t(int, skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); | 1250 | err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control, |
1251 | 1251 | &mic[0]); | |
1252 | eh = (struct ethhdr *) skb->data; | 1252 | if (err) |
1253 | 1253 | goto drop; | |
1254 | tx_control = cpu_to_le16(0); | 1254 | |
1255 | memcpy(buf, &tx_control, sizeof(tx_control)); | 1255 | { |
1256 | buf += sizeof(tx_control); | 1256 | __le16 *tx_cntl = (__le16 *)buf; |
1257 | /* Encapsulate Ethernet-II frames */ | 1257 | *tx_cntl = cpu_to_le16(tx_control); |
1258 | if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */ | 1258 | buf += sizeof(*tx_cntl); |
1259 | struct header_struct *hdr = (void *) buf; | ||
1260 | buf += sizeof(*hdr); | ||
1261 | data_len = len; | ||
1262 | data_off = sizeof(tx_control) + sizeof(*hdr); | ||
1263 | p = skb->data + ETH_HLEN; | ||
1264 | |||
1265 | /* 802.3 header */ | ||
1266 | memcpy(hdr->dest, eh->h_dest, ETH_ALEN); | ||
1267 | memcpy(hdr->src, eh->h_source, ETH_ALEN); | ||
1268 | hdr->len = htons(data_len + ENCAPS_OVERHEAD); | ||
1269 | |||
1270 | /* 802.2 header */ | ||
1271 | memcpy(&hdr->dsap, &encaps_hdr, sizeof(encaps_hdr)); | ||
1272 | |||
1273 | hdr->ethertype = eh->h_proto; | ||
1274 | } else { /* IEEE 802.3 frame */ | ||
1275 | data_len = len + ETH_HLEN; | ||
1276 | data_off = sizeof(tx_control); | ||
1277 | p = skb->data; | ||
1278 | } | 1259 | } |
1279 | 1260 | ||
1280 | memcpy(buf, p, data_len); | 1261 | memcpy(buf, skb->data, skb->len); |
1281 | buf += data_len; | 1262 | buf += skb->len; |
1263 | |||
1264 | if (tx_control & HERMES_TXCTRL_MIC) { | ||
1265 | u8 *m = mic; | ||
1266 | /* Mic has been offset so it can be copied to an even | ||
1267 | * address. We're copying eveything anyway, so we | ||
1268 | * don't need to copy that first byte. */ | ||
1269 | if (skb->len % 2) | ||
1270 | m++; | ||
1271 | memcpy(buf, m, MICHAEL_MIC_LEN); | ||
1272 | buf += MICHAEL_MIC_LEN; | ||
1273 | } | ||
1282 | 1274 | ||
1283 | /* Finally, we actually initiate the send */ | 1275 | /* Finally, we actually initiate the send */ |
1284 | netif_stop_queue(dev); | 1276 | netif_stop_queue(dev); |
@@ -1294,20 +1286,23 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1294 | if (net_ratelimit()) | 1286 | if (net_ratelimit()) |
1295 | printk(KERN_ERR "%s: Error %d transmitting packet\n", | 1287 | printk(KERN_ERR "%s: Error %d transmitting packet\n", |
1296 | dev->name, err); | 1288 | dev->name, err); |
1297 | stats->tx_errors++; | 1289 | goto busy; |
1298 | goto fail; | ||
1299 | } | 1290 | } |
1300 | 1291 | ||
1301 | dev->trans_start = jiffies; | 1292 | dev->trans_start = jiffies; |
1302 | stats->tx_bytes += data_off + data_len; | 1293 | stats->tx_bytes += skb->len; |
1294 | goto ok; | ||
1303 | 1295 | ||
1304 | orinoco_unlock(priv, &flags); | 1296 | drop: |
1297 | stats->tx_errors++; | ||
1298 | stats->tx_dropped++; | ||
1305 | 1299 | ||
1300 | ok: | ||
1301 | orinoco_unlock(priv, &flags); | ||
1306 | dev_kfree_skb(skb); | 1302 | dev_kfree_skb(skb); |
1307 | |||
1308 | return NETDEV_TX_OK; | 1303 | return NETDEV_TX_OK; |
1309 | 1304 | ||
1310 | fail: | 1305 | busy: |
1311 | orinoco_unlock(priv, &flags); | 1306 | orinoco_unlock(priv, &flags); |
1312 | return NETDEV_TX_BUSY; | 1307 | return NETDEV_TX_BUSY; |
1313 | } | 1308 | } |