void ath_ald_update_frame_stats(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts) { struct ieee80211_frame *wh; int type; int bfUsed = 0; u_int32_t ptime = 0; u_int32_t airtime = 0; int i; void *ds = bf->bf_lastbf->bf_desc; wh = (struct ieee80211_frame *)wbuf_header(bf->bf_mpdu); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if((type == IEEE80211_FC0_TYPE_DATA) && (!IEEE80211_IS_MULTICAST(wh->i_addr1)) && (!IEEE80211_IS_BROADCAST(wh->i_addr1))){ for(i=0; i < HAL_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { bfUsed += sc->sc_txq[i].axq_num_buf_used; } } ptime = sc->sc_ald.sc_ald_txairtime; airtime = ath_hal_txcalcairtime(sc->sc_ah, ds, ts, AH_FALSE, 1, 1); sc->sc_ald.sc_ald_txairtime += airtime; if (ptime > sc->sc_ald.sc_ald_txairtime) { sc->sc_ald.sc_ald_txairtime = airtime; sc->sc_ald.sc_ald_pktnum = 0; } if (airtime) { sc->sc_ald.sc_ald_pktlen += (bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen); sc->sc_ald.sc_ald_pktnum += bf->bf_nframes; sc->sc_ald.sc_ald_bfused += bfUsed; sc->sc_ald.sc_ald_counter += 1; } } }
void android_ar6k_check_wow_status(AR_SOFTC_T *ar, struct sk_buff *skb, A_BOOL isEvent) { #ifdef CONFIG_HAS_WAKELOCK unsigned long wake_timeout = HZ; /* 1 second for normal window's ping test */ #endif AR_SOFTC_DEV_T *arPriv; A_UINT8 i; A_BOOL needWake = FALSE; for(i = 0; i < num_device; i++) { arPriv = ar->arDev[i]; if ( #ifdef CONFIG_HAS_EARLYSUSPEND screen_is_off && #endif skb && arPriv->arConnected) { if (isEvent) { if (A_NETBUF_LEN(skb) >= sizeof(A_UINT16)) { A_UINT16 cmd = *(const A_UINT16 *)A_NETBUF_DATA(skb); switch (cmd) { case WMI_CONNECT_EVENTID: #ifdef CONFIG_HAS_WAKELOCK wake_timeout = 3*HZ; #endif needWake = TRUE; break; default: /* dont wake lock the system for other event */ break; } } } else if (A_NETBUF_LEN(skb) >= sizeof(ATH_MAC_HDR)) { ATH_MAC_HDR *datap = (ATH_MAC_HDR *)A_NETBUF_DATA(skb); if (!IEEE80211_IS_MULTICAST(datap->dstMac)) { switch (A_BE2CPU16(datap->typeOrLen)) { case 0x0800: /* IP */ if (A_NETBUF_LEN(skb)>=24 && *((A_UCHAR*)A_NETBUF_DATA(skb)+23)==0x11) { A_UCHAR *udpPkt = (A_UCHAR*)A_NETBUF_DATA(skb)+14; A_UINT8 ihl = (*udpPkt & 0x0f) * sizeof(A_UINT32); const A_UCHAR ipsec_keepalive[] = { 0x11, 0x94, 0x11, 0x94, 0x00, 0x09, 0x00, 0x00, 0xff }; udpPkt += ihl; if (A_NETBUF_LEN(skb)>=14+ihl+sizeof(ipsec_keepalive) && !memcmp(udpPkt, ipsec_keepalive, sizeof(ipsec_keepalive)-3) && udpPkt[8]==0xff) { /* * RFC 3948 UDP Encapsulation of IPsec ESP Packets * Source and Destination port must be 4500 * Receivers MUST NOT depend upon the UDP checksum being zero * Sender must use 1 byte payload with 0xff * Receiver SHOULD ignore a received NAT-keepalive packet * * IPSec over UDP NAT keepalive packet. Just ignore */ break; } } case 0x888e: /* EAPOL */ case 0x88c7: /* RSN_PREAUTH */ case 0x88b4: /* WAPI */ needWake = TRUE; break; case 0x0806: /* ARP is not important to hold wake lock */ needWake = (arPriv->arNetworkType==AP_NETWORK); break; default: break; } } else if ( !IEEE80211_IS_BROADCAST(datap->dstMac) ) { if (A_NETBUF_LEN(skb)>=14+20 ) { /* check if it is mDNS packets */ A_UINT8 *dstIpAddr = (A_UINT8*)(A_NETBUF_DATA(skb)+14+20-4); struct net_device *ndev = arPriv->arNetDev; needWake = ((dstIpAddr[3] & 0xf8) == 0xf8) && (arPriv->arNetworkType==AP_NETWORK || (ndev->flags & IFF_ALLMULTI || ndev->flags & IFF_MULTICAST)); } }else if (arPriv->arNetworkType==AP_NETWORK) { switch (A_BE2CPU16(datap->typeOrLen)) { case 0x0800: /* IP */ if (A_NETBUF_LEN(skb)>=14+20+2) { A_UINT16 dstPort = *(A_UINT16*)(A_NETBUF_DATA(skb)+14+20); dstPort = A_BE2CPU16(dstPort); needWake = (dstPort == 0x43); /* dhcp request */ } break; case 0x0806: needWake = TRUE; default: break; } } } } } if (needWake) { #ifdef CONFIG_HAS_WAKELOCK /* keep host wake up if there is any event and packate comming in*/ wake_lock_timeout(&ar6k_wow_wake_lock, wake_timeout); #endif if (wowledon) { char buf[32]; int len = sprintf(buf, "on"); android_readwrite_file("/sys/power/state", NULL, buf, len); len = sprintf(buf, "%d", 127); android_readwrite_file("/sys/class/leds/lcd-backlight/brightness", NULL, buf,len); } } }
void android_ar6k_check_wow_status(AR_SOFTC_T *ar, struct sk_buff *skb, A_BOOL isEvent) { AR_SOFTC_DEV_T *arPriv; A_UINT8 i; A_BOOL needWake = FALSE; for(i = 0; i < num_device; i++) { arPriv = ar->arDev[i]; if ( #ifdef CONFIG_HAS_EARLYSUSPEND screen_is_off && #endif skb && arPriv->arConnected) { if (isEvent) { if (A_NETBUF_LEN(skb) >= sizeof(A_UINT16)) { A_UINT16 cmd = *(const A_UINT16 *)A_NETBUF_DATA(skb); switch (cmd) { case WMI_CONNECT_EVENTID: case WMI_DISCONNECT_EVENTID: needWake = TRUE; break; default: /* dont wake lock the system for other event */ break; } } } else if (A_NETBUF_LEN(skb) >= sizeof(ATH_MAC_HDR)) { ATH_MAC_HDR *datap = (ATH_MAC_HDR *)A_NETBUF_DATA(skb); if (!IEEE80211_IS_MULTICAST(datap->dstMac)) { switch (A_BE2CPU16(datap->typeOrLen)) { case 0x0800: /* IP */ case 0x888e: /* EAPOL */ case 0x88c7: /* RSN_PREAUTH */ case 0x88b4: /* WAPI */ needWake = TRUE; break; case 0x0806: /* ARP is not important to hold wake lock */ needWake = (arPriv->arNetworkType==AP_NETWORK); break; default: break; } } else if ( !IEEE80211_IS_BROADCAST(datap->dstMac) ) { if (A_NETBUF_LEN(skb)>=14+20 ) { /* check if it is mDNS packets */ A_UINT8 *dstIpAddr = (A_UINT8*)(A_NETBUF_DATA(skb)+14+20-4); struct net_device *ndev = arPriv->arNetDev; needWake = ((dstIpAddr[3] & 0xf8) == 0xf8) && (arPriv->arNetworkType==AP_NETWORK || (ndev->flags & IFF_ALLMULTI || ndev->flags & IFF_MULTICAST)); } }else if (arPriv->arNetworkType==AP_NETWORK) { switch (A_BE2CPU16(datap->typeOrLen)) { case 0x0800: /* IP */ if (A_NETBUF_LEN(skb)>=14+20+2) { A_UINT16 dstPort = *(A_UINT16*)(A_NETBUF_DATA(skb)+14+20); dstPort = A_BE2CPU16(dstPort); needWake = (dstPort == 0x43); /* dhcp request */ } break; case 0x0806: needWake = TRUE; default: break; } } } } } if (needWake) { #ifdef CONFIG_HAS_WAKELOCK /* keep host wake up if there is any event and packate comming in*/ wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ); #endif if (wowledon) { char buf[32]; int len = sprintf(buf, "on"); android_readwrite_file("/sys/power/state", NULL, buf, len); len = sprintf(buf, "%d", 127); android_readwrite_file("/sys/class/leds/lcd-backlight/brightness", NULL, buf,len); } } }
/* * processes data frames. * ieee80211_wow_magic_parser parses the wbuf to check if match magic packet. */ void ieee80211_wow_magic_parser(struct ieee80211_node *ni, wbuf_t wbuf) { struct ieee80211vap *vap = ni->ni_vap; a_uint8_t i_addr[IEEE80211_ADDR_LEN]; a_int32_t left_len = wbuf_get_pktlen(wbuf); a_uint8_t *cur_ptr; a_uint32_t dup_cnt, is_match = FALSE, is_bcast = FALSE; //wow_dump_pkt(wbuf->data, wbuf->len); if (left_len < IEEE80211_WOW_MAGIC_PKTLEN) return; cur_ptr = wbuf_header(wbuf); IEEE80211_ADDR_COPY(i_addr, vap->iv_myaddr); /* parse whole pkt */ while (cur_ptr && (left_len>0) && (!is_match)) { /* left len is less than magic pkt size, give up */ if (left_len < IEEE80211_WOW_MAGIC_PKTLEN) break; /* to skip continuous 0xFF and to match last 6 bytes of 0xFF */ while (IEEE80211_IS_BROADCAST(cur_ptr) && (left_len>=IEEE80211_WOW_MAGIC_PKTLEN)) { is_bcast = TRUE; cur_ptr += IEEE80211_ADDR_LEN; left_len -= IEEE80211_ADDR_LEN; } /* 6 bytes of 0xFF matched, to check if 16 duplications of the IEEE address */ if (is_bcast) { dup_cnt = 0; /* if 0xFF exists at head, skip it */ while ((cur_ptr[0]==0xFF) && (left_len>=IEEE80211_WOW_MAGIC_DUPLEN)) { cur_ptr++; left_len--; } /* left len is less than duplication size, give up */ if (left_len < IEEE80211_WOW_MAGIC_DUPLEN) break; /* to check if 16 duplications of the IEEE address */ while (cur_ptr && (left_len>=IEEE80211_ADDR_LEN) && IEEE80211_ADDR_EQ(cur_ptr, i_addr)) { cur_ptr += IEEE80211_ADDR_LEN; left_len -= IEEE80211_ADDR_LEN; dup_cnt++; if (dup_cnt >= IEEE80211_WOW_MAGIC_DUPCNT) { is_match = TRUE; break; } } /* not match magic pkt, keep parsing */ is_bcast = FALSE; } else { cur_ptr++; left_len--; } } if (is_match) { adf_os_print("Magic packet received...\n"); ieee80211_wow_set_gpio(vap); } }
int ieee80211_recv_probereq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; u_int8_t *frm, *efrm; u_int8_t *ssid, *rates, *ven; #if ATH_SUPPORT_AP_WDS_COMBO if (vap->iv_opmode == IEEE80211_M_STA || !ieee80211_vap_ready_is_set(vap) || vap->iv_no_beacon) { #else if (vap->iv_opmode == IEEE80211_M_STA || !ieee80211_vap_ready_is_set(vap)) { #endif vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; } wh = (struct ieee80211_frame *) wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf); /*zhaoyang1 add start for probe request REQUIREMENTS-340*/ if (vap->iv_probe_request) { switch (vap->iv_probe_request) { case IEEE80211_BROADCAST_PROBE: if (IEEE80211_IS_BROADCAST(wh->i_addr1)) { vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; } break; case IEEE80211_ALL_PROBE: vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; default: printk("Probe_req value is wrong, iv_probe_request = %d\n", vap->iv_probe_request); break; } } /*zhaoyang1 add end*/ if (IEEE80211_IS_MULTICAST(wh->i_addr2)) { /* frame must be directed */ vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ return -EINVAL; } /* * prreq frame format * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] Atheros Advanced Capabilities */ ssid = rates = NULL; while (((frm+1) < efrm) && (frm + frm[1] + 1 < efrm)) { switch (*frm) { case IEEE80211_ELEMID_SSID: ssid = frm; break; case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_VENDOR: if (vap->iv_venie && vap->iv_venie->ven_oui_set) { ven = frm; if (ven[2] == vap->iv_venie->ven_oui[0] && ven[3] == vap->iv_venie->ven_oui[1] && ven[4] == vap->iv_venie->ven_oui[2]) { vap->iv_venie->ven_ie_len = MIN(ven[1] + 2, IEEE80211_MAX_IE_LEN); OS_MEMCPY(vap->iv_venie->ven_ie, ven, vap->iv_venie->ven_ie_len); } } break; } frm += frm[1] + 2; } if (frm > efrm) { return -EINVAL; } IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); IEEE80211_VERIFY_SSID(vap->iv_bss, ssid); if (IEEE80211_VAP_IS_HIDESSID_ENABLED(vap) && (ssid[1] == 0)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, ieee80211_mgt_subtype_name[ subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s", "no ssid with ssid suppression enabled"); vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/ return -EINVAL; } /* * Skip Probe Requests received while the scan algorithm is setting a new * channel, or while in a foreign channel. * Trying to transmit a frame (Probe Response) during a channel change * (which includes a channel reset) can cause a NMI due to invalid HW * addresses. * Trying to transmit the Probe Response while in a foreign channel * wouldn't do us any good either. */ if (ieee80211_scan_can_transmit(ic->ic_scanner)) ieee80211_send_proberesp(ni, wh->i_addr2, NULL,0); return 0; }