/** * @brief Get number of aggregated packets * * @param data A pointer to packet data * @param total_pkt_len Total packet length * * @return Number of packets */ static int wlan_11n_get_num_aggrpkts(t_u8 * data, int total_pkt_len) { int pkt_count = 0, pkt_len, pad; t_u8 hdr_len = sizeof(Eth803Hdr_t); ENTER(); while (total_pkt_len >= hdr_len) { /* Length will be in network format, change it to host */ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)))); if (pkt_len > total_pkt_len) { PRINTM(MERROR, "Error in packet length.\n"); break; } pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ? (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0; data += pkt_len + pad + sizeof(Eth803Hdr_t); total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t); ++pkt_count; } LEAVE(); return pkt_count; }
/** * @brief Function to send packet * * @param pmlan_adapter A pointer to mlan_adapter structure * @param pmbuf A pointer to mlan_buffer structure * * @return MLAN_STATUS_PENDING */ mlan_status mlan_send_packet(IN t_void * pmlan_adapter, IN pmlan_buffer pmbuf) { mlan_status ret = MLAN_STATUS_PENDING; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; ENTER(); MASSERT(pmlan_adapter && pmbuf); MASSERT(pmbuf->bss_num < MLAN_MAX_BSS_NUM); pmbuf->flags = MLAN_BUF_FLAG_MOAL_TX_BUF; if ((pmadapter->priv[pmbuf->bss_num]->port_ctrl_mode == MTRUE) && (mlan_ntohs(*(t_u16 *) & pmbuf->pbuf[pmbuf->data_offset + MLAN_ETHER_PKT_TYPE_OFFSET]) == MLAN_ETHER_PKT_TYPE_EAPOL)) { PRINTM(MINFO, "mlan_send_pkt(): enq(bybass_txq)\n"); wlan_add_buf_bypass_txqueue(pmadapter, pmbuf); } else { /* Transmit the packet */ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf); } LEAVE(); return ret; }
/** * @brief Function to send packet * * @param pmlan_adapter A pointer to mlan_adapter structure * @param pmbuf A pointer to mlan_buffer structure * * @return MLAN_STATUS_PENDING */ mlan_status mlan_send_packet(IN t_void * pmlan_adapter, IN pmlan_buffer pmbuf) { mlan_status ret = MLAN_STATUS_PENDING; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; mlan_private *pmpriv; t_u16 eth_type = 0; t_u8 ra[MLAN_MAC_ADDR_LENGTH]; tdlsStatus_e tdls_status; ENTER(); MASSERT(pmlan_adapter && pmbuf); MASSERT(pmbuf->bss_index < pmadapter->priv_num); pmbuf->flags |= MLAN_BUF_FLAG_MOAL_TX_BUF; pmpriv = pmadapter->priv[pmbuf->bss_index]; eth_type = mlan_ntohs(*(t_u16 *) & pmbuf-> pbuf[pmbuf->data_offset + MLAN_ETHER_PKT_TYPE_OFFSET]); if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) && ((eth_type == MLAN_ETHER_PKT_TYPE_EAPOL) || (eth_type == MLAN_ETHER_PKT_TYPE_WAPI) )) || (eth_type == MLAN_ETHER_PKT_TYPE_TDLS_ACTION) || (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) ) { if (eth_type == MLAN_ETHER_PKT_TYPE_TDLS_ACTION) { memcpy(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset, MLAN_MAC_ADDR_LENGTH); tdls_status = wlan_get_tdls_link_status(pmpriv, ra); if (MTRUE == wlan_is_tdls_link_setup(tdls_status) || !pmpriv->media_connected) pmbuf->flags |= MLAN_BUF_FLAG_TDLS; } PRINTM(MINFO, "mlan_send_pkt(): enq(bybass_txq)\n"); wlan_add_buf_bypass_txqueue(pmadapter, pmbuf); } else { /* Transmit the packet */ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf); } LEAVE(); return ret; }
/** * @brief Get number of aggregated packets * * @param data A pointer to packet data * @param total_pkt_len Total packet length * * @return Number of packets */ static int wlan_11n_get_num_aggrpkts(t_u8 * data, int total_pkt_len) { int pkt_count = 0, pkt_len, pad; ENTER(); while (total_pkt_len > 0) { /* Length will be in network format, change it to host */ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)))); pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ? (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0; data += pkt_len + pad + sizeof(Eth803Hdr_t); total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t); ++pkt_count; } LEAVE(); return pkt_count; }
/** * @brief Function to send packet * * @param pmlan_adapter A pointer to mlan_adapter structure * @param pmbuf A pointer to mlan_buffer structure * * @return MLAN_STATUS_PENDING */ mlan_status mlan_send_packet(IN t_void * pmlan_adapter, IN pmlan_buffer pmbuf) { mlan_status ret = MLAN_STATUS_PENDING; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; mlan_private *pmpriv; t_u16 eth_type = 0; ENTER(); MASSERT(pmlan_adapter && pmbuf); MASSERT(pmbuf->bss_index < pmadapter->priv_num); pmbuf->flags |= MLAN_BUF_FLAG_MOAL_TX_BUF; pmpriv = pmadapter->priv[pmbuf->bss_index]; eth_type = mlan_ntohs(*(t_u16 *) & pmbuf-> pbuf[pmbuf->data_offset + MLAN_ETHER_PKT_TYPE_OFFSET]); if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) && ((eth_type == MLAN_ETHER_PKT_TYPE_EAPOL) || (eth_type == MLAN_ETHER_PKT_TYPE_WAPI) )) || (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) ) { PRINTM(MINFO, "mlan_send_pkt(): enq(bybass_txq)\n"); wlan_add_buf_bypass_txqueue(pmadapter, pmbuf); } else { /* Transmit the packet */ wlan_wmm_add_buf_txqueue(pmadapter, pmbuf); } LEAVE(); return ret; }
/** * @brief Deaggregate the received AMSDU packet * * @param priv A pointer to mlan_private structure * @param pmbuf A pointer to aggregated data packet * * @return MLAN_STATUS_SUCCESS --success, otherwise fail */ mlan_status wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf) { t_u16 pkt_len; int total_pkt_len; t_u8 *data; t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE; int pad; mlan_status ret = MLAN_STATUS_FAILURE; RxPacketHdr_t *prx_pkt; mlan_buffer *daggr_mbuf = MNULL; mlan_adapter *pmadapter = priv->adapter; t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; t_u8 hdr_len = sizeof(Eth803Hdr_t); ENTER(); data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset); total_pkt_len = pmbuf->data_len; /* Sanity test */ if (total_pkt_len > max_rx_data_size) { PRINTM(MERROR, "Total packet length greater than tx buffer" " size %d\n", total_pkt_len); goto done; } pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len); while (total_pkt_len >= hdr_len) { prx_pkt = (RxPacketHdr_t *) data; /* Length will be in network format, change it to host */ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)))); if (pkt_len > total_pkt_len) { PRINTM(MERROR, "Error in packet length: total_pkt_len = %d, pkt_len = %d\n", total_pkt_len, pkt_len); break; } pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ? (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0; total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t); if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { memmove(pmadapter, data + LLC_SNAP_LEN, data, (2 * MLAN_MAC_ADDR_LENGTH)); data += LLC_SNAP_LEN; pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN; } else { *(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)) = (t_u16) 0; pkt_len += sizeof(Eth803Hdr_t); } daggr_mbuf = wlan_alloc_mlan_buffer(pmadapter, pkt_len, 0, MOAL_ALLOC_MLAN_BUFFER); if (daggr_mbuf == MNULL) { PRINTM(MERROR, "Error allocating daggr mlan_buffer\n"); LEAVE(); return MLAN_STATUS_FAILURE; } daggr_mbuf->bss_index = pmbuf->bss_index; daggr_mbuf->buf_type = pmbuf->buf_type; daggr_mbuf->data_len = pkt_len; daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec; daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec; daggr_mbuf->pparent = pmbuf; daggr_mbuf->priority = pmbuf->priority; memcpy(pmadapter, daggr_mbuf->pbuf + daggr_mbuf->data_offset, data, pkt_len); #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { ret = wlan_uap_recv_packet(priv, daggr_mbuf); } else { #endif /* UAP_SUPPORT */ ret = pmadapter->callbacks.moal_recv_packet(pmadapter-> pmoal_handle, daggr_mbuf); #ifdef UAP_SUPPORT } #endif /* UAP_SUPPORT */ switch (ret) { case MLAN_STATUS_PENDING: break; case MLAN_STATUS_FAILURE: PRINTM(MERROR, "Deaggr, send to moal failed\n"); daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID; case MLAN_STATUS_SUCCESS: wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret); break; default: break; } data += pkt_len + pad; } done: LEAVE(); return ret; }
/** * @brief This function process tdls action frame * * @param priv A pointer to mlan_private structure * @param pbuf A pointer to tdls action frame buffer * @param len len of tdls action frame buffer * @return N/A */ void wlan_process_tdls_action_frame(pmlan_private priv, t_u8 *pbuf, t_u32 len) { sta_node *sta_ptr = MNULL; t_u8 *peer; t_u8 *pos, *end; t_u8 action; int ie_len = 0; t_u8 i; #define TDLS_PAYLOAD_TYPE 2 #define TDLS_CATEGORY 0x0c #define TDLS_REQ_FIX_LEN 6 #define TDLS_RESP_FIX_LEN 8 #define TDLS_CONFIRM_FIX_LEN 6 if (len < (sizeof(EthII_Hdr_t) + 3)) return; if (*(t_u8 *)(pbuf + sizeof(EthII_Hdr_t)) != TDLS_PAYLOAD_TYPE) /* TDLS payload type = 2 */ return; if (*(t_u8 *)(pbuf + sizeof(EthII_Hdr_t) + 1) != TDLS_CATEGORY) /* TDLS category = 0xc */ return; peer = pbuf + MLAN_MAC_ADDR_LENGTH; action = *(t_u8 *)(pbuf + sizeof(EthII_Hdr_t) + 2); /* 2= payload type + category */ if (action > TDLS_SETUP_CONFIRM) { /* just handle TDLS setup request/response/confirm */ PRINTM(MMSG, "Recv TDLS Action: peer=" MACSTR ", action=%d\n", MAC2STR(peer), action); return; } sta_ptr = wlan_add_station_entry(priv, peer); if (!sta_ptr) return; if (action == TDLS_SETUP_REQUEST) { /* setup request */ sta_ptr->status = TDLS_NOT_SETUP; PRINTM(MMSG, "Recv TDLS SETUP Request: peer=" MACSTR "\n", MAC2STR(peer)); wlan_hold_tdls_packets(priv, peer); if (len < (sizeof(EthII_Hdr_t) + TDLS_REQ_FIX_LEN)) return; pos = pbuf + sizeof(EthII_Hdr_t) + 4; /* payload 1+ category 1 + action 1 +dialog 1 */ sta_ptr->capability = mlan_ntohs(*(t_u16 *)pos); ie_len = len - sizeof(EthII_Hdr_t) - TDLS_REQ_FIX_LEN; pos += 2; } else if (action == 1) { /* setup respons */ PRINTM(MMSG, "Recv TDLS SETUP Response: peer=" MACSTR "\n", MAC2STR(peer)); if (len < (sizeof(EthII_Hdr_t) + TDLS_RESP_FIX_LEN)) return; pos = pbuf + sizeof(EthII_Hdr_t) + 6; /* payload 1+ category 1 + action 1 +dialog 1 +status 2 */ sta_ptr->capability = mlan_ntohs(*(t_u16 *)pos); ie_len = len - sizeof(EthII_Hdr_t) - TDLS_RESP_FIX_LEN; pos += 2; } else { /* setup confirm */ PRINTM(MMSG, "Recv TDLS SETUP Confirm: peer=" MACSTR "\n", MAC2STR(peer)); if (len < (sizeof(EthII_Hdr_t) + TDLS_CONFIRM_FIX_LEN)) return; pos = pbuf + sizeof(EthII_Hdr_t) + TDLS_CONFIRM_FIX_LEN; /* payload 1+ category 1 + action 1 +dialog 1 + status 2 */ ie_len = len - sizeof(EthII_Hdr_t) - TDLS_CONFIRM_FIX_LEN; } for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) { if (pos + 2 + pos[1] > end) break; switch (*pos) { case SUPPORTED_RATES: sta_ptr->rate_len = pos[1]; for (i = 0; i < pos[1]; i++) sta_ptr->support_rate[i] = pos[2 + i]; break; case EXTENDED_SUPPORTED_RATES: for (i = 0; i < pos[1]; i++) sta_ptr->support_rate[sta_ptr->rate_len + i] = pos[2 + i]; sta_ptr->rate_len += pos[1]; break; case HT_CAPABILITY: memcpy(priv->adapter, (t_u8 *)&sta_ptr->HTcap, pos, sizeof(IEEEtypes_HTCap_t)); sta_ptr->is_11n_enabled = 1; DBG_HEXDUMP(MDAT_D, "TDLS HT capability", (t_u8 *)(&sta_ptr->HTcap), MIN(sizeof(IEEEtypes_HTCap_t), MAX_DATA_DUMP_LEN)); break; case HT_OPERATION: memcpy(priv->adapter, &sta_ptr->HTInfo, pos, sizeof(IEEEtypes_HTInfo_t)); DBG_HEXDUMP(MDAT_D, "TDLS HT info", (t_u8 *)(&sta_ptr->HTInfo), MIN(sizeof(IEEEtypes_HTInfo_t), MAX_DATA_DUMP_LEN)); break; case BSSCO_2040: memcpy(priv->adapter, (t_u8 *)&sta_ptr->BSSCO_20_40, pos, sizeof(IEEEtypes_2040BSSCo_t)); break; case EXT_CAPABILITY: memcpy(priv->adapter, (t_u8 *)&sta_ptr->ExtCap, pos, pos[1] + sizeof(IEEEtypes_Header_t)); DBG_HEXDUMP(MDAT_D, "TDLS Extended capability", (t_u8 *)(&sta_ptr->ExtCap), sta_ptr->ExtCap.ieee_hdr.len + 2); break; case RSN_IE: memcpy(priv->adapter, (t_u8 *)&sta_ptr->rsn_ie, pos, pos[1] + sizeof(IEEEtypes_Header_t)); DBG_HEXDUMP(MDAT_D, "TDLS Rsn ie ", (t_u8 *)(&sta_ptr->rsn_ie), pos[1] + sizeof(IEEEtypes_Header_t)); break; case QOS_INFO: sta_ptr->qos_info = pos[2]; PRINTM(MDAT_D, "TDLS qos info %x\n", sta_ptr->qos_info); break; case LINK_ID: memcpy(priv->adapter, (t_u8 *)&sta_ptr->link_ie, pos, sizeof(IEEEtypes_LinkIDElement_t)); break; default: break; } } return; }