diff options
author | Christoph Hellwig <hch@lst.de> | 2005-06-18 19:28:06 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-27 00:23:55 -0400 |
commit | 98c4cae1dafcf1abbfebc0189ff27df586a838b0 (patch) | |
tree | dbd2374d0acbc068bb2679a868c2929361f25eb4 /drivers/net/wireless | |
parent | 8f2abf4430ef2a131926a537ee6325dc43b0ec28 (diff) |
[PATCH] orinoco: monitor mode support
Patch from Pavel Roskin
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/orinoco.c | 208 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.h | 1 |
2 files changed, 180 insertions, 29 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 96df2885728f..05c2ad556506 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -499,6 +499,10 @@ static int ignore_disconnect; /* = 0 */ | |||
499 | module_param(ignore_disconnect, int, 0644); | 499 | module_param(ignore_disconnect, int, 0644); |
500 | MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer"); | 500 | MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer"); |
501 | 501 | ||
502 | static int force_monitor; /* = 0 */ | ||
503 | module_param(force_monitor, int, 0644); | ||
504 | MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions"); | ||
505 | |||
502 | /********************************************************************/ | 506 | /********************************************************************/ |
503 | /* Compile time configuration and compatibility stuff */ | 507 | /* Compile time configuration and compatibility stuff */ |
504 | /********************************************************************/ | 508 | /********************************************************************/ |
@@ -670,6 +674,10 @@ static inline void set_port_type(struct orinoco_private *priv) | |||
670 | priv->createibss = 1; | 674 | priv->createibss = 1; |
671 | } | 675 | } |
672 | break; | 676 | break; |
677 | case IW_MODE_MONITOR: | ||
678 | priv->port_type = 3; | ||
679 | priv->createibss = 0; | ||
680 | break; | ||
673 | default: | 681 | default: |
674 | printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", | 682 | printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", |
675 | priv->ndev->name); | 683 | priv->ndev->name); |
@@ -856,7 +864,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
856 | return 1; | 864 | return 1; |
857 | } | 865 | } |
858 | 866 | ||
859 | if (! netif_carrier_ok(dev)) { | 867 | if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) { |
860 | /* Oops, the firmware hasn't established a connection, | 868 | /* Oops, the firmware hasn't established a connection, |
861 | silently drop the packet (this seems to be the | 869 | silently drop the packet (this seems to be the |
862 | safest approach). */ | 870 | safest approach). */ |
@@ -1118,6 +1126,117 @@ static void orinoco_stat_gather(struct net_device *dev, | |||
1118 | } | 1126 | } |
1119 | } | 1127 | } |
1120 | 1128 | ||
1129 | /* | ||
1130 | * orinoco_rx_monitor - handle received monitor frames. | ||
1131 | * | ||
1132 | * Arguments: | ||
1133 | * dev network device | ||
1134 | * rxfid received FID | ||
1135 | * desc rx descriptor of the frame | ||
1136 | * | ||
1137 | * Call context: interrupt | ||
1138 | */ | ||
1139 | static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, | ||
1140 | struct hermes_rx_descriptor *desc) | ||
1141 | { | ||
1142 | u32 hdrlen = 30; /* return full header by default */ | ||
1143 | u32 datalen = 0; | ||
1144 | u16 fc; | ||
1145 | int err; | ||
1146 | int len; | ||
1147 | struct sk_buff *skb; | ||
1148 | struct orinoco_private *priv = netdev_priv(dev); | ||
1149 | struct net_device_stats *stats = &priv->stats; | ||
1150 | hermes_t *hw = &priv->hw; | ||
1151 | |||
1152 | len = le16_to_cpu(desc->data_len); | ||
1153 | |||
1154 | /* Determine the size of the header and the data */ | ||
1155 | fc = le16_to_cpu(desc->frame_ctl); | ||
1156 | switch (fc & IEEE80211_FCTL_FTYPE) { | ||
1157 | case IEEE80211_FTYPE_DATA: | ||
1158 | if ((fc & IEEE80211_FCTL_TODS) | ||
1159 | && (fc & IEEE80211_FCTL_FROMDS)) | ||
1160 | hdrlen = 30; | ||
1161 | else | ||
1162 | hdrlen = 24; | ||
1163 | datalen = len; | ||
1164 | break; | ||
1165 | case IEEE80211_FTYPE_MGMT: | ||
1166 | hdrlen = 24; | ||
1167 | datalen = len; | ||
1168 | break; | ||
1169 | case IEEE80211_FTYPE_CTL: | ||
1170 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
1171 | case IEEE80211_STYPE_PSPOLL: | ||
1172 | case IEEE80211_STYPE_RTS: | ||
1173 | case IEEE80211_STYPE_CFEND: | ||
1174 | case IEEE80211_STYPE_CFENDACK: | ||
1175 | hdrlen = 16; | ||
1176 | break; | ||
1177 | case IEEE80211_STYPE_CTS: | ||
1178 | case IEEE80211_STYPE_ACK: | ||
1179 | hdrlen = 10; | ||
1180 | break; | ||
1181 | } | ||
1182 | break; | ||
1183 | default: | ||
1184 | /* Unknown frame type */ | ||
1185 | break; | ||
1186 | } | ||
1187 | |||
1188 | /* sanity check the length */ | ||
1189 | if (datalen > IEEE80211_DATA_LEN + 12) { | ||
1190 | printk(KERN_DEBUG "%s: oversized monitor frame, " | ||
1191 | "data length = %d\n", dev->name, datalen); | ||
1192 | err = -EIO; | ||
1193 | stats->rx_length_errors++; | ||
1194 | goto update_stats; | ||
1195 | } | ||
1196 | |||
1197 | skb = dev_alloc_skb(hdrlen + datalen); | ||
1198 | if (!skb) { | ||
1199 | printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n", | ||
1200 | dev->name); | ||
1201 | err = -ENOMEM; | ||
1202 | goto drop; | ||
1203 | } | ||
1204 | |||
1205 | /* Copy the 802.11 header to the skb */ | ||
1206 | memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen); | ||
1207 | skb->mac.raw = skb->data; | ||
1208 | |||
1209 | /* If any, copy the data from the card to the skb */ | ||
1210 | if (datalen > 0) { | ||
1211 | err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen), | ||
1212 | ALIGN(datalen, 2), rxfid, | ||
1213 | HERMES_802_2_OFFSET); | ||
1214 | if (err) { | ||
1215 | printk(KERN_ERR "%s: error %d reading monitor frame\n", | ||
1216 | dev->name, err); | ||
1217 | goto drop; | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | skb->dev = dev; | ||
1222 | skb->ip_summed = CHECKSUM_NONE; | ||
1223 | skb->pkt_type = PACKET_OTHERHOST; | ||
1224 | skb->protocol = __constant_htons(ETH_P_802_2); | ||
1225 | |||
1226 | dev->last_rx = jiffies; | ||
1227 | stats->rx_packets++; | ||
1228 | stats->rx_bytes += skb->len; | ||
1229 | |||
1230 | netif_rx(skb); | ||
1231 | return; | ||
1232 | |||
1233 | drop: | ||
1234 | dev_kfree_skb_irq(skb); | ||
1235 | update_stats: | ||
1236 | stats->rx_errors++; | ||
1237 | stats->rx_dropped++; | ||
1238 | } | ||
1239 | |||
1121 | static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | 1240 | static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) |
1122 | { | 1241 | { |
1123 | struct orinoco_private *priv = netdev_priv(dev); | 1242 | struct orinoco_private *priv = netdev_priv(dev); |
@@ -1137,24 +1256,29 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1137 | if (err) { | 1256 | if (err) { |
1138 | printk(KERN_ERR "%s: error %d reading Rx descriptor. " | 1257 | printk(KERN_ERR "%s: error %d reading Rx descriptor. " |
1139 | "Frame dropped.\n", dev->name, err); | 1258 | "Frame dropped.\n", dev->name, err); |
1140 | stats->rx_errors++; | 1259 | goto update_stats; |
1141 | goto drop; | ||
1142 | } | 1260 | } |
1143 | 1261 | ||
1144 | status = le16_to_cpu(desc.status); | 1262 | status = le16_to_cpu(desc.status); |
1145 | 1263 | ||
1146 | if (status & HERMES_RXSTAT_ERR) { | 1264 | if (status & HERMES_RXSTAT_BADCRC) { |
1147 | if (status & HERMES_RXSTAT_UNDECRYPTABLE) { | 1265 | DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", |
1148 | wstats->discard.code++; | 1266 | dev->name); |
1149 | DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", | 1267 | stats->rx_crc_errors++; |
1150 | dev->name); | 1268 | goto update_stats; |
1151 | } else { | 1269 | } |
1152 | stats->rx_crc_errors++; | ||
1153 | DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); | ||
1154 | } | ||
1155 | 1270 | ||
1156 | stats->rx_errors++; | 1271 | /* Handle frames in monitor mode */ |
1157 | goto drop; | 1272 | if (priv->iw_mode == IW_MODE_MONITOR) { |
1273 | orinoco_rx_monitor(dev, rxfid, &desc); | ||
1274 | return; | ||
1275 | } | ||
1276 | |||
1277 | if (status & HERMES_RXSTAT_UNDECRYPTABLE) { | ||
1278 | DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", | ||
1279 | dev->name); | ||
1280 | wstats->discard.code++; | ||
1281 | goto update_stats; | ||
1158 | } | 1282 | } |
1159 | 1283 | ||
1160 | length = le16_to_cpu(desc.data_len); | 1284 | length = le16_to_cpu(desc.data_len); |
@@ -1165,15 +1289,13 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1165 | /* At least on Symbol firmware with PCF we get quite a | 1289 | /* At least on Symbol firmware with PCF we get quite a |
1166 | lot of these legitimately - Poll frames with no | 1290 | lot of these legitimately - Poll frames with no |
1167 | data. */ | 1291 | data. */ |
1168 | stats->rx_dropped++; | 1292 | return; |
1169 | goto drop; | ||
1170 | } | 1293 | } |
1171 | if (length > IEEE802_11_DATA_LEN) { | 1294 | if (length > IEEE802_11_DATA_LEN) { |
1172 | printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", | 1295 | printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", |
1173 | dev->name, length); | 1296 | dev->name, length); |
1174 | stats->rx_length_errors++; | 1297 | stats->rx_length_errors++; |
1175 | stats->rx_errors++; | 1298 | goto update_stats; |
1176 | goto drop; | ||
1177 | } | 1299 | } |
1178 | 1300 | ||
1179 | /* We need space for the packet data itself, plus an ethernet | 1301 | /* We need space for the packet data itself, plus an ethernet |
@@ -1185,7 +1307,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1185 | if (!skb) { | 1307 | if (!skb) { |
1186 | printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", | 1308 | printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", |
1187 | dev->name); | 1309 | dev->name); |
1188 | goto drop; | 1310 | goto update_stats; |
1189 | } | 1311 | } |
1190 | 1312 | ||
1191 | /* We'll prepend the header, so reserve space for it. The worst | 1313 | /* We'll prepend the header, so reserve space for it. The worst |
@@ -1199,7 +1321,6 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1199 | if (err) { | 1321 | if (err) { |
1200 | printk(KERN_ERR "%s: error %d reading frame. " | 1322 | printk(KERN_ERR "%s: error %d reading frame. " |
1201 | "Frame dropped.\n", dev->name, err); | 1323 | "Frame dropped.\n", dev->name, err); |
1202 | stats->rx_errors++; | ||
1203 | goto drop; | 1324 | goto drop; |
1204 | } | 1325 | } |
1205 | 1326 | ||
@@ -1245,11 +1366,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) | |||
1245 | return; | 1366 | return; |
1246 | 1367 | ||
1247 | drop: | 1368 | drop: |
1369 | dev_kfree_skb_irq(skb); | ||
1370 | update_stats: | ||
1371 | stats->rx_errors++; | ||
1248 | stats->rx_dropped++; | 1372 | stats->rx_dropped++; |
1249 | |||
1250 | if (skb) | ||
1251 | dev_kfree_skb_irq(skb); | ||
1252 | return; | ||
1253 | } | 1373 | } |
1254 | 1374 | ||
1255 | /********************************************************************/ | 1375 | /********************************************************************/ |
@@ -2065,6 +2185,20 @@ static int __orinoco_program_rids(struct net_device *dev) | |||
2065 | } | 2185 | } |
2066 | } | 2186 | } |
2067 | 2187 | ||
2188 | if (priv->iw_mode == IW_MODE_MONITOR) { | ||
2189 | /* Enable monitor mode */ | ||
2190 | dev->type = ARPHRD_IEEE80211; | ||
2191 | err = hermes_docmd_wait(hw, HERMES_CMD_TEST | | ||
2192 | HERMES_TEST_MONITOR, 0, NULL); | ||
2193 | } else { | ||
2194 | /* Disable monitor mode */ | ||
2195 | dev->type = ARPHRD_ETHER; | ||
2196 | err = hermes_docmd_wait(hw, HERMES_CMD_TEST | | ||
2197 | HERMES_TEST_STOP, 0, NULL); | ||
2198 | } | ||
2199 | if (err) | ||
2200 | return err; | ||
2201 | |||
2068 | /* Set promiscuity / multicast*/ | 2202 | /* Set promiscuity / multicast*/ |
2069 | priv->promiscuous = 0; | 2203 | priv->promiscuous = 0; |
2070 | priv->mc_count = 0; | 2204 | priv->mc_count = 0; |
@@ -2413,6 +2547,7 @@ static int determine_firmware(struct net_device *dev) | |||
2413 | priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ | 2547 | priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ |
2414 | priv->ibss_port = 1; | 2548 | priv->ibss_port = 1; |
2415 | priv->has_hostscan = (firmver >= 0x8000a); | 2549 | priv->has_hostscan = (firmver >= 0x8000a); |
2550 | priv->broken_monitor = (firmver >= 0x80000); | ||
2416 | 2551 | ||
2417 | /* Tested with Agere firmware : | 2552 | /* Tested with Agere firmware : |
2418 | * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II | 2553 | * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II |
@@ -2980,6 +3115,15 @@ static int orinoco_ioctl_setmode(struct net_device *dev, | |||
2980 | case IW_MODE_INFRA: | 3115 | case IW_MODE_INFRA: |
2981 | break; | 3116 | break; |
2982 | 3117 | ||
3118 | case IW_MODE_MONITOR: | ||
3119 | if (priv->broken_monitor && !force_monitor) { | ||
3120 | printk(KERN_WARNING "%s: Monitor mode support is " | ||
3121 | "buggy in this firmware, not enabling\n", | ||
3122 | dev->name); | ||
3123 | err = -EOPNOTSUPP; | ||
3124 | } | ||
3125 | break; | ||
3126 | |||
2983 | default: | 3127 | default: |
2984 | err = -EOPNOTSUPP; | 3128 | err = -EOPNOTSUPP; |
2985 | break; | 3129 | break; |
@@ -3355,11 +3499,9 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, | |||
3355 | unsigned long flags; | 3499 | unsigned long flags; |
3356 | int err = -EINPROGRESS; /* Call commit handler */ | 3500 | int err = -EINPROGRESS; /* Call commit handler */ |
3357 | 3501 | ||
3358 | /* We can only use this in Ad-Hoc demo mode to set the operating | 3502 | /* In infrastructure mode the AP sets the channel */ |
3359 | * frequency, or in IBSS mode to set the frequency where the IBSS | 3503 | if (priv->iw_mode == IW_MODE_INFRA) |
3360 | * will be created - Jean II */ | 3504 | return -EBUSY; |
3361 | if (priv->iw_mode != IW_MODE_ADHOC) | ||
3362 | return -EOPNOTSUPP; | ||
3363 | 3505 | ||
3364 | if ( (frq->e == 0) && (frq->m <= 1000) ) { | 3506 | if ( (frq->e == 0) && (frq->m <= 1000) ) { |
3365 | /* Setting by channel number */ | 3507 | /* Setting by channel number */ |
@@ -3383,7 +3525,15 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, | |||
3383 | 3525 | ||
3384 | if (orinoco_lock(priv, &flags) != 0) | 3526 | if (orinoco_lock(priv, &flags) != 0) |
3385 | return -EBUSY; | 3527 | return -EBUSY; |
3528 | |||
3386 | priv->channel = chan; | 3529 | priv->channel = chan; |
3530 | if (priv->iw_mode == IW_MODE_MONITOR) { | ||
3531 | /* Fast channel change - no commit if successful */ | ||
3532 | hermes_t *hw = &priv->hw; | ||
3533 | err = hermes_docmd_wait(hw, HERMES_CMD_TEST | | ||
3534 | HERMES_TEST_SET_CHANNEL, | ||
3535 | chan, NULL); | ||
3536 | } | ||
3387 | orinoco_unlock(priv, &flags); | 3537 | orinoco_unlock(priv, &flags); |
3388 | 3538 | ||
3389 | return err; | 3539 | return err; |
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 2a6b1c09b26d..0f4be5da46e7 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h | |||
@@ -94,6 +94,7 @@ struct orinoco_private { | |||
94 | unsigned int has_sensitivity:1; | 94 | unsigned int has_sensitivity:1; |
95 | unsigned int has_hostscan:1; | 95 | unsigned int has_hostscan:1; |
96 | unsigned int broken_disableport:1; | 96 | unsigned int broken_disableport:1; |
97 | unsigned int broken_monitor:1; | ||
97 | 98 | ||
98 | /* Configuration paramaters */ | 99 | /* Configuration paramaters */ |
99 | u32 iw_mode; | 100 | u32 iw_mode; |