00001
00002
00003
00004
00005 static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
00006 int left)
00007 {
00008 struct hfa384x_comm_tallies *tallies;
00009
00010 if (left < sizeof(struct hfa384x_comm_tallies)) {
00011 printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
00012 "info frame\n", local->dev->name, left);
00013 return;
00014 }
00015
00016 tallies = (struct hfa384x_comm_tallies *) buf;
00017 #define ADD_COMM_TALLIES(name) \
00018 local->comm_tallies.name += le16_to_cpu(tallies->name)
00019 ADD_COMM_TALLIES(tx_unicast_frames);
00020 ADD_COMM_TALLIES(tx_multicast_frames);
00021 ADD_COMM_TALLIES(tx_fragments);
00022 ADD_COMM_TALLIES(tx_unicast_octets);
00023 ADD_COMM_TALLIES(tx_multicast_octets);
00024 ADD_COMM_TALLIES(tx_deferred_transmissions);
00025 ADD_COMM_TALLIES(tx_single_retry_frames);
00026 ADD_COMM_TALLIES(tx_multiple_retry_frames);
00027 ADD_COMM_TALLIES(tx_retry_limit_exceeded);
00028 ADD_COMM_TALLIES(tx_discards);
00029 ADD_COMM_TALLIES(rx_unicast_frames);
00030 ADD_COMM_TALLIES(rx_multicast_frames);
00031 ADD_COMM_TALLIES(rx_fragments);
00032 ADD_COMM_TALLIES(rx_unicast_octets);
00033 ADD_COMM_TALLIES(rx_multicast_octets);
00034 ADD_COMM_TALLIES(rx_fcs_errors);
00035 ADD_COMM_TALLIES(rx_discards_no_buffer);
00036 ADD_COMM_TALLIES(tx_discards_wrong_sa);
00037 ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
00038 ADD_COMM_TALLIES(rx_message_in_msg_fragments);
00039 ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
00040 #undef ADD_COMM_TALLIES
00041 }
00042
00043
00044
00045 static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
00046 int left)
00047 {
00048 struct hfa384x_comm_tallies32 *tallies;
00049
00050 if (left < sizeof(struct hfa384x_comm_tallies32)) {
00051 printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
00052 "info frame\n", local->dev->name, left);
00053 return;
00054 }
00055
00056 tallies = (struct hfa384x_comm_tallies32 *) buf;
00057 #define ADD_COMM_TALLIES(name) \
00058 local->comm_tallies.name += le32_to_cpu(tallies->name)
00059 ADD_COMM_TALLIES(tx_unicast_frames);
00060 ADD_COMM_TALLIES(tx_multicast_frames);
00061 ADD_COMM_TALLIES(tx_fragments);
00062 ADD_COMM_TALLIES(tx_unicast_octets);
00063 ADD_COMM_TALLIES(tx_multicast_octets);
00064 ADD_COMM_TALLIES(tx_deferred_transmissions);
00065 ADD_COMM_TALLIES(tx_single_retry_frames);
00066 ADD_COMM_TALLIES(tx_multiple_retry_frames);
00067 ADD_COMM_TALLIES(tx_retry_limit_exceeded);
00068 ADD_COMM_TALLIES(tx_discards);
00069 ADD_COMM_TALLIES(rx_unicast_frames);
00070 ADD_COMM_TALLIES(rx_multicast_frames);
00071 ADD_COMM_TALLIES(rx_fragments);
00072 ADD_COMM_TALLIES(rx_unicast_octets);
00073 ADD_COMM_TALLIES(rx_multicast_octets);
00074 ADD_COMM_TALLIES(rx_fcs_errors);
00075 ADD_COMM_TALLIES(rx_discards_no_buffer);
00076 ADD_COMM_TALLIES(tx_discards_wrong_sa);
00077 ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
00078 ADD_COMM_TALLIES(rx_message_in_msg_fragments);
00079 ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
00080 #undef ADD_COMM_TALLIES
00081 }
00082
00083
00084
00085 static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
00086 int left)
00087 {
00088 if (local->tallies32)
00089 prism2_info_commtallies32(local, buf, left);
00090 else
00091 prism2_info_commtallies16(local, buf, left);
00092 }
00093
00094
00095 #ifndef PRISM2_NO_STATION_MODES
00096 #ifndef PRISM2_NO_DEBUG
00097 static const char* hfa384x_linkstatus_str(u16 linkstatus)
00098 {
00099 switch (linkstatus) {
00100 case HFA384X_LINKSTATUS_CONNECTED:
00101 return "Connected";
00102 case HFA384X_LINKSTATUS_DISCONNECTED:
00103 return "Disconnected";
00104 case HFA384X_LINKSTATUS_AP_CHANGE:
00105 return "Access point change";
00106 case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
00107 return "Access point out of range";
00108 case HFA384X_LINKSTATUS_AP_IN_RANGE:
00109 return "Access point in range";
00110 case HFA384X_LINKSTATUS_ASSOC_FAILED:
00111 return "Association failed";
00112 default:
00113 return "Unknown";
00114 }
00115 }
00116 #endif
00117
00118
00119
00120 static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
00121 int left)
00122 {
00123 u16 val;
00124 int non_sta_mode;
00125
00126
00127
00128 local->last_join_time = 0;
00129
00130 if (left != 2) {
00131 printk(KERN_DEBUG "%s: invalid linkstatus info frame "
00132 "length %d\n", local->dev->name, left);
00133 return;
00134 }
00135
00136 non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
00137 local->iw_mode == IW_MODE_REPEAT ||
00138 local->iw_mode == IW_MODE_MONITOR;
00139
00140 val = buf[0] | (buf[1] << 8);
00141 if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
00142 PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
00143 local->dev->name, val, hfa384x_linkstatus_str(val));
00144 }
00145
00146 if (non_sta_mode)
00147 return;
00148
00149
00150 set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
00151 local->prev_link_status = val;
00152 PRISM2_SCHEDULE_TASK(&local->info_queue);
00153 }
00154
00155
00156 static void prism2_host_roaming(local_info_t *local)
00157 {
00158 struct hfa384x_join_request req;
00159 struct net_device *dev = local->dev;
00160 struct hfa384x_scan_result *selected, *entry;
00161 int i;
00162 unsigned long flags;
00163
00164 if (local->last_join_time &&
00165 time_before(jiffies, local->last_join_time + 10 * HZ)) {
00166 PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
00167 "completed - waiting for it before issuing new one\n",
00168 dev->name);
00169 return;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 spin_lock_irqsave(&local->lock, flags);
00181 if (local->last_scan_results == NULL ||
00182 local->last_scan_results_count == 0) {
00183 spin_unlock_irqrestore(&local->lock, flags);
00184 PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
00185 dev->name);
00186 return;
00187 }
00188
00189 selected = &local->last_scan_results[0];
00190
00191 if (local->preferred_ap[0] || local->preferred_ap[1] ||
00192 local->preferred_ap[2] || local->preferred_ap[3] ||
00193 local->preferred_ap[4] || local->preferred_ap[5]) {
00194
00195 PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n",
00196 dev->name, MAC2STR(local->preferred_ap));
00197 for (i = 0; i < local->last_scan_results_count; i++) {
00198 entry = &local->last_scan_results[i];
00199 if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
00200 {
00201 PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
00202 "selection\n", dev->name);
00203 selected = entry;
00204 break;
00205 }
00206 }
00207 }
00208
00209 memcpy(req.bssid, selected->bssid, 6);
00210 req.channel = selected->chid;
00211 spin_unlock_irqrestore(&local->lock, flags);
00212
00213 PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n",
00214 dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel));
00215 if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
00216 sizeof(req))) {
00217 printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
00218 }
00219 local->last_join_time = jiffies;
00220 }
00221
00222
00223 #if WIRELESS_EXT > 13
00224 static void hostap_report_scan_complete(local_info_t *local)
00225 {
00226 union iwreq_data wrqu;
00227
00228
00229
00230 wrqu.data.length = 0;
00231 wrqu.data.flags = 0;
00232 wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
00233
00234
00235
00236 local->scan_timestamp = 0;
00237 }
00238 #else
00239 static inline void hostap_report_scan_complete(local_info_t *local)
00240 {
00241 }
00242 #endif
00243
00244
00245
00246 static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
00247 int left)
00248 {
00249 u16 *pos;
00250 int new_count;
00251 unsigned long flags;
00252 struct hfa384x_scan_result *results, *prev;
00253
00254 if (left < 4) {
00255 printk(KERN_DEBUG "%s: invalid scanresult info frame "
00256 "length %d\n", local->dev->name, left);
00257 return;
00258 }
00259
00260 pos = (u16 *) buf;
00261 pos++;
00262 pos++;
00263 left -= 4;
00264
00265 new_count = left / sizeof(struct hfa384x_scan_result);
00266 results = kmalloc(new_count * sizeof(struct hfa384x_scan_result),
00267 GFP_ATOMIC);
00268 if (results == NULL)
00269 return;
00270 memcpy(results, pos, new_count * sizeof(struct hfa384x_scan_result));
00271
00272 spin_lock_irqsave(&local->lock, flags);
00273 local->last_scan_type = PRISM2_SCAN;
00274 prev = local->last_scan_results;
00275 local->last_scan_results = results;
00276 local->last_scan_results_count = new_count;
00277 spin_unlock_irqrestore(&local->lock, flags);
00278 kfree(prev);
00279
00280 hostap_report_scan_complete(local);
00281
00282
00283 set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
00284 PRISM2_SCHEDULE_TASK(&local->info_queue);
00285 }
00286
00287
00288
00289 static void prism2_info_hostscanresults(local_info_t *local,
00290 unsigned char *buf, int left)
00291 {
00292 int i, result_size, copy_len, new_count;
00293 struct hfa384x_hostscan_result *results, *prev;
00294 unsigned long flags;
00295 u16 *pos;
00296 u8 *ptr;
00297
00298 wake_up_interruptible(&local->hostscan_wq);
00299
00300 if (left < 4) {
00301 printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
00302 "length %d\n", local->dev->name, left);
00303 return;
00304 }
00305
00306 pos = (u16 *) buf;
00307 copy_len = result_size = le16_to_cpu(*pos);
00308 if (result_size == 0) {
00309 printk(KERN_DEBUG "%s: invalid result_size (0) in "
00310 "hostscanresults\n", local->dev->name);
00311 return;
00312 }
00313 if (copy_len > sizeof(struct hfa384x_hostscan_result))
00314 copy_len = sizeof(struct hfa384x_hostscan_result);
00315
00316 pos++;
00317 pos++;
00318 left -= 4;
00319 ptr = (u8 *) pos;
00320
00321 new_count = left / result_size;
00322 results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
00323 GFP_ATOMIC);
00324 if (results == NULL)
00325 return;
00326 memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result));
00327
00328 for (i = 0; i < new_count; i++) {
00329 memcpy(&results[i], ptr, copy_len);
00330 ptr += result_size;
00331 left -= result_size;
00332 }
00333
00334 if (left) {
00335 printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
00336 local->dev->name, left, result_size);
00337 }
00338
00339 spin_lock_irqsave(&local->lock, flags);
00340 local->last_scan_type = PRISM2_HOSTSCAN;
00341 prev = local->last_hostscan_results;
00342 local->last_hostscan_results = results;
00343 local->last_hostscan_results_count = new_count;
00344 spin_unlock_irqrestore(&local->lock, flags);
00345 kfree(prev);
00346
00347 hostap_report_scan_complete(local);
00348 }
00349 #endif
00350
00351
00352
00353 void hostap_info_process(local_info_t *local, struct sk_buff *skb)
00354 {
00355 struct hfa384x_info_frame *info;
00356 unsigned char *buf;
00357 int left;
00358 #ifndef PRISM2_NO_DEBUG
00359 int i;
00360 #endif
00361
00362 info = (struct hfa384x_info_frame *) skb->data;
00363 buf = skb->data + sizeof(*info);
00364 left = skb->len - sizeof(*info);
00365
00366 switch (info->type) {
00367 case HFA384X_INFO_COMMTALLIES:
00368 prism2_info_commtallies(local, buf, left);
00369 break;
00370
00371 #ifndef PRISM2_NO_STATION_MODES
00372 case HFA384X_INFO_LINKSTATUS:
00373 prism2_info_linkstatus(local, buf, left);
00374 break;
00375
00376 case HFA384X_INFO_SCANRESULTS:
00377 prism2_info_scanresults(local, buf, left);
00378 break;
00379
00380 case HFA384X_INFO_HOSTSCANRESULTS:
00381 prism2_info_hostscanresults(local, buf, left);
00382 break;
00383 #endif
00384
00385 #ifndef PRISM2_NO_DEBUG
00386 default:
00387 PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
00388 local->dev->name, info->len, info->type);
00389 PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
00390 for (i = 0; i < (left < 100 ? left : 100); i++)
00391 PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
00392 PDEBUG2(DEBUG_EXTRA, "\n");
00393 break;
00394 #endif
00395 }
00396 }
00397
00398
00399 #ifndef PRISM2_NO_STATION_MODES
00400 static void handle_info_queue_linkstatus(local_info_t *local)
00401 {
00402 int val = local->prev_link_status;
00403 int connected;
00404
00405 connected =
00406 val == HFA384X_LINKSTATUS_CONNECTED ||
00407 val == HFA384X_LINKSTATUS_AP_CHANGE ||
00408 val == HFA384X_LINKSTATUS_AP_IN_RANGE;
00409
00410 if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
00411 local->bssid, ETH_ALEN, 1) < 0) {
00412 printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
00413 "LinkStatus event\n", local->dev->name);
00414 } else {
00415 PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n",
00416 local->dev->name,
00417 MAC2STR((unsigned char *) local->bssid));
00418 if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
00419 hostap_add_sta(local->ap, local->bssid);
00420 }
00421
00422 #if WIRELESS_EXT > 13
00423 {
00424 union iwreq_data wrqu;
00425
00426
00427 if (connected)
00428 memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
00429 else
00430 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
00431 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
00432 wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
00433 }
00434 #endif
00435 }
00436
00437
00438 static void handle_info_queue_scanresults(local_info_t *local)
00439 {
00440 if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
00441 prism2_host_roaming(local);
00442 }
00443
00444
00445
00446
00447 static void handle_info_queue(void *data)
00448 {
00449 local_info_t *local = (local_info_t *) data;
00450
00451 if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
00452 &local->pending_info))
00453 handle_info_queue_linkstatus(local);
00454
00455 if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
00456 &local->pending_info))
00457 handle_info_queue_scanresults(local);
00458
00459 #ifndef NEW_MODULE_CODE
00460 MOD_DEC_USE_COUNT;
00461 #endif
00462 }
00463 #endif
00464
00465
00466 void hostap_info_init(local_info_t *local)
00467 {
00468 skb_queue_head_init(&local->info_list);
00469 #ifndef PRISM2_NO_STATION_MODES
00470 INIT_WORK(&local->info_queue, handle_info_queue, local);
00471 #endif
00472 }
00473
00474
00475 EXPORT_SYMBOL(hostap_info_init);
00476 EXPORT_SYMBOL(hostap_info_process);