Warning, cross-references for /kernel/drivers/net/mac80211.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <kernel.h>
0022 #include <drivers/net/ieee80211.h>
0023 #include <drivers/net/mac80211.h>
0024 #include <drivers/net/ieee80211_standard.h>
0025 #include <drivers/net/ethernet.h>
0026 #include <util/debug.h>
0027 #include <mem/pow2.h>
0028 #include <sched/sched.h>
0029 #include <arch/i386.h>
0030 #include <string.h>
0031
0032 typedef uint8 ethaddr_t[ETH_ADDR_LEN];
0033 #define SSID "quest"
0034 ethaddr_t quest_bssid = {
0035 0xb6, 0x27, 0x07, 0xb6, 0x73, 0x7E
0036 };
0037 #define TIME_UNIT 1024
0038
0039 #define DEBUG_MAC80211
0040
0041 #ifdef DEBUG_MAC80211
0042 #define DLOG(fmt,...) DLOG_PREFIX("mac80211",fmt,##__VA_ARGS__)
0043 #else
0044 #define DLOG(fmt,...) ;
0045 #endif
0046
0047
0048 #define MAX_MACS 4
0049
0050 struct ieee80211_local {
0051 struct ieee80211_hw hw;
0052 const struct ieee80211_ops *ops;
0053 ethernet_device ethdev;
0054 char *ssid;
0055 u64 prev_time_update;
0056 struct ieee80211_vif vif;
0057 char priv[0] ALIGNED(32);
0058 };
0059 typedef struct ieee80211_local local_t;
0060
0061 static inline struct ieee80211_local *
0062 hw_to_local(struct ieee80211_hw *hw)
0063 {
0064 return container_of(hw, struct ieee80211_local, hw);
0065 }
0066
0067 static inline struct ieee80211_hw *
0068 local_to_hw(struct ieee80211_local *local)
0069 {
0070 return &local->hw;
0071 }
0072
0073 struct wiphy *
0074 wiphy_new (int sizeof_priv)
0075 {
0076 int sz = sizeof_priv + sizeof (struct wiphy);
0077 struct wiphy *wiphy;
0078 if (pow2_alloc (sz, (u8 **)&wiphy))
0079 return wiphy;
0080 else
0081 return NULL;
0082 }
0083
0084 struct ieee80211_hw *
0085 ieee80211_alloc_hw (size_t priv_data_len,
0086 const struct ieee80211_ops *ops)
0087 {
0088 local_t *local;
0089 struct wiphy *wiphy;
0090
0091 wiphy = wiphy_new (priv_data_len + sizeof (local_t));
0092 if (!wiphy) return NULL;
0093
0094 local = (void *)wiphy->priv;
0095
0096 local->ops = ops;
0097
0098 return &local->hw;
0099 }
0100
0101 static int num_macs = 0;
0102 static local_t *hw_table[MAX_MACS];
0103
0104 static struct ieee80211_channel channels[] = {
0105 { .center_freq = 2412 },
0106 { .center_freq = 2417 },
0107 { .center_freq = 2422 },
0108 { .center_freq = 2427 },
0109 { .center_freq = 2432 },
0110 { .center_freq = 2437 },
0111 { .center_freq = 2442 },
0112 { .center_freq = 2447 },
0113 { .center_freq = 2452 },
0114 { .center_freq = 2457 },
0115 { .center_freq = 2462 },
0116 { .center_freq = 2467 },
0117 { .center_freq = 2472 },
0118 { .center_freq = 2484 },
0119 };
0120
0121 static uint32 beacon_stack[1024] ALIGNED(0x1000);
0122 static void beacon_thread (local_t *);
0123 local_t *hack_local = NULL;
0124 sint mac80211_tx (uint8* buffer, sint len);
0125 bool mac80211_get_hwaddr (uint8 addr[ETH_ADDR_LEN]);
0126 void mac80211_poll (void);
0127 static void init_tsc_ufreq (void);
0128
0129 bool
0130 ieee80211_register_hw (struct ieee80211_hw *hw)
0131 {
0132 local_t *local = hw_to_local (hw);
0133 struct ieee80211_if_init_conf if_conf;
0134 struct ieee80211_tx_queue_params tx_q_p = {
0135 .txop = 94,
0136 .cw_min = 7,
0137 .cw_max = 15,
0138 .aifs = 2
0139 };
0140
0141 if (num_macs < MAX_MACS) {
0142 hw_table[num_macs] = local;
0143 num_macs++;
0144 } else return FALSE;
0145
0146
0147
0148 DLOG ("register_hw: initialize");
0149 if (!local->ops->add_interface (hw, &if_conf))
0150 return FALSE;
0151
0152 local->ops->conf_tx (hw, 0, &tx_q_p);
0153 local->ops->conf_tx (hw, 1, &tx_q_p);
0154 local->ops->conf_tx (hw, 2, &tx_q_p);
0155 local->ops->conf_tx (hw, 3, &tx_q_p);
0156
0157 if (!local->ops->start (hw))
0158 return FALSE;
0159
0160 hw->conf.channel = &channels[0];
0161
0162 if (!local->ops->config (hw, 0))
0163 return FALSE;
0164
0165 local->vif.bss_conf.bssid = quest_bssid;
0166 local->vif.bss_conf.timestamp = 0;
0167 local->vif.bss_conf.beacon_int = 0x64;
0168 local->vif.bss_conf.assoc_capability = 0x22;
0169 local->ssid = SSID;
0170
0171 local->ethdev.recv_func = NULL;
0172 local->ethdev.send_func = mac80211_tx;
0173 local->ethdev.get_hwaddr_func = mac80211_get_hwaddr;
0174 local->ethdev.poll_func = mac80211_poll;
0175 hack_local = local;
0176 if (!net_register_device (&local->ethdev)) {
0177 DLOG ("registration failed");
0178 return FALSE;
0179 }
0180
0181 init_tsc_ufreq ();
0182
0183 create_kernel_thread_args ((u32) beacon_thread, (u32) &beacon_stack[1023],
0184 TRUE, 1, local);
0185
0186 return TRUE;
0187 }
0188
0189
0190
0191 static u32 tsc_ufreq;
0192 extern u64 tsc_freq;
0193
0194 static void
0195 init_tsc_ufreq (void)
0196 {
0197 u64 f;
0198 u32 f_hi, f_lo;
0199 u32 divisor = 1000000;
0200 f = tsc_freq;
0201
0202 f_hi = (u32) (f >> 32);
0203 f_lo = (u32) (f & 0xFFFFFFFF);
0204 asm volatile ("div %1":"=a" (tsc_ufreq):"r" (divisor),"a" (f_lo),"d" (f_hi));
0205
0206 DLOG ("tsc_ufreq=%d", tsc_ufreq);
0207 }
0208
0209 static void
0210 update_timestamp (local_t *local)
0211 {
0212 u64 new_time_update, diff;
0213 RDTSC (new_time_update);
0214 if (local->prev_time_update == 0) {
0215 local->prev_time_update = new_time_update;
0216 } else {
0217 diff = new_time_update - local->prev_time_update;
0218 u32 f_hi, f_lo, udiff;
0219 f_hi = (u32) (diff >> 32);
0220 f_lo = (u32) (diff & 0xFFFFFFFF);
0221 asm volatile ("div %1":"=a" (udiff):"r" (tsc_ufreq),"a" (f_lo),"d" (f_hi));
0222 local->vif.bss_conf.timestamp += udiff;
0223 }
0224 }
0225
0226
0227
0228 #if 0
0229 static bool
0230 make_mgmt_pkt (u8 subtype, u8 control,
0231 ethaddr_t da, ethaddr_t sa, ethaddr_t bssid);
0232 #endif
0233
0234 static u8 *insert_eid (u8 *ptr, u8 eid, u8 len, void *data)
0235 {
0236 *(ptr++) = eid;
0237 *(ptr++) = len;
0238 memcpy (ptr, data, len);
0239 return ptr + len;
0240 }
0241
0242 static u32
0243 make_beacon_pkt (local_t *local,
0244 ethaddr_t sa,
0245 u8 *rates, u8 rates_len,
0246 u8 chan,
0247 u8 *buf, u32 len)
0248 {
0249 uint8 *bssid = local->vif.bss_conf.bssid;
0250 char *ssid = local->ssid;
0251 struct ieee80211_mgmt *m = (struct ieee80211_mgmt *)buf;
0252 int i;
0253 u8 *ptr, ssid_len = strlen (ssid);
0254 u32 req = ((u32) m->u.beacon.variable - (u32) m)
0255 + 2 + ssid_len + 2 + rates_len + 3;
0256
0257 if (len < req) return req;
0258
0259 m->frame_control =
0260 IEEE80211_FTYPE_MGMT |
0261 IEEE80211_STYPE_BEACON;
0262 m->duration = 0;
0263 for (i=0;i<ETH_ADDR_LEN;i++) {
0264 m->da[i] = 0xFF;
0265 m->sa[i] = sa[i];
0266 m->bssid[i] = bssid[i];
0267 }
0268 m->u.beacon.timestamp = local->vif.bss_conf.timestamp;
0269 m->u.beacon.beacon_int = local->vif.bss_conf.beacon_int;
0270 m->u.beacon.capab_info = local->vif.bss_conf.assoc_capability;
0271 ptr = m->u.beacon.variable;
0272 ptr = insert_eid (ptr, WLAN_EID_SSID, ssid_len, ssid);
0273 ptr = insert_eid (ptr, WLAN_EID_SUPP_RATES, rates_len, rates);
0274 ptr = insert_eid (ptr, WLAN_EID_DS_PARAMS, 1, &chan);
0275
0276 return req;
0277 }
0278
0279 static u32
0280 make_probe_req_pkt (ethaddr_t sa, ethaddr_t bssid,
0281 char *ssid,
0282 u8 *rates, u8 rates_len,
0283 u8 *buf, u32 len)
0284 {
0285 struct ieee80211_mgmt *m = (struct ieee80211_mgmt *)buf;
0286 int i;
0287 u8 *ptr, ssid_len = strlen (ssid);
0288 u32 req = ((u32) m->u.probe_req.variable - (u32) m)
0289 + 2 + ssid_len + 2 + rates_len;
0290
0291 if (len < req) return req;
0292
0293 m->frame_control =
0294 IEEE80211_FTYPE_MGMT |
0295 IEEE80211_STYPE_PROBE_REQ;
0296 m->duration = 0x013A;
0297 for (i=0;i<ETH_ADDR_LEN;i++) {
0298 m->da[i] = 0xFF;
0299 m->sa[i] = sa[i];
0300 m->bssid[i] = bssid[i];
0301 }
0302 m->seq_ctrl = 0x4640;
0303 ptr = m->u.probe_req.variable;
0304 ptr = insert_eid (ptr, WLAN_EID_SSID, ssid_len, ssid);
0305 ptr = insert_eid (ptr, WLAN_EID_SUPP_RATES, rates_len, rates);
0306
0307 return req;
0308 }
0309
0310 static u32
0311 make_ack_pkt (ethaddr_t ra, u8 *buf, u32 len)
0312 {
0313 struct ieee80211_hdr *h = (struct ieee80211_hdr *) buf;
0314 int i;
0315 if (len < 10) return 10;
0316 h->frame_control =
0317 IEEE80211_FTYPE_CTL |
0318 IEEE80211_STYPE_ACK;
0319 h->duration_id = 0;
0320 for (i=0; i<ETH_ADDR_LEN; i++)
0321 h->addr1[i] = ra[i];
0322 return 10;
0323 }
0324
0325 static uint8 rates[8] = {
0326 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
0327 };
0328
0329 static void
0330 tx_beacon (struct ieee80211_local *local)
0331 {
0332 uint8 pkt[128];
0333 ethaddr_t sa = {
0334 0x00, 0x1E, 0x2A, 0x42, 0x73, 0x7E
0335 };
0336 u32 len = make_beacon_pkt (local, sa, rates, 8, 1, pkt, 128);
0337 if (len > 128) { DLOG ("make_beacon_pkt wants %d bytes", len); return; }
0338 struct sk_buff skb = {
0339 .data = pkt,
0340 .len = len,
0341 };
0342 local->ops->tx (local_to_hw (local), &skb);
0343 }
0344
0345 static void
0346 beacon_thread (local_t *local)
0347 {
0348 DLOG ("beacon: hello from 0x%x", str ());
0349 for (;;) {
0350 sched_usleep (1000000);
0351 DLOG ("sending beacon timestamp=0x%.08X %.08X",
0352 (u32) (local->vif.bss_conf.timestamp >> 32),
0353 (u32) local->vif.bss_conf.timestamp);
0354 tx_beacon (local);
0355 }
0356 }
0357
0358 static bool
0359 find_eid (struct ieee80211_mgmt *m, s32 len, u8 eid,
0360 u8 *output, u8 max_len, u8 *act_len)
0361 {
0362
0363 uint8 *ptr;
0364 u32 hdr_len;
0365 #define CASE(x) \
0366 if (ieee80211_is_##x (m->frame_control)) { \
0367 ptr = m->u.x.variable; \
0368 hdr_len = ((u32) m->u.x.variable) - ((u32) m); \
0369 }
0370 CASE(beacon);
0371 CASE(probe_req);
0372 CASE(probe_resp);
0373 CASE(assoc_req);
0374 CASE(assoc_resp);
0375 #undef CASE
0376
0377 len -= hdr_len;
0378 for (;len > 0;) {
0379
0380 if (ptr[0] == eid) {
0381 if (ptr[1] > max_len) {
0382 return FALSE;
0383 } if (ptr[1] + 2 > len) {
0384 return FALSE;
0385 } else {
0386 memcpy (output, &ptr[2], ptr[1]);
0387 *act_len = ptr[1];
0388 return TRUE;
0389 }
0390 }
0391 len -= (ptr[1] + 2);
0392 ptr += (ptr[1] + 2);
0393 }
0394 return FALSE;
0395 }
0396
0397 static void
0398 tx_probe_resp (struct ieee80211_local *local)
0399 {
0400 uint8 pkt[] = {
0401 0x50, 0x00, 0x3A, 0x01,
0402 0x00, 0x23, 0x4D, 0xAF, 0x00, 0x3C,
0403
0404
0405
0406 0x00, 0x1E, 0x2A, 0x42, 0x73, 0x7E,
0407 0xb6, 0x27, 0x07, 0xb6, 0x73, 0x7E,
0408
0409 0x20, 0x00,
0410
0411 0x8E, 0x91, 0x42, 0x11, 0x67, 0x00, 0x00, 0x00,
0412 0x64, 0x00,
0413 0x01, 0x04,
0414
0415 0x00, 0x05, 'q', 'u', 'e', 's', 't',
0416
0417 0x01, 0x08, 0x82, 0x84, 0x8B, 0x96, 0x0C, 0x12, 0x18, 0x24
0418 };
0419 struct sk_buff skb = {
0420 .data = pkt,
0421 .len = sizeof (pkt)
0422 };
0423 struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) pkt;
0424 m->u.probe_resp.timestamp = __cpu_to_le64 (local->vif.bss_conf.timestamp);
0425 local->ops->tx (local_to_hw (local), &skb);
0426 }
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478 static void
0479 debug_buf (char *prefix, uint8 *buf, u32 len)
0480 {
0481 s32 i, j;
0482
0483 for (i=0;i<len;i+=8) {
0484 logger_printf ("%s: ", prefix);
0485 for (j=0;j<8;j++) {
0486 if (i+j >= len) break;
0487 logger_printf ("%.02X ", buf[i+j]);
0488 }
0489 logger_printf ("\n");
0490 }
0491 }
0492
0493 extern void
0494 ieee80211_rx (struct ieee80211_hw *hw, struct sk_buff *skb)
0495 {
0496 local_t *local = hw_to_local (hw);
0497 struct ieee80211_hdr *hdr;
0498 char ssid[IEEE80211_MAX_SSID_LEN+1];
0499 u8 act_len;
0500 u8 pkt[128];
0501 u32 len, i;
0502 ethaddr_t sa = {
0503 0x00, 0x1E, 0x2A, 0x42, 0x73, 0x7E
0504 };
0505 ethaddr_t bssid = {
0506 0xB6, 0x27, 0x07, 0xB6, 0x73, 0x7E
0507 };
0508
0509 update_timestamp (local);
0510
0511 hdr = (struct ieee80211_hdr *)skb->data;
0512
0513 if (ieee80211_is_mgmt (hdr->frame_control)) {
0514 struct ieee80211_mgmt *m = (struct ieee80211_mgmt *)skb->data;
0515 if (ieee80211_is_beacon (hdr->frame_control)) {
0516 if (find_eid (m, skb->len, WLAN_EID_SSID,
0517 (u8 *)ssid, IEEE80211_MAX_SSID_LEN, &act_len)) {
0518 ssid[act_len] = 0;
0519
0520 if (strncmp (SSID, ssid, act_len) == 0) {
0521 local->vif.bss_conf.timestamp = m->u.beacon.timestamp + TIME_UNIT;
0522 local->vif.bss_conf.beacon_int = m->u.beacon.beacon_int;
0523 local->vif.bss_conf.assoc_capability = m->u.beacon.capab_info;
0524 DLOG ("beacon %s; synchronizing beacon_int=0x%x capab=0x%x",
0525 ssid, local->vif.bss_conf.beacon_int,
0526 local->vif.bss_conf.assoc_capability);
0527 DLOG (" new timestamp=0x%.08X %.08X",
0528 (u32) (local->vif.bss_conf.timestamp >> 32),
0529 (u32) local->vif.bss_conf.timestamp);
0530 }
0531 #if 0
0532 len = make_probe_req_pkt (sa, m->bssid, ssid, rates, 8,
0533 pkt, sizeof (pkt));
0534 if (len <= sizeof (pkt)) {
0535 struct sk_buff skb = {
0536 .data = pkt,
0537 .len = len,
0538 };
0539 local->ops->tx (local_to_hw (local), &skb);
0540 }
0541 #endif
0542 } else {
0543
0544 }
0545 } else if (ieee80211_is_probe_req (hdr->frame_control)) {
0546 if (find_eid (m, skb->len, WLAN_EID_SSID,
0547 (u8 *)ssid, IEEE80211_MAX_SSID_LEN, &act_len)) {
0548 ssid[act_len] = 0;
0549 DLOG ("probe_req %s", ssid);
0550 if (strncmp (SSID, ssid, act_len) == 0) {
0551 tx_probe_resp (local);
0552 }
0553 } else {
0554 DLOG ("probe_req, no SSID");
0555 }
0556 } else if (ieee80211_is_probe_resp (hdr->frame_control)) {
0557 if (find_eid (m, skb->len, WLAN_EID_SSID,
0558 (u8 *)ssid, IEEE80211_MAX_SSID_LEN, &act_len)) {
0559 ssid[act_len] = 0;
0560 DLOG ("probe_resp %s", ssid);
0561 } else {
0562 DLOG ("probe_resp, no SSID");
0563 }
0564 len = make_ack_pkt (m->sa, pkt, sizeof (pkt));
0565 if (len <= sizeof (pkt)) {
0566 struct sk_buff skb = {
0567 .data = pkt,
0568 .len = len,
0569 };
0570 local->ops->tx (local_to_hw (local), &skb);
0571 }
0572 }
0573 } else if (ieee80211_is_data (hdr->frame_control)) {
0574 if ((hdr->seq_ctrl & 0xF) == 0) {
0575 DLOG ("data for %.02X:%.02X:%.02X:%.02X:%.02X:%.02X",
0576 hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
0577 hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
0578 for (i=0; i<ETH_ADDR_LEN; i++)
0579 if (hdr->addr3[i] != bssid[i])
0580 return;
0581 #ifdef DEBUG_MAC80211
0582 debug_buf ("mac80211: data", skb->data, skb->len);
0583 #endif
0584
0585 memcpy (skb->data + 18, skb->data + 4, ETH_ADDR_LEN);
0586 memcpy (skb->data + 24, skb->data + 10, ETH_ADDR_LEN);
0587 local->ethdev.recv_func (&local->ethdev,
0588 skb->data + 18,
0589 skb->len - 18);
0590 }
0591 } else if (ieee80211_is_ctl (hdr->frame_control)) {
0592 if (ieee80211_is_ack (hdr->frame_control)) {
0593 DLOG ("ack");
0594 }
0595 }
0596 }
0597
0598
0599 static u8 tx_buf[2500];
0600
0601 sint
0602 mac80211_tx (uint8* buffer, sint len)
0603 {
0604 struct ieee80211_hw *hw = local_to_hw (hack_local);
0605 bool is_arp=FALSE;
0606 u8 hdr[] = {
0607 0x08, 0x00, 0x3a, 0x01,
0608 0x00, 0x23, 0x4d, 0xaf, 0x00, 0x3c,
0609 0x00, 0x1e, 0x2a, 0x42, 0x73, 0x7e,
0610 0xb6, 0x27, 0x07, 0xb6, 0x73, 0x7e,
0611 0x90, 0x94,
0612
0613 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00,
0614
0615
0616
0617 0x08, 0x00
0618 };
0619
0620
0621 len -= 14;
0622 buffer += 14;
0623
0624 DLOG ("mac80211_tx: %p %d bytes: %x %x", buffer, len, buffer[0], buffer[1]);
0625 if (buffer[0] == 0 && buffer[1] == 1)
0626 is_arp = TRUE;
0627
0628 struct sk_buff skb = {
0629 .data = tx_buf,
0630 .len = len + sizeof (hdr)
0631 };
0632 memcpy (tx_buf, hdr, sizeof (hdr));
0633 memcpy (tx_buf + sizeof (hdr), buffer, len);
0634 if (is_arp) tx_buf[sizeof (hdr) - 1] = 6;
0635
0636 return hack_local->ops->tx (hw, &skb);
0637 }
0638
0639 bool
0640 mac80211_get_hwaddr (uint8 addr[ETH_ADDR_LEN])
0641 {
0642 int i;
0643
0644 ethaddr_t sa = {
0645 0x00, 0x1E, 0x2A, 0x42, 0x73, 0x7E
0646 };
0647
0648 for (i=0; i<ETH_ADDR_LEN; i++)
0649 addr[i] = sa[i];
0650 return TRUE;
0651 }
0652
0653 void
0654 mac80211_poll (void)
0655 {
0656 }
0657
0658 u16
0659 ieee80211_calc_duration (u32 len, s16 rate)
0660 {
0661 u16 duration;
0662 u16 drift;
0663 switch (rate) {
0664 case 0:
0665 duration = ((len+4)<<4) / 0x2;
0666 drift = ((len+4)<<4) % 0x2;
0667 if (drift == 0) break;
0668 duration++;
0669 break;
0670
0671 case 1:
0672 duration = ((len+4)<<4) / 0x4;
0673 drift = ((len+4)<<4) % 0x4;
0674 if (drift == 0) break;
0675 duration++;
0676 break;
0677
0678 case 2:
0679 duration = ((len+4)<<4) / 0xb;
0680 drift = ((len+4)<<4) % 0xb;
0681 if (drift == 0) break;
0682 duration++;
0683 break;
0684
0685 default:
0686 case 3:
0687 duration = ((len+4)<<4) / 0x16;
0688 drift = ((len+4)<<4) % 0x16;
0689 if (drift == 0) break;
0690 duration++;
0691 break;
0692 }
0693
0694 return duration;
0695 }
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708