diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-09-21 12:54:47 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-21 23:02:31 -0400 |
commit | 3f552bbf8614d2d26f488ca0d3e188bdec484bf4 (patch) | |
tree | 9721d4dc2d53579d7c324fa0b98eddc964149ab4 | |
parent | 3cdd00c5827621cd0b1bb0665aa62ef9a724297d (diff) |
[PATCH] ieee82011: Added ieee80211_tx_frame to convert generic 802.11 data frames, and callbacks
tree 40adc78b623ae70d56074934ec6334eb4f0ae6a5
parent db43d847bcebaa3df6414e26d0008eb21690e8cf
author James Ketrenos <jketreno@linux.intel.com> 1124445938 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127313102 -0500
Added ieee80211_tx_frame to convert generic 802.11 data frames into
txbs for transmission.
Added several purpose specific callbacks (handle_assoc, handle_auth,
etc.) which the driver can register with for being notified on
reception of variouf frame elements.
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | include/net/ieee80211.h | 23 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 58 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 64 |
3 files changed, 130 insertions, 15 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 5e11ccf8a763..43cf2e577191 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h | |||
@@ -769,6 +769,27 @@ struct ieee80211_device { | |||
769 | int (*hard_start_xmit) (struct ieee80211_txb * txb, | 769 | int (*hard_start_xmit) (struct ieee80211_txb * txb, |
770 | struct net_device * dev); | 770 | struct net_device * dev); |
771 | int (*reset_port) (struct net_device * dev); | 771 | int (*reset_port) (struct net_device * dev); |
772 | int (*is_queue_full) (struct net_device * dev, int pri); | ||
773 | |||
774 | /* Typical STA methods */ | ||
775 | int (*handle_auth) (struct net_device * dev, | ||
776 | struct ieee80211_auth * auth); | ||
777 | int (*handle_disassoc) (struct net_device * dev, | ||
778 | struct ieee80211_disassoc * assoc); | ||
779 | int (*handle_beacon) (struct net_device * dev, | ||
780 | struct ieee80211_beacon * beacon, | ||
781 | struct ieee80211_network * network); | ||
782 | int (*handle_probe_response) (struct net_device * dev, | ||
783 | struct ieee80211_probe_response * resp, | ||
784 | struct ieee80211_network * network); | ||
785 | int (*handle_assoc_response) (struct net_device * dev, | ||
786 | struct ieee80211_assoc_response * resp, | ||
787 | struct ieee80211_network * network); | ||
788 | |||
789 | /* Typical AP methods */ | ||
790 | int (*handle_assoc_request) (struct net_device * dev); | ||
791 | int (*handle_reassoc_request) (struct net_device * dev, | ||
792 | struct ieee80211_reassoc_request * req); | ||
772 | 793 | ||
773 | /* This must be the last item so that it points to the data | 794 | /* This must be the last item so that it points to the data |
774 | * allocated beyond this structure by alloc_ieee80211 */ | 795 | * allocated beyond this structure by alloc_ieee80211 */ |
@@ -877,6 +898,8 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee); | |||
877 | /* ieee80211_tx.c */ | 898 | /* ieee80211_tx.c */ |
878 | extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); | 899 | extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); |
879 | extern void ieee80211_txb_free(struct ieee80211_txb *); | 900 | extern void ieee80211_txb_free(struct ieee80211_txb *); |
901 | extern int ieee80211_tx_frame(struct ieee80211_device *ieee, | ||
902 | struct ieee80211_hdr *frame, int len); | ||
880 | 903 | ||
881 | /* ieee80211_rx.c */ | 904 | /* ieee80211_rx.c */ |
882 | extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | 905 | extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, |
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 71d14c7d915c..d1ae28280d7e 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c | |||
@@ -1029,12 +1029,18 @@ static inline void update_network(struct ieee80211_network *dst, | |||
1029 | /* dst->last_associate is not overwritten */ | 1029 | /* dst->last_associate is not overwritten */ |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | static inline int is_beacon(int fc) | ||
1033 | { | ||
1034 | return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); | ||
1035 | } | ||
1036 | |||
1032 | static inline void ieee80211_process_probe_response(struct ieee80211_device | 1037 | static inline void ieee80211_process_probe_response(struct ieee80211_device |
1033 | *ieee, struct | 1038 | *ieee, struct |
1034 | ieee80211_probe_response | 1039 | ieee80211_probe_response |
1035 | *beacon, struct ieee80211_rx_stats | 1040 | *beacon, struct ieee80211_rx_stats |
1036 | *stats) | 1041 | *stats) |
1037 | { | 1042 | { |
1043 | struct net_device *dev = ieee->dev; | ||
1038 | struct ieee80211_network network; | 1044 | struct ieee80211_network network; |
1039 | struct ieee80211_network *target; | 1045 | struct ieee80211_network *target; |
1040 | struct ieee80211_network *oldest = NULL; | 1046 | struct ieee80211_network *oldest = NULL; |
@@ -1070,11 +1076,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device | |||
1070 | escape_essid(info_element->data, | 1076 | escape_essid(info_element->data, |
1071 | info_element->len), | 1077 | info_element->len), |
1072 | MAC_ARG(beacon->header.addr3), | 1078 | MAC_ARG(beacon->header.addr3), |
1073 | WLAN_FC_GET_STYPE(le16_to_cpu | 1079 | is_beacon(le16_to_cpu |
1074 | (beacon->header. | 1080 | (beacon->header. |
1075 | frame_ctl)) == | 1081 | frame_ctl)) ? |
1076 | IEEE80211_STYPE_PROBE_RESP ? | 1082 | "BEACON" : "PROBE RESPONSE"); |
1077 | "PROBE RESPONSE" : "BEACON"); | ||
1078 | return; | 1083 | return; |
1079 | } | 1084 | } |
1080 | 1085 | ||
@@ -1123,11 +1128,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device | |||
1123 | escape_essid(network.ssid, | 1128 | escape_essid(network.ssid, |
1124 | network.ssid_len), | 1129 | network.ssid_len), |
1125 | MAC_ARG(network.bssid), | 1130 | MAC_ARG(network.bssid), |
1126 | WLAN_FC_GET_STYPE(le16_to_cpu | 1131 | is_beacon(le16_to_cpu |
1127 | (beacon->header. | 1132 | (beacon->header. |
1128 | frame_ctl)) == | 1133 | frame_ctl)) ? |
1129 | IEEE80211_STYPE_PROBE_RESP ? | 1134 | "BEACON" : "PROBE RESPONSE"); |
1130 | "PROBE RESPONSE" : "BEACON"); | ||
1131 | #endif | 1135 | #endif |
1132 | memcpy(target, &network, sizeof(*target)); | 1136 | memcpy(target, &network, sizeof(*target)); |
1133 | list_add_tail(&target->list, &ieee->network_list); | 1137 | list_add_tail(&target->list, &ieee->network_list); |
@@ -1136,15 +1140,22 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device | |||
1136 | escape_essid(target->ssid, | 1140 | escape_essid(target->ssid, |
1137 | target->ssid_len), | 1141 | target->ssid_len), |
1138 | MAC_ARG(target->bssid), | 1142 | MAC_ARG(target->bssid), |
1139 | WLAN_FC_GET_STYPE(le16_to_cpu | 1143 | is_beacon(le16_to_cpu |
1140 | (beacon->header. | 1144 | (beacon->header. |
1141 | frame_ctl)) == | 1145 | frame_ctl)) ? |
1142 | IEEE80211_STYPE_PROBE_RESP ? | 1146 | "BEACON" : "PROBE RESPONSE"); |
1143 | "PROBE RESPONSE" : "BEACON"); | ||
1144 | update_network(target, &network); | 1147 | update_network(target, &network); |
1145 | } | 1148 | } |
1146 | 1149 | ||
1147 | spin_unlock_irqrestore(&ieee->lock, flags); | 1150 | spin_unlock_irqrestore(&ieee->lock, flags); |
1151 | |||
1152 | if (is_beacon(le16_to_cpu(beacon->header.frame_ctl))) { | ||
1153 | if (ieee->handle_beacon != NULL) | ||
1154 | ieee->handle_beacon(dev, beacon, &network); | ||
1155 | } else { | ||
1156 | if (ieee->handle_probe_response != NULL) | ||
1157 | ieee->handle_probe_response(dev, beacon, &network); | ||
1158 | } | ||
1148 | } | 1159 | } |
1149 | 1160 | ||
1150 | void ieee80211_rx_mgt(struct ieee80211_device *ieee, | 1161 | void ieee80211_rx_mgt(struct ieee80211_device *ieee, |
@@ -1185,6 +1196,23 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, | |||
1185 | ieee80211_probe_response *) | 1196 | ieee80211_probe_response *) |
1186 | header, stats); | 1197 | header, stats); |
1187 | break; | 1198 | break; |
1199 | case IEEE80211_STYPE_AUTH: | ||
1200 | |||
1201 | IEEE80211_DEBUG_MGMT("recieved auth (%d)\n", | ||
1202 | WLAN_FC_GET_STYPE(le16_to_cpu | ||
1203 | (header->frame_ctl))); | ||
1204 | |||
1205 | if (ieee->handle_auth != NULL) | ||
1206 | ieee->handle_auth(ieee->dev, | ||
1207 | (struct ieee80211_auth *)header); | ||
1208 | break; | ||
1209 | |||
1210 | case IEEE80211_STYPE_DISASSOC: | ||
1211 | if (ieee->handle_disassoc != NULL) | ||
1212 | ieee->handle_disassoc(ieee->dev, | ||
1213 | (struct ieee80211_disassoc *) | ||
1214 | header); | ||
1215 | break; | ||
1188 | 1216 | ||
1189 | default: | 1217 | default: |
1190 | IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", | 1218 | IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", |
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index cdee41cefb26..f505aa127e21 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c | |||
@@ -459,7 +459,71 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
459 | netif_stop_queue(dev); | 459 | netif_stop_queue(dev); |
460 | stats->tx_errors++; | 460 | stats->tx_errors++; |
461 | return 1; | 461 | return 1; |
462 | } | ||
463 | |||
464 | /* Incoming 802.11 strucure is converted to a TXB | ||
465 | * a block of 802.11 fragment packets (stored as skbs) */ | ||
466 | int ieee80211_tx_frame(struct ieee80211_device *ieee, | ||
467 | struct ieee80211_hdr *frame, int len) | ||
468 | { | ||
469 | struct ieee80211_txb *txb = NULL; | ||
470 | unsigned long flags; | ||
471 | struct net_device_stats *stats = &ieee->stats; | ||
472 | struct sk_buff *skb_frag; | ||
473 | |||
474 | spin_lock_irqsave(&ieee->lock, flags); | ||
475 | |||
476 | /* If there is no driver handler to take the TXB, dont' bother | ||
477 | * creating it... */ | ||
478 | if (!ieee->hard_start_xmit) { | ||
479 | printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); | ||
480 | goto success; | ||
481 | } | ||
462 | 482 | ||
483 | if (unlikely(len < 24)) { | ||
484 | printk(KERN_WARNING "%s: skb too small (%d).\n", | ||
485 | ieee->dev->name, len); | ||
486 | goto success; | ||
487 | } | ||
488 | |||
489 | /* When we allocate the TXB we allocate enough space for the reserve | ||
490 | * and full fragment bytes (bytes_per_frag doesn't include prefix, | ||
491 | * postfix, header, FCS, etc.) */ | ||
492 | txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC); | ||
493 | if (unlikely(!txb)) { | ||
494 | printk(KERN_WARNING "%s: Could not allocate TXB\n", | ||
495 | ieee->dev->name); | ||
496 | goto failed; | ||
497 | } | ||
498 | txb->encrypted = 0; | ||
499 | txb->payload_size = len; | ||
500 | |||
501 | skb_frag = txb->fragments[0]; | ||
502 | |||
503 | memcpy(skb_put(skb_frag, len), frame, len); | ||
504 | |||
505 | if (ieee->config & | ||
506 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | ||
507 | skb_put(skb_frag, 4); | ||
508 | |||
509 | success: | ||
510 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
511 | |||
512 | if (txb) { | ||
513 | if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) { | ||
514 | stats->tx_packets++; | ||
515 | stats->tx_bytes += txb->payload_size; | ||
516 | return 0; | ||
517 | } | ||
518 | ieee80211_txb_free(txb); | ||
519 | } | ||
520 | return 0; | ||
521 | |||
522 | failed: | ||
523 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
524 | stats->tx_errors++; | ||
525 | return 1; | ||
463 | } | 526 | } |
464 | 527 | ||
528 | EXPORT_SYMBOL(ieee80211_tx_frame); | ||
465 | EXPORT_SYMBOL(ieee80211_txb_free); | 529 | EXPORT_SYMBOL(ieee80211_txb_free); |