/*---------------------------------------------------------------- * p80211pb_80211_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. * * Arguments: * ethconv Conversion type to perform * skb Packet buffer containing the 802.11 frame * * Returns: * 0 on success, non-zero otherwise * * Call context: * May be called in interrupt or non-interrupt context ----------------------------------------------------------------*/ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, struct sk_buff *skb) { netdevice_t *netdev = wlandev->netdev; u16 fc; unsigned int payload_length; unsigned int payload_offset; u8 daddr[WLAN_ETHADDR_LEN]; u8 saddr[WLAN_ETHADDR_LEN]; union p80211_hdr *w_hdr; struct wlan_ethhdr *e_hdr; struct wlan_llc *e_llc; struct wlan_snap *e_snap; int foo; payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; payload_offset = WLAN_HDR_A3_LEN; w_hdr = (union p80211_hdr *) skb->data; /* setup some vars for convenience */ fc = le16_to_cpu(w_hdr->a3.fc); if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) { memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); } else if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1)) { memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); } else if ((WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0)) { memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); } else { payload_offset = WLAN_HDR_A4_LEN; if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) { ; return 1; } payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN); } /* perform de-wep if necessary.. */ if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc) && (wlandev->hostwep & HOSTWEP_DECRYPT)) { if (payload_length <= 8) { // printk(KERN_ERR "WEP frame too short (%u).\n", ; return 1; } foo = wep_decrypt(wlandev, skb->data + payload_offset + 4, payload_length - 8, -1, skb->data + payload_offset, skb->data + payload_offset + payload_length - 4); if (foo) { /* de-wep failed, drop skb. */ pr_debug("Host de-WEP failed, dropping frame (%d).\n", foo); wlandev->rx.decrypt_err++; return 2; } /* subtract the IV+ICV length off the payload */ payload_length -= 8; /* chop off the IV */ skb_pull(skb, 4); /* chop off the ICV. */ skb_trim(skb, skb->len - 4); wlandev->rx.decrypt++; } e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset); e_llc = (struct wlan_llc *) (skb->data + payload_offset); e_snap = (struct wlan_snap *) (skb->data + payload_offset + sizeof(struct wlan_llc)); /* Test for the various encodings */ if ((payload_length >= sizeof(struct wlan_ethhdr)) && (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) && ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) || (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) { pr_debug("802.3 ENCAP len: %d\n", payload_length); /* 802.3 Encapsulated */ /* Test for an overlength frame */ if (payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) { /* A bogus length ethfrm has been encap'd. */ /* Is someone trying an oflow attack? */ // printk(KERN_ERR "ENCAP frame too large (%d > %d)\n", ; return 1; } /* Chop off the 802.11 header. it's already sane. */ skb_pull(skb, payload_offset); /* chop off the 802.11 CRC */ skb_trim(skb, skb->len - WLAN_CRC_LEN); } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap)) && (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa) && (e_llc->ctl == 0x03) && (((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0) && (ethconv == WLAN_ETHCONV_8021h) && (p80211_stt_findproto(le16_to_cpu(e_snap->type)))) || (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) != 0))) { pr_debug("SNAP+RFC1042 len: %d\n", payload_length); /* it's a SNAP + RFC1042 frame && protocol is in STT */ /* build 802.3 + RFC1042 */ /* Test for an overlength frame */ if (payload_length > netdev->mtu) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ // printk(KERN_ERR "SNAP frame too large (%d > %d)\n", ; return 1; } /* chop 802.11 header from skb. */ skb_pull(skb, payload_offset); /* create 802.3 header at beginning of skb. */ e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN); memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); e_hdr->type = htons(payload_length); /* chop off the 802.11 CRC */ skb_trim(skb, skb->len - WLAN_CRC_LEN); } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap)) && (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa) && (e_llc->ctl == 0x03)) { pr_debug("802.1h/RFC1042 len: %d\n", payload_length); /* it's an 802.1h frame || (an RFC1042 && protocol not in STT) build a DIXII + RFC894 */ /* Test for an overlength frame */ if ((payload_length - sizeof(struct wlan_llc) - sizeof(struct wlan_snap)) > netdev->mtu) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ // printk(KERN_ERR "DIXII frame too large (%ld > %d)\n", // (long int)(payload_length - // sizeof(struct wlan_llc) - ; return 1; } /* chop 802.11 header from skb. */ skb_pull(skb, payload_offset); /* chop llc header from skb. */ skb_pull(skb, sizeof(struct wlan_llc)); /* chop snap header from skb. */ skb_pull(skb, sizeof(struct wlan_snap)); /* create 802.3 header at beginning of skb. */ e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN); e_hdr->type = e_snap->type; memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); /* chop off the 802.11 CRC */ skb_trim(skb, skb->len - WLAN_CRC_LEN); } else { pr_debug("NON-ENCAP len: %d\n", payload_length); /* 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 (payload_length > netdev->mtu) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ // printk(KERN_ERR "OTHER frame too large (%d > %d)\n", ; return 1; } /* Chop off the 802.11 header. */ skb_pull(skb, payload_offset); /* create 802.3 header at beginning of skb. */ e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN); memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); e_hdr->type = htons(payload_length); /* chop off the 802.11 CRC */ skb_trim(skb, skb->len - WLAN_CRC_LEN); } /* * Note that eth_type_trans() expects an skb w/ skb->data pointing * at the MAC header, it then sets the following skb members: * skb->mac_header, * skb->data, and * skb->pkt_type. * It then _returns_ the value that _we're_ supposed to stuff in * skb->protocol. This is nuts. */ skb->protocol = eth_type_trans(skb, netdev); /* jkriegl: process signal and noise as set in hfa384x_int_rx() */ /* jkriegl: only process signal/noise if requested by iwspy */ if (wlandev->spy_number) orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source, P80211SKB_RXMETA(skb)); /* Free the metadata */ p80211skb_rxmeta_detach(skb); return 0; }
/* * Description: Update Tx Statistic Counter * * Parameters: * In: * pStatistic - Pointer to Statistic Counter Data Structure * byTSR0 - Tx Status * byTSR1 - Tx Status * pbyBuffer - Tx Buffer * cbFrameLength - Tx Length * uIdx - Index of Tx DMA * Out: * none * * Return Value: none * */ void STAvUpdateTDStatCounter ( PSStatCounter pStatistic, unsigned char byTSR0, unsigned char byTSR1, unsigned char *pbyBuffer, unsigned int cbFrameLength, unsigned int uIdx ) { PWLAN_80211HDR_A4 pHeader; unsigned char *pbyDestAddr; unsigned char byTSR0_NCR = byTSR0 & TSR0_NCR; pHeader = (PWLAN_80211HDR_A4) pbyBuffer; if (WLAN_GET_FC_TODS(pHeader->wFrameCtl) == 0) { pbyDestAddr = &(pHeader->abyAddr1[0]); } else { pbyDestAddr = &(pHeader->abyAddr3[0]); } // increase tx packet count pStatistic->dwTsrTxPacket[uIdx]++; pStatistic->dwTsrTxOctet[uIdx] += cbFrameLength; if (byTSR0_NCR != 0) { pStatistic->dwTsrRetry[uIdx]++; pStatistic->dwTsrTotalRetry[uIdx] += byTSR0_NCR; if (byTSR0_NCR == 1) pStatistic->dwTsrOnceRetry[uIdx]++; else pStatistic->dwTsrMoreThanOnceRetry[uIdx]++; } if ((byTSR1&(TSR1_TERR|TSR1_RETRYTMO|TSR1_TMO|ACK_DATA)) == 0) { pStatistic->ullTsrOK[uIdx]++; pStatistic->CustomStat.ullTsrAllOK = (pStatistic->ullTsrOK[TYPE_AC0DMA] + pStatistic->ullTsrOK[TYPE_TXDMA0]); // update counters in case that successful transmit if (is_broadcast_ether_addr(pbyDestAddr)) { pStatistic->ullTxBroadcastFrames[uIdx]++; pStatistic->ullTxBroadcastBytes[uIdx] += (unsigned long long) cbFrameLength; } else if (is_multicast_ether_addr(pbyDestAddr)) { pStatistic->ullTxMulticastFrames[uIdx]++; pStatistic->ullTxMulticastBytes[uIdx] += (unsigned long long) cbFrameLength; } else { pStatistic->ullTxDirectedFrames[uIdx]++; pStatistic->ullTxDirectedBytes[uIdx] += (unsigned long long) cbFrameLength; } } else { if (byTSR1 & TSR1_TERR) pStatistic->dwTsrErr[uIdx]++; if (byTSR1 & TSR1_RETRYTMO) pStatistic->dwTsrRetryTimeout[uIdx]++; if (byTSR1 & TSR1_TMO) pStatistic->dwTsrTransmitTimeout[uIdx]++; if (byTSR1 & ACK_DATA) pStatistic->dwTsrACKData[uIdx]++; } if (is_broadcast_ether_addr(pbyDestAddr)) pStatistic->dwTsrBroadcast[uIdx]++; else if (is_multicast_ether_addr(pbyDestAddr)) pStatistic->dwTsrMulticast[uIdx]++; else pStatistic->dwTsrDirected[uIdx]++; }