📄 am930llc.c
字号:
pb->p80211_payload = pb->ethbuf + sizeof(wlan_ethhdr_t); pb->p80211_payloadlen = pb->ethbuflen - sizeof(wlan_ethhdr_t); } } return 0;}/*----------------------------------------------------------------* am930llc_p80211_to_ether* Uses the contents of a received 802.11 frame and the etherconv * setting to build an ether frame.** This function extracts the src and dest address from the 802.11* frame to use in the construction of the eth frame.** This function _will_ set the ethfree member. If a caller wants* to allow some other component (a higher layer?) take responsiblity* for freeing the ethhostbuf, the caller should set ethfree to NULL.** Assume the following are already set:* pb->p80211free* pb->p80211hostbuf* pb->p80211buf* pb->p80211buflen* pb->p80211_hdr* pb->p80211_payload* pb->p80211_payloadlen* returns: zero on success, non-zero on failure----------------------------------------------------------------*/int am930llc_pb_p80211_to_ether( am930llc_t *llc, wlan_pb_t *pb){ UINT8 *daddr = NULL; UINT8 *saddr = NULL; wlan_ethhdr_t *ethhdr; UINT llclen; /* 802 LLC+data length */ UINT dixlen; /* DIX data length */ UINT buflen; /* full frame length, including PAD */ UINT16 fc; /* setup some vars for convenience */ fc = ieee2host16(pb->p80211_hdr->a3.fc); if ( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0) ) { daddr = pb->p80211_hdr->a3.a1; saddr = pb->p80211_hdr->a3.a2; } else if( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1) ) { daddr = pb->p80211_hdr->a3.a1; saddr = pb->p80211_hdr->a3.a3; } else if( (WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0) ) { daddr = pb->p80211_hdr->a3.a3; saddr = pb->p80211_hdr->a3.a2; } else { WLAN_LOG_ERROR0("HDR_A4 detected! A4 currently not supported.\n"); /* set some bogus pointers so at least we won't crash */ daddr = pb->p80211_hdr->a3.a1; saddr = pb->p80211_hdr->a3.a2; } ethhdr = (wlan_ethhdr_t*)(pb->p80211_payload); pb->p80211_llc = (wlan_llc_t*)(((UINT8*)pb->p80211_hdr) + sizeof(p80211_hdr_a3_t)); pb->p80211_snap = (wlan_snap_t*)(((UINT8*)pb->p80211_llc) + sizeof(wlan_llc_t)); /* Test for the various encodings */ if ( memcmp( daddr, ethhdr->daddr, WLAN_ETHADDR_LEN) == 0 && memcmp( saddr, ethhdr->saddr, WLAN_ETHADDR_LEN) == 0 ) { /* ENCAP */ /* Test for an overlength frame */ if ( pb->p80211frmlen > WLAN_HDR_A3_LEN+WLAN_CRC_LEN+WLAN_MAX_ETHFRM_LEN) { /* A bogus length ethfrm has been encap'd. */ /* Is someone trying an oflow attack? */ return 1; } /* allocate space and setup host buffer */ buflen = llclen = pb->p80211frmlen - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; pb->ethhostbuf = dev_alloc_skb(buflen + 2); /* +2 is attempt to align IP header */ if ( pb->ethhostbuf == NULL ) return 1; pb->ethfree = am930llc_pbfreeskb; skb_reserve( pb->ethhostbuf, 2); skb_put( ((struct sk_buff*)pb->ethhostbuf), buflen); /* make room */ pb->ethbuf = ((struct sk_buff*)pb->ethhostbuf)->data; pb->ethbuflen = buflen; /* setup the pointers */ pb->eth_hdr = (wlan_ethhdr_t*)pb->ethbuf; pb->eth_llc = (wlan_llc_t*)(pb->ethbuf + sizeof(wlan_ethhdr_t)); pb->eth_snap = (wlan_snap_t*) (pb->ethbuf + sizeof(wlan_ethhdr_t) + sizeof(wlan_llc_t)); pb->eth_payload = pb->ethbuf + sizeof(wlan_ethhdr_t); pb->eth_payloadlen = buflen - sizeof(wlan_ethhdr_t); /* now copy the data from the 80211 frame */ memcpy( pb->ethbuf, pb->p80211_payload, buflen); /* copy the data */ } else if ( pb->p80211_llc->dsap == 0xaa && pb->p80211_llc->ssap == 0xaa && pb->p80211_llc->ctl == 0x03 && memcmp( pb->p80211_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0 && llc->ethconv == WLAN_ETHCONV_8021h && am930llc_stt_findproto(llc, pb->p80211_snap->type) ) { /* it's a SNAP + RFC1042 frame && protocol is in STT */ /* build 802.3 + RFC1042 */ /* Test for an overlength frame */ if ( pb->p80211_payloadlen > WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN ) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ return 1; } llclen = pb->p80211_payloadlen; buflen = wlan_max( llclen + sizeof(wlan_ethhdr_t), WLAN_MIN_ETHFRM_LEN); pb->ethhostbuf = dev_alloc_skb(buflen + 2); /* +2 is attempt to align IP header */ if ( pb->ethhostbuf == NULL ) return 1; skb_reserve( (struct sk_buff*)pb->ethhostbuf, 2); skb_put( (struct sk_buff*)pb->ethhostbuf, buflen); /* make room */ pb->ethbuf = ((struct sk_buff*)pb->ethhostbuf)->data; pb->ethbuflen = buflen;/* memset( pb->ethbuf, 0, buflen); */ /* zero for possible PAD */ /* set up the pointers */ pb->eth_hdr = (wlan_ethhdr_t*)pb->ethbuf; pb->eth_llc = (wlan_llc_t*)(pb->ethbuf + sizeof(wlan_ethhdr_t)); pb->eth_snap = (wlan_snap_t*) (pb->ethbuf + sizeof(wlan_ethhdr_t) + sizeof(wlan_llc_t)); pb->eth_payload = pb->ethbuf + sizeof(wlan_ethhdr_t); pb->eth_payloadlen = llclen; /* set up the 802.3 header */ pb->eth_hdr->type = htons(pb->eth_payloadlen); memcpy( pb->eth_hdr->daddr, daddr, WLAN_ETHADDR_LEN); memcpy( pb->eth_hdr->saddr, saddr, WLAN_ETHADDR_LEN); /* now copy the data from the 80211 frame */ memcpy( pb->eth_payload, pb->p80211_payload, pb->p80211_payloadlen); } else if ( pb->p80211_llc->dsap == 0xaa && pb->p80211_llc->ssap == 0xaa && pb->p80211_llc->ctl == 0x03 ) { /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */ /* build a DIXII + RFC894 */ dixlen = pb->p80211_payloadlen - sizeof(wlan_llc_t) - sizeof(wlan_snap_t); /* Test for an overlength frame */ if ( dixlen + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ return 1; } dixlen = pb->p80211_payloadlen - sizeof(wlan_llc_t) - sizeof(wlan_snap_t); buflen = wlan_max( dixlen + sizeof(wlan_ethhdr_t), WLAN_MIN_ETHFRM_LEN); pb->ethhostbuf = dev_alloc_skb(buflen + 2); /* +2 is attempt to align IP header */ if ( pb->ethhostbuf == NULL ) return 1; skb_reserve( (struct sk_buff*)pb->ethhostbuf, 2); skb_put( (struct sk_buff*)pb->ethhostbuf, buflen); /* make room */ pb->ethbuf = ((struct sk_buff*)pb->ethhostbuf)->data; pb->ethbuflen = buflen;/* memset( pb->ethbuf, 0, buflen); */ /* zero for possible PAD */ /* set up the pointers */ pb->eth_hdr = (wlan_ethhdr_t*)pb->ethbuf; pb->eth_llc = NULL; pb->eth_snap = NULL; pb->eth_payload = pb->ethbuf + sizeof(wlan_ethhdr_t); pb->eth_payloadlen = dixlen; /* make sure the llc and snap ptrs are set */ pb->p80211_llc = (wlan_llc_t*)pb->p80211_payload; pb->p80211_snap = (wlan_snap_t*) (pb->p80211_payload + sizeof(wlan_llc_t)); /* set up the DIXII header */ pb->eth_hdr->type = pb->p80211_snap->type; memcpy( pb->eth_hdr->daddr, daddr, WLAN_ETHADDR_LEN); memcpy( pb->eth_hdr->saddr, saddr, WLAN_ETHADDR_LEN); /* now copy the data from the 80211 frame */ memcpy( pb->eth_payload, pb->p80211_payload + sizeof(wlan_llc_t) + sizeof(wlan_snap_t), dixlen); } else { /* any NON-ENCAP */ /* it's a generic 80211+LLC or IPX 'Raw 802.3' */ /* build an 802.3 frame */ /* allocate space and setup hostbuf */ /* Test for an overlength frame */ if ( pb->p80211_payloadlen + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ return 1; } llclen = pb->p80211_payloadlen; buflen = wlan_max( llclen + sizeof(wlan_ethhdr_t), WLAN_MIN_ETHFRM_LEN); pb->ethhostbuf = dev_alloc_skb(buflen + 2); /* +2 is attempt to align IP header */ if ( pb->ethhostbuf == NULL ) return 1; skb_reserve( (struct sk_buff*)pb->ethhostbuf, 2); skb_put( (struct sk_buff*)pb->ethhostbuf, buflen); /* make room */ pb->ethbuf = ((struct sk_buff*)pb->ethhostbuf)->data; pb->ethbuflen = buflen;/* memset( pb->ethbuf, 0, buflen); */ /* zero for possible PAD */ /* set up the pointers */ pb->eth_hdr = (wlan_ethhdr_t*)pb->ethbuf; pb->eth_llc = (wlan_llc_t*)(pb->ethbuf + sizeof(wlan_ethhdr_t)); pb->eth_snap = (wlan_snap_t*) (pb->ethbuf + sizeof(wlan_ethhdr_t) + sizeof(wlan_llc_t)); pb->eth_payload = pb->ethbuf + sizeof(wlan_ethhdr_t); pb->eth_payloadlen = llclen; /* set up the 802.3 header */ pb->eth_hdr->type = htons(pb->eth_payloadlen); memcpy( pb->eth_hdr->daddr, daddr, WLAN_ETHADDR_LEN); memcpy( pb->eth_hdr->saddr, saddr, WLAN_ETHADDR_LEN); /* now copy the data from the 80211 frame */ memcpy( pb->eth_payload, pb->p80211_payload, pb->p80211_payloadlen); } return 0;}/*----------------------------------------------------------------* am930llc_pbfreeskb* Free method for wlan_pb's that have skbs in them. Called* via ptr from am930llc_pbfree.** returns: nothing----------------------------------------------------------------*/void am930llc_pbfreeskb( void *buf, int size ){#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)) dev_kfree_skb( (struct sk_buff*)buf, FREE_WRITE);#else dev_kfree_skb( (struct sk_buff*)buf );#endif}/*----------------------------------------------------------------* am930llc_pbkfree_s* Free method for wlan_pb's that have linux kmalloc'd * buffer's in them. Called via ptr from am930llc_pbfree.** returns: nothing----------------------------------------------------------------*/void am930llc_pbkfree_s( void *buf, int size){ kfree_s( buf, size);}/*----------------------------------------------------------------* am930llc_pballoc* Allocates and zeros a wlan_pb structure. Largely here for* symmetry with the pbfree routine.** returns: A valid wlan_pb ptr on success,* NULL otherwise.----------------------------------------------------------------*/wlan_pb_t* am930llc_pballoc(void){ wlan_pb_t *pb; pb = kmalloc( sizeof(wlan_pb_t), GFP_ATOMIC); if ( pb != NULL ) { memset(pb, 0, sizeof(wlan_pb_t)); } return pb;}/*----------------------------------------------------------------* am930llc_pballoc_p80211* Allocates a buffer for an 80211 frame and sets the ptrs in a * given pb. Primarily used by the receive path (see hw). Handled* here so that the allocation used and the free method are set* in one place (helps with portability?).** returns: nothing* caller should check pb->p80211hostbuf for NULL----------------------------------------------------------------*/void am930llc_pballoc_p80211(wlan_pb_t *pb, UINT len){ pb->p80211hostbuf = kmalloc( len, GFP_ATOMIC); if ( pb->p80211hostbuf != NULL ) { pb->p80211free = am930llc_pbkfree_s; pb->p80211buf = (UINT8*)pb->p80211hostbuf; pb->p80211buflen = len; pb->p80211frmlen = len; /* initially assume frm is same as buf */ pb->p80211_hdr = (p80211_hdr_t*)pb->p80211buf; pb->p80211_payload = pb->p80211buf + WLAN_HDR_A3_LEN; pb->p80211_payloadlen = pb->p80211buflen - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; } return;}/*----------------------------------------------------------------* am930llc_pbfree* Frees the ethhostbuf and the p80211hostbuf elements of a wlan_pb* if there is a free method for each. Then frees the wlan_pb itself.** returns: nothing----------------------------------------------------------------*/void am930llc_pbfree(wlan_pb_t* pb){ if ( pb->ethhostbuf != NULL && pb->ethfree != NULL) { (*(pb->ethfree))(pb->ethhostbuf, pb->ethbuflen); } if ( pb->p80211hostbuf != NULL && pb->p80211free != NULL) { (*(pb->p80211free))(pb->p80211hostbuf, pb->p80211buflen); } kfree_s(pb, sizeof(wlan_pb_t));}/*----------------------------------------------------------------* am930llc_rxframe* Event method called from mac when a frame has been received.** returns: zero----------------------------------------------------------------*/void am930llc_rxframe( am930llc_t *llc, wlan_pb_t *pb){ struct sk_buff *skb; DBFENTER; llc->dev->interrupt = 1; if ( llc->dev->start ) { if ( am930llc_pb_p80211_to_ether(llc, pb) == 0 ) { llc->dev->last_rx = jiffies; /* take ownership of skb from pb */ skb = (struct sk_buff*)pb->ethhostbuf; pb->ethhostbuf = NULL; pb->ethfree = NULL; skb->dev = llc->dev; WLAN_HEX_DUMP(3,"llcethrx:", skb->data, skb->len); skb->protocol = eth_type_trans( skb, llc->dev); V2P(llc->dev->priv)->stats.rx_packets++; netif_rx(skb); } } llc->dev->interrupt = 0; am930llc_pbfree(pb); DBFEXIT; return;}/*----------------------------------------------------------------* am930llc_rxframe_err** returns: zero----------------------------------------------------------------*/void am930llc_rxframe_err( am930llc_t *llc){ DBFENTER; V2P(llc->dev->priv)->stats.rx_errors++; DBFEXIT; return;}/*----------------------------------------------------------------* am930llc_sendtosniffer* * If a sniffer is registered, this function fills in the * sniffer msg header and uses a netlink unicast delivery to send* the frame up to the sniffer.* * Note: the caller is relinquishes ownership of the skb passed to* this function.* Arguments:* skb ptr to an skb allocated by the caller and filled with* a wlan_sniffer_t + an 802.11 frame.** returns: nothing----------------------------------------------------------------*/void am930llc_sendtosniffer(am930llc_t *llc, struct sk_buff *skb){ if ( llc->nlsk == NULL || llc->snifferpid == 0) { /* This really shouldn't happen */ WLAN_LOG_WARNING0("sendtosniffer called when no nl sk or registered sniffern"); kfree_skb(skb); } else { netlink_unicast( llc->nlsk, skb, llc->snifferpid, 1); } return;}/*----------------------------------------------------------------* am930llc_stt_findproto* Searches the 802.1h Selective Translation Table for a given * protocol.** returns: 1 - if the table is empty or a match is found.* 0 - if the table is non-empty and a match is not found.----------------------------------------------------------------*/int am930llc_stt_findproto(am930llc_t *llc, UINT16 proto){ /* Always return found for now. This is the behavior used by the */ /* Zoom Win95 driver when 802.1h mode is selected */ /* TODO: If necessary, add an actual search */ return 1;}/*----------------------------------------------------------------* am930llc_stt_addproto* Adds a protocol number to the 802.1h Selective Translation Table.** returns: 0 - on success* non-zero - if the table is full, or a memory allocation fails.----------------------------------------------------------------*/int am930llc_stt_addproto(am930llc_t *llc, UINT16 proto){ return 0;}/*----------------------------------------------------------------* am930llc_devset_multicast_list* set_multicast_list method for the linux net device. ** returns: nothing----------------------------------------------------------------*/#define HW_MAX_ADDRS 4void am930llc_devset_multicast_list(device_t *dev){ DBFENTER; /* First handle our promisc state on its own */ /* We can handle it here by itself since the card supports ALLMULTI */ if ( dev->flags & IFF_PROMISC ) { /* Enable Promiscuous Mode */ UINT8 one = 1; am930mgr_mibsetitem(V2P(dev->priv)->llc->mgr, MAC_PROMISC_EN, &one, sizeof(one)); WLAN_LOG_DEBUG0(2, "am930 promisc enabled\n"); } else { UINT8 zero = 0; am930mgr_mibsetitem(V2P(dev->priv)->llc->mgr, MAC_PROMISC_EN, &zero, sizeof(zero)); WLAN_LOG_DEBUG0(2, "am930 promisc disabled\n"); } /* Now handle the multicast state */ if ( dev->flags & IFF_ALLMULTI || (dev->mc_count > HW_MAX_ADDRS) ) { /* Enable the hw "rcv all multicast" mode, either because of the IFF_ALLMULTI switch or because we have more multicast hw addresses than the hw filter can hold (1.0 fw has four). */ printk(KERN_DEBUG "IFF_ALLMULTI currently unsupported.\n"); } else if ( dev->mc_count ) { /* Load the contents of the mc_list from the dev structure into the filter list in the hardware (effectively reset it from scratch). */ printk(KERN_DEBUG "Multicast filters currently unsupported.\n"); } else { /* Disable allmulti, and clear the multicast filter list */ } DBFEXIT; return;}/*----------------------------------------------------------------* am930llc_ontxcomplete** returns: zero----------------------------------------------------------------*/void am930llc_ontxcomplete( am930llc_t *llc, UINT32 txresult){ DBFENTER; if ( txresult != 0 && txresult != 0xffffffffUL) /* tx failure */ { V2P(llc->dev->priv)->stats.tx_errors++; } else { V2P(llc->dev->priv)->stats.tx_packets++; } llc->dev->tbusy = 0; mark_bh(NET_BH); DBFEXIT; return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -