📄 am930mac.c
字号:
DBFENTER; if ( mac->hw != NULL ) { am930hw_ISR( mac->hw ); } DBFEXIT;}/*----------------------------------------------------------------* am930mac_mk_capinfo** Uses the MIB and the current MAC state variables to construct* a cap_info halfword. The value returned is in HOST order!** Arguments:* none** returns: * The capinfo halfword in HOST order!----------------------------------------------------------------*/UINT16 am930mac_mk_capinfo(am930mac_t *mac){ UINT16 capinfo = 0; if ( mac->mode == AM930_MACMODE_ESS_STA || mac->mode == AM930_MACMODE_ESS_AP ) { capinfo |= WLAN_SET_MGMT_CAP_INFO_ESS(1); } else if ( mac->mode == AM930_MACMODE_IBSS_STA ) { capinfo |= WLAN_SET_MGMT_CAP_INFO_IBSS(1); } if ( mac->exclude_unencrypted ) { capinfo |= WLAN_SET_MGMT_CAP_INFO_PRIVACY(1); } return capinfo;}/*----------------------------------------------------------------* am930mac_ontxcomplete** Callback from hw when tx is signaled complete.** returns: nothing----------------------------------------------------------------*/void am930mac_ontxcomplete( am930mac_t *mac, UINT32 txresult ){ UINT32 txdone = 1; wlan_pb_t *pb = NULL; am930q_t *q; int i = 0; DBFENTER; do { WLAN_LOG_DEBUG3( 3,"nextq=%x llcq.len=%d macq.len=%d\n", mac->nextq, am930q_length(mac->llcq), am930q_length(mac->macq)); q = NULL; if ( am930q_length(mac->llcq) > 0 && am930q_length(mac->macq) > 0 ) { q = mac->nextq & 0x01 ? mac->llcq : mac->macq; } else if ( am930q_length(mac->llcq) > 0 ) { q = mac->llcq; } else if ( am930q_length(mac->macq) > 0 ) { q = mac->macq; } if ( q != NULL ) { pb = (wlan_pb_t*)am930q_dequeue(q); if ( pb != NULL ) { txdone = am930hw_txdata( mac->hw, pb, mac->mgr->curr_rate); am930shim_pbfree(pb); pb = NULL; } else { txdone = 1; } } mac->nextq ^= 1; } while( q != NULL && txdone == 0 && i++ < 4);#if (WLAN_OS == WLAN_LINUX_KERNEL) if ( txresult != 0xffffffff ) { am930shim_ontxcomplete( mac->llc, txresult); }#elif (WLAN_OS == WLAN_LWOS) am930shim_ontxcomplete( mac->llc, txresult);#else #error "No WLAN_OS match!"#endif DBFEXIT; return;}/*----------------------------------------------------------------* am930mac_rxdata** Private helper for the rxframe method.** returns: nothing----------------------------------------------------------------*/void am930mac_rxdata( am930mac_t *mac, wlan_pb_t *pb, am930rxstats_t *stats){ wlan_pb_t *pb2; /* a clone */ DBFENTER; if ( mac->mode != AM930_MACMODE_ESS_AP ) { am930shim_rxframe( mac->llc, pb); } else { int isme; int isgroup; wlan_stable_item_t *sta = NULL; isme = (memcmp(pb->p80211_hdr->a3.a3, mac->hw->addr, WLAN_ADDR_LEN) == 0); isgroup = (pb->p80211_hdr->a3.a3[0] & 0x01); /* Determine if we need two copies of the frame */ if ( !isgroup ) { /* It's a directed frame, we only need one copy. That */ /* one copy will be sent either out the the WM, or up */ /* to the higher layers */ /* TODO: We're making some assumptions about the hdr format here. */ /* Needs review. */ sta = am930mgr_stable_lookup( mac->mgr, pb->p80211_hdr->a3.a3); if ( sta != NULL ) { if (!(sta->sta.info & WLAN_STA_INFO_AUTH) ) { am930mgr_class2err(mac->mgr, pb->p80211_hdr->a3.a2); am930shim_pbfree(pb); kfree_s( stats, sizeof(am930rxstats_t)); return; } } if ( sta != NULL ) { if ( !(sta->sta.info & WLAN_STA_INFO_ASSOC) ) { am930mgr_class3err(mac->mgr, pb->p80211_hdr->a3.a2); am930shim_pbfree(pb); kfree_s( stats, sizeof(am930rxstats_t)); return; } } pb2 = pb; } else { /* It's a multi/broadcast frame, we need two copies. One */ /* for retransmission on the WM, one to hand up to higher */ /* layers */ /* clone the pb */ pb2 = am930shim_pballoc(); if ( pb2 != NULL ) { am930shim_pballoc_p80211(pb2, pb->p80211buflen); if ( pb2->p80211hostbuf != NULL ) { memcpy(pb2->p80211hostbuf, pb->p80211hostbuf, pb->p80211buflen); pb2->p80211frmlen = pb->p80211frmlen - WLAN_CRC_LEN; pb2->p80211_payloadlen = pb->p80211_payloadlen; pb2->wep_iscrypt = pb->wep_iscrypt; pb2->wep_iv = pb->wep_iv; pb2->wep_icv = pb->wep_icv; } else /* alloc failure, drop the frame */ { am930shim_pbfree(pb2); am930shim_pbfree(pb); kfree_s( stats, sizeof(am930rxstats_t)); return; } } else /* alloc failure, drop the frame */ { am930shim_pbfree(pb); kfree_s( stats, sizeof(am930rxstats_t)); return; } } /* If the frame needs to go back out on the WM, do it */ if ( isgroup || sta != NULL ) { UINT8 a[WLAN_ADDR_LEN]; UINT16 fc; /* switch the addresses around and send it out */ memcpy( a, pb2->p80211_hdr->a3.a1, WLAN_BSSID_LEN); /* save bssid */ memcpy( pb2->p80211_hdr->a3.a1, pb2->p80211_hdr->a3.a3, WLAN_ADDR_LEN); /* DA to a1 */ memcpy( pb2->p80211_hdr->a3.a3, pb2->p80211_hdr->a3.a2, WLAN_ADDR_LEN); /* SA to a3 */ memcpy( pb2->p80211_hdr->a3.a2, a, WLAN_BSSID_LEN); /* bssid to a2 */ fc = ieee2host16(pb2->p80211_hdr->a3.fc); fc &= ~(WLAN_SET_FC_TODS(1) | WLAN_SET_FC_RETRY(1) | WLAN_SET_FC_PWRMGT(1) ); fc |= WLAN_SET_FC_FROMDS(1); pb2->p80211_hdr->a3.fc = host2ieee16(fc); pb2->p80211_hdr->a3.dur = host2ieee16(0); /* check to see if we need to encrypt */ if ( ((pb2->p80211_hdr->a3.a1[0] & 0x01) && mac->exclude_unencrypted)) { am930mac_wep_encrypt(mac, pb2); } else if ( sta != NULL ) { if ( ( sta->sta.info & WLAN_STA_INFO_WEPON) || mac->exclude_unencrypted) { am930mac_wep_encrypt(mac, pb2); } } /* enqueue the frame for delivery */ if ( am930mac_txmac( mac, pb2) > 1 ) /* if not queued */ { am930shim_pbfree(pb2); } } /* If the frame needs to go up to higher layers, do that. In the */ /* case of multi/broadcast frames, both will be done. */ if( isme || isgroup || sta == NULL ) { am930shim_rxframe( mac->llc, pb); } } kfree_s( stats, sizeof(am930rxstats_t)); DBFEXIT; return;}/*----------------------------------------------------------------* am930mac_rxenqueue** Enqueue a received frame for later processing.** returns: nothing----------------------------------------------------------------*/void am930mac_rxenqueue( am930mac_t *mac, wlan_pb_t *pb, am930rxstats_t *stats){ am930mac_rxitem_t *item; DBFENTER; item = kmalloc(sizeof(am930mac_rxitem_t), GFP_ATOMIC); if ( item != NULL ) { item->f = pb; item->s = stats; if ( am930q_enqueue( mac->rxq, item) >= 2 ) { /* drop the frame */ am930shim_pbfree( pb ); am930shim_free(stats, sizeof(am930rxstats_t)); kfree_s(item, sizeof(am930mac_rxitem_t)); } else { #if (WLAN_OS == WLAN_LWOS ) am930lw_readerkick(); #endif } } else { /* drop the frame */ am930shim_pbfree( pb ); am930shim_free(stats, sizeof(am930rxstats_t)); } DBFEXIT; return;}/*----------------------------------------------------------------* am930mac_rxframe** Public method called when a frame has been received at a* lower layer and needs to be handled by this layer.** returns: nothing----------------------------------------------------------------*/void am930mac_rxframe( am930mac_t *mac){ UINT32 ftype; wlan_pb_t *pb; am930rxstats_t *stats; am930mac_rxitem_t *item; DBFENTER; while (((item) = am930q_dequeue(mac->rxq)) != NULL) { pb = item->f; stats = item->s; kfree_s( item, sizeof(*item)); ftype = WLAN_GET_FC_FTYPE(ieee2host16(pb->p80211_hdr->a3.fc)); if ( ftype != WLAN_FTYPE_MGMT && ftype != WLAN_FTYPE_DATA ) { /* we've got a frame we shouldn't...drop it */ WLAN_LOG_WARNING0("Ctl or unknown frame type received, dropped\n"); kfree_s( stats, sizeof(am930rxstats_t)); am930shim_pbfree(pb); } /* first, give the frag filter a chance */ pb = am930mac_defrag(mac, pb); if ( pb == NULL ) { /* the frame was absorbed by a fragment pool, do no more */ kfree_s( stats, sizeof(am930rxstats_t)); } else { /* OK, we still have the frame, give the crypto a chance */ pb = am930mac_wep_decrypt(mac, pb); if ( pb == NULL ) { /* the frame failed decryption somehow, do no more */ kfree_s( stats, sizeof(am930rxstats_t)); } else { switch( ftype ) { case WLAN_FTYPE_MGMT: am930mac_rxmgmt( mac, pb, stats); break; case WLAN_FTYPE_DATA: am930mac_rxdata( mac, pb, stats); break; } } } } DBFEXIT; return;}/*----------------------------------------------------------------* am930mac_defragfinish** Takes a fragment pool, validates it and assembles the MSDU* into a new pb buffer. If the fragments are encrypted, each* fragment is decrypted as it's being added to the assembly.** When defragmentation is complete, we discard the pb's for* the fragments and mark the fragpool as free.** Arguments:* mac - the receiver* hash - index of the fragpool to assemble* * returns: * <a new pb> - if the fragpool was succesfully reassembled* NULL - The fragpool was missing fragments, or the decryption* of a fragment failed.----------------------------------------------------------------*/wlan_pb_t *am930mac_defragfinish( am930mac_t *mac, UINT8 hash ){ wlan_pb_t *pb = NULL; UINT32 nfrag = 0; UINT32 iscrypt = 0; UINT32 seenall = 0; UINT32 offset = 0; UINT32 isbad = 0; UINT32 i; UINT32 len = WLAN_HDR_A3_LEN + WLAN_CRC_LEN; /* calcs elsewhere assume CRC is present, so we need it */ DBFENTER; /* add a lot to the lifetime counter to prevent removal */ mac->defragpool[hash].lifetime += 100000UL; /* validate the fragment pool */ for (i=0; i < WLAN_FRAGS_MAX && !seenall; i++) { pb = mac->defragpool[hash].pb[i]; if ( pb == NULL ) { /* Missing fragments. It's bad */ seenall = 1; isbad = 1; WLAN_LOG_DEBUG0(1, "defragfinish, missing frags, dropped .\n"); } else { if ( i == 0 && WLAN_GET_FC_ISWEP(ieee2host16(pb->p80211_hdr->a3.fc)) ) { /* If the first frag is crypt, they must all be */ iscrypt = 1; } if ( WLAN_GET_FC_ISWEP(ieee2host16(pb->p80211_hdr->a3.fc)) && !iscrypt ) { /* mix of crypt and non-crypt. It's bad */ seenall = 1; isbad = 1; WLAN_LOG_DEBUG0(1, "defragfinish, not all crypt, dropped .\n"); } if ( WLAN_GET_FC_MOREFRAG(ieee2host16(pb->p80211_hdr->a3.fc)) == 0 ) { /* Ok, this is the last one. As long as isbad is clear */ /* we're on our way */ seenall = 1; } nfrag++; len += pb->p80211_payloadlen; } } if ( !isbad ) { /* validation was successful, decrypt and defrag */ #if (WLAN_OS == WLAN_LINUX_KERNEL) pb = am930llc_pballoc(); #elif (WLAN_OS == WLAN_LWOS) pb = am930lw_pballoc(); #else #error "No WLAN_OS match!" #endif if ( pb == NULL ) { WLAN_LOG_DEBUG0(2,"pballoc failed.\n"); } else { #if (WLAN_OS == WLAN_LINUX_KERNEL) am930llc_pballoc_p80211(pb, len); #elif (WLAN_OS == WLAN_LWOS) am930lw_pballoc_p80211(pb, len); #else #error "No WLAN_OS match!" #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -