Beispiel #1
0
void
ol_rx_err(
    ol_pdev_handle pdev,
    u_int8_t vdev_id,
    u_int8_t *peer_mac_addr,
    int tid,
    u_int32_t tsf32,
    enum ol_rx_err_type err_type,
    adf_nbuf_t rx_frame)
{
    struct ieee80211_frame wh;
    struct ether_header *eh;
    struct ol_ath_softc_net80211 *scn ;
    struct ieee80211vap *vap;
    enum ieee80211_opmode opmode;
    A_BOOL notify = TRUE;

    eh = (struct ether_header *)adf_nbuf_data(rx_frame);
    scn = (struct ol_ath_softc_net80211 *)pdev;
    vap = ol_ath_vap_get(scn, vdev_id);
    if(vap == NULL) {
       printk("%s: vap is NULL \n", __func__);
       return;
    }
    opmode = ieee80211_vap_get_opmode(vap);

    if (err_type == OL_RX_ERR_TKIP_MIC) {
        /*TODO: Reconstructing the WLAN header for now from ether header
         * since WLAN header is not available for HL case.
         */
        wh.i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA;
        wh.i_dur[0] = wh.i_dur[1] = 0;
        wh.i_seq[0] = wh.i_seq[1] = 0;

        adf_os_mem_copy(&wh.i_addr1, &vap->iv_myaddr, IEEE80211_ADDR_LEN);
        adf_os_mem_copy(&wh.i_addr2, peer_mac_addr, IEEE80211_ADDR_LEN);

        if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_WDS) {
            wh.i_fc[1] = IEEE80211_FC1_DIR_TODS;
            adf_os_mem_copy(&wh.i_addr3, &eh->ether_dhost , IEEE80211_ADDR_LEN);
        } else if (opmode == IEEE80211_M_STA) {
            wh.i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
            adf_os_mem_copy(&wh.i_addr3, &eh->ether_shost , IEEE80211_ADDR_LEN);
        } else {
            /*TODO: Handle other cases*/
            notify = FALSE;
        }

        if (notify) {
            printk("%s: TKIP MIC failure \n",__func__);
            ieee80211_notify_michael_failure(vap,(const struct ieee80211_frame *)&wh,0);
        }
    }
}
Beispiel #2
0
static inline void
ol_rx_decap_to_native_wifi(
    struct ol_txrx_vdev_t *vdev,
    adf_nbuf_t msdu,
    struct ol_rx_decap_info_t *info,
    struct ethernet_hdr_t *ethr_hdr)
{
    struct ieee80211_frame_addr4 *wh;
    u_int16_t hdsize;

    /*
     * we need to remove Qos control field and HT control.
     * MSFT: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552608(v=vs.85).aspx
     */
    wh = (struct ieee80211_frame_addr4 *)info->hdr;
    if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
        hdsize = sizeof(struct ieee80211_frame_addr4);
    }
    else {
        hdsize = sizeof(struct ieee80211_frame);
    }
    wh = (struct ieee80211_frame_addr4 *) adf_nbuf_push_head(msdu, hdsize);
    TXRX_ASSERT2(wh != NULL);
    TXRX_ASSERT2(hdsize <= info->hdr_len);
    adf_os_mem_copy ((u_int8_t *)wh, info->hdr, hdsize);

    /* amsdu subfrm handling if ethr_hdr is not NULL  */
    if (ethr_hdr != NULL) {
        switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        case IEEE80211_FC1_DIR_NODS:
            adf_os_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr2, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_TODS:
            adf_os_mem_copy(wh->i_addr2, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_FROMDS:
            adf_os_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_DSTODS:
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr4, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        }
    }
    if (IEEE80211_QOS_HAS_SEQ(wh) ) {
        if (wh->i_fc[1] & IEEE80211_FC1_ORDER) {
            wh->i_fc[1] &= ~IEEE80211_FC1_ORDER;
        }
        wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS;
    }
}
Beispiel #3
0
int
wmi_send_node_rate_sched(struct ol_ath_softc_net80211 *scn,
        wmi_peer_rate_retry_sched_cmd *cmd_buf)
{
    wmi_unified_t wmi_handle = scn->wmi_handle;

    wmi_peer_rate_retry_sched_cmd *cmd;
    wmi_buf_t buf;
    int len = sizeof(wmi_peer_rate_retry_sched_cmd);

    buf = wmi_buf_alloc(wmi_handle, len);
    if(!buf) {
        printk("%s: wmi_buf_alloc failed\n", __func__);
        return ENOMEM;
    }

    cmd = (wmi_peer_rate_retry_sched_cmd *)wmi_buf_data(buf);

    adf_os_mem_copy(cmd, cmd_buf, len);

    return (wmi_unified_cmd_send(
                    wmi_handle,
                    buf,
                    len,
                    WMI_PEER_RATE_RETRY_SCHED_CMDID));
}
Beispiel #4
0
a_status_t
fwd_send_next(fwd_softc_t *sc) 
{
    a_uint32_t len, alloclen; 
    adf_nbuf_t nbuf;
    fwd_cmd_t  *h;
    a_uint8_t  *pld;
    a_uint32_t  target_jmp_loc;

    len      =   fwd_chunk_len(sc);
    alloclen =   sizeof(fwd_cmd_t) + len;

    if (fwd_is_first(sc) || fwd_is_last(sc))
        alloclen += 4;

    nbuf     =   adf_nbuf_alloc(NULL,alloclen + 20, 20, 0);

    if (!nbuf) {
        adf_os_print("FWD: packet allocation failed. \n");
        return A_STATUS_ENOMEM;
    }

    h            =  (fwd_cmd_t *)adf_nbuf_put_tail(nbuf, alloclen);        

    h->more_data =  adf_os_htons(!fwd_is_last(sc));
    h->len       =  adf_os_htons(len);
    h->offset    =  adf_os_htonl(sc->offset);

    pld          =  (a_uint8_t *)(h + 1);

    if (fwd_is_first(sc)) {
        *(a_uint32_t *)pld  =   adf_os_htonl(sc->target_upload_addr);
                       pld +=   4;
    }

    adf_os_mem_copy(pld, &sc->image[sc->offset], len);

    if(h->more_data == 0) {
        target_jmp_loc = adf_os_htonl(fw_exec_addr);
        adf_os_mem_copy(pld+len, (a_uint8_t *)&target_jmp_loc, 4);
    }

    HIFSend(sc->hif_handle, sc->tx_pipe, NULL, nbuf);
    /*adf_os_timer_start(&sc->tmr, FWD_TIMEOUT_MSECS);*/

    return A_STATUS_OK;
}
Beispiel #5
0
void
__adf_nbuf_trace_update(struct sk_buff *buf, char *event_string)
{
   char string_buf[NBUF_PKT_TRAC_MAX_STRING];

   if ((!trace_update_cb) || (!event_string)) {
      return;
   }

   if (!adf_nbuf_trace_get_proto_type(buf)) {
      return;
   }

   /* Buffer over flow */
   if (NBUF_PKT_TRAC_MAX_STRING <=
       (adf_os_str_len(event_string) + NBUF_PKT_TRAC_PROTO_STRING)) {
      return;
   }

   adf_os_mem_zero(string_buf,
                   NBUF_PKT_TRAC_MAX_STRING);
   adf_os_mem_copy(string_buf,
                   event_string, adf_os_str_len(event_string));
   if (NBUF_PKT_TRAC_TYPE_EAPOL &
       adf_nbuf_trace_get_proto_type(buf)) {
      adf_os_mem_copy(string_buf + adf_os_str_len(event_string),
                      "EPL",
                      NBUF_PKT_TRAC_PROTO_STRING);
   }
   else if (NBUF_PKT_TRAC_TYPE_DHCP &
            adf_nbuf_trace_get_proto_type(buf)) {
      adf_os_mem_copy(string_buf + adf_os_str_len(event_string),
                      "DHC",
                      NBUF_PKT_TRAC_PROTO_STRING);
   } else if (NBUF_PKT_TRAC_TYPE_MGMT_ACTION &
              adf_nbuf_trace_get_proto_type(buf)) {
      adf_os_mem_copy(string_buf + adf_os_str_len(event_string),
                      "MACT",
                      NBUF_PKT_TRAC_PROTO_STRING);
   }

   trace_update_cb(string_buf);
   return;
}
/**
 * adf_dp_add_record() - add dp trace record
 * @code: dptrace code
 * @data: data pointer
 * @size: size of buffer
 * @print: print it in kmsg
 *
 * Return: none
 */
void adf_dp_add_record(enum ADF_DP_TRACE_ID code,
		       uint8_t *data, uint8_t size, bool print)
{
	struct adf_dp_trace_record_s *rec = NULL;
	int index;

	spin_lock_bh(&l_dp_trace_lock);

	g_adf_dp_trace_data.num++;

	if (g_adf_dp_trace_data.num > MAX_ADF_DP_TRACE_RECORDS)
		g_adf_dp_trace_data.num = MAX_ADF_DP_TRACE_RECORDS;

	if (INVALID_ADF_DP_TRACE_ADDR == g_adf_dp_trace_data.head) {
		/* first record */
		g_adf_dp_trace_data.head = 0;
		g_adf_dp_trace_data.tail = 0;
	} else {
		/* queue is not empty */
		g_adf_dp_trace_data.tail++;

		if (MAX_ADF_DP_TRACE_RECORDS == g_adf_dp_trace_data.tail)
			g_adf_dp_trace_data.tail = 0;

		if (g_adf_dp_trace_data.head == g_adf_dp_trace_data.tail) {
			/* full */
			if (MAX_ADF_DP_TRACE_RECORDS ==
				++g_adf_dp_trace_data.head)
				g_adf_dp_trace_data.head = 0;
		}
	}

	rec = &g_adf_dp_trace_tbl[g_adf_dp_trace_data.tail];
	index = g_adf_dp_trace_data.tail;
	rec->code = code;
	rec->size = 0;
	if (data != NULL && size > 0) {
		if (size > ADF_DP_TRACE_RECORD_SIZE)
			size = ADF_DP_TRACE_RECORD_SIZE;

		rec->size = size;
		adf_os_mem_copy(rec->data, data, size);

	}
	rec->time = adf_os_gettimestamp();
	rec->pid = (in_interrupt() ? 0 : current->pid);
	spin_unlock_bh(&l_dp_trace_lock);

	if ((g_adf_dp_trace_data.live_mode || print == true) &&
	    (rec->code < ADF_DP_TRACE_MAX))
		adf_dp_trace_cb_table[rec->code] (rec, index);
}
Beispiel #7
0
adf_nbuf_t RxSgToSingleNetbuf(HTC_TARGET *target)
{
    adf_nbuf_t skb;
    a_uint8_t *anbdata;
    a_uint8_t *anbdata_new;
    a_uint32_t anblen;
    adf_nbuf_t new_skb = NULL;
    a_uint32_t sg_queue_len;
    adf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;

    sg_queue_len = adf_nbuf_queue_len(rx_sg_queue);

    if (sg_queue_len <= 1) {
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
            ("RxSgToSingleNetbuf: invalid sg queue len %u\n"));
        goto _failed;
    }

    new_skb = adf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, FALSE);
    if (new_skb == NULL) {
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
            ("RxSgToSingleNetbuf: can't allocate %u size netbuf\n",
                target->ExpRxSgTotalLen));
        goto _failed;
    }

    adf_nbuf_peek_header(new_skb, &anbdata_new, &anblen);

    skb = adf_nbuf_queue_remove(rx_sg_queue);
    do {
        adf_nbuf_peek_header(skb, &anbdata, &anblen);
        adf_os_mem_copy(anbdata_new, anbdata, adf_nbuf_len(skb));
        adf_nbuf_put_tail(new_skb, adf_nbuf_len(skb));
        anbdata_new += adf_nbuf_len(skb);
        adf_nbuf_free(skb);
        skb = adf_nbuf_queue_remove(rx_sg_queue);
    } while(skb != NULL);

    RESET_RX_SG_CONFIG(target);
    return new_skb;

_failed:

    while ((skb = adf_nbuf_queue_remove(rx_sg_queue)) != NULL) {
        adf_nbuf_free(skb);
    }

    RESET_RX_SG_CONFIG(target);
    return NULL;
}
Beispiel #8
0
/** 
 * @brief
 * 
 * @param sc
 * @param data
 * 
 * @return 
 */
static a_status_t   
acfg_iwevent_leave_ap(__adf_softc_t   *sc, acfg_ev_data_t    *data)
{
    union iwreq_data wreq = {{0}};

    wreq.addr.sa_family = ARPHRD_ETHER;
    adf_os_mem_copy(wreq.addr.sa_data, data->leave_ap.mac, ETH_ALEN);

    adf_trace(ADF_DEBUG_FUNCTRACE, "ADF_EVENT: LEAVE AP\n"); 

    wireless_send_event(hdl_to_netdev(sc), IWEVEXPIRED, &wreq, NULL);

    return A_STATUS_OK;
}
/**
 * adf_dp_trace_ptr() - record dptrace
 * @code: dptrace code
 * @data: data
 * @size: size of data
 * @msdu_id: msdu_id
 * @status: return status
 *
 * Return: none
 */
void adf_dp_trace_ptr(adf_nbuf_t nbuf, enum ADF_DP_TRACE_ID code,
		uint8_t *data, uint8_t size, uint16_t msdu_id, uint16_t status)
{
	struct adf_dp_trace_ptr_buf buf;
	int buf_size = sizeof(struct adf_dp_trace_ptr_buf);

	if (adf_dp_enable_check(nbuf, code, ADF_TX) == false)
		return;

	if (buf_size > ADF_DP_TRACE_RECORD_SIZE)
		ADF_BUG(0);

	adf_os_mem_copy(&buf.cookie, data, size);
	buf.msdu_id = msdu_id;
	buf.status = status;
	adf_dp_add_record(code, (uint8_t *)&buf, buf_size, false);
}
Beispiel #10
0
static inline A_STATUS
ol_tx_copy_native_wifi_header(
    adf_nbuf_t msdu,
    u_int8_t *hdsize,
    u_int8_t *localbuf)
{
    struct ieee80211_frame *wh = (struct ieee80211_frame*)adf_nbuf_data(msdu);
    if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
        *hdsize = sizeof(struct ieee80211_frame_addr4);
    } else {
        *hdsize = sizeof(struct ieee80211_frame);
    }
    if (adf_nbuf_len(msdu) < *hdsize) {
        return A_ERROR;
    }
    adf_os_mem_copy(localbuf, wh, *hdsize);
    return A_OK;
}
Beispiel #11
0
void _wmi_cmd_rsp(void *pContext, WMI_COMMAND_ID cmd_id, A_UINT16 SeqNo,
		  A_UINT8 *buffer, int Length)
{
	adf_nbuf_t netbuf = ADF_NBUF_NULL;
	A_UINT8 *pData;

	netbuf = WMI_AllocEvent(pContext, WMI_EVT_CLASS_CMD_REPLY, sizeof(WMI_CMD_HDR) + Length);

	if (netbuf == ADF_NBUF_NULL) {
		adf_os_print("%s: buffer allocation for event_id %x failed!\n", __FUNCTION__, cmd_id);
		adf_os_assert(0);
		return;
	}

	if (Length != 0 && buffer != NULL) {
		pData = (A_UINT8 *)adf_nbuf_put_tail(netbuf, Length);
		adf_os_mem_copy(pData, buffer, Length);
	}

	WMI_SendEvent(pContext, netbuf, cmd_id, SeqNo, Length);
}
Beispiel #12
0
static inline A_STATUS
ol_tx_encap_from_native_wifi (
    struct ol_txrx_vdev_t *vdev,
    struct ol_tx_desc_t *tx_desc,
    adf_nbuf_t msdu,
    struct ol_txrx_msdu_info_t *tx_msdu_info
)
{
    u_int8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4)];
    struct ieee80211_frame *wh;
    u_int8_t hdsize, new_hdsize;
    struct ieee80211_qoscntl *qos_cntl;
    struct ol_txrx_peer_t *peer;

    if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) {
        return A_OK;
    }
    peer = tx_msdu_info->peer;
    /*
     * for unicast,the peer should not be NULL.
     * for multicast, the peer is AP.
     */
    if (tx_msdu_info->htt.info.is_unicast
        && peer->qos_capable)
    {
        if (A_OK != ol_tx_copy_native_wifi_header(msdu, &hdsize, localbuf))
            return A_ERROR;
        wh = (struct ieee80211_frame*)localbuf;

        /*add qos cntl*/
        qos_cntl = (struct ieee80211_qoscntl*)(localbuf + hdsize);
        qos_cntl->i_qos[0] = tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID;

#if 0
        if ( wmmParam[ac].wmep_noackPolicy ) {
            qos_cntl->i_qos[0]|= 1 << IEEE80211_QOS_ACKPOLICY_S;
        }
#endif

        qos_cntl->i_qos[1] = 0;
        wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
        /* count for qos field */
        new_hdsize = hdsize + sizeof(struct ieee80211_qosframe) - sizeof(struct ieee80211_frame);

        /*add ht control field if needed */

        /* copy new hd to bd */
        adf_os_mem_copy(
                       (void*)htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, new_hdsize),
                       localbuf,
                       new_hdsize);
        adf_nbuf_pull_head(msdu, hdsize);
        tx_msdu_info->htt.info.l3_hdr_offset = new_hdsize;
        tx_desc->orig_l2_hdr_bytes = hdsize;
    }
    /* Set Protected Frame bit in MAC header */
    if (vdev->pdev->sw_pf_proc_enable && tx_msdu_info->htt.action.do_encrypt) {
        if (tx_desc->orig_l2_hdr_bytes) {
            wh = (struct ieee80211_frame*)htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc,
                tx_msdu_info->htt.info.l3_hdr_offset);
        } else {
            if (A_OK != ol_tx_copy_native_wifi_header(msdu, &hdsize, localbuf))
                return A_ERROR;
            wh = (struct ieee80211_frame*)htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, hdsize);
            adf_os_mem_copy((void*)wh, localbuf, hdsize);
            adf_nbuf_pull_head(msdu, hdsize);
            tx_msdu_info->htt.info.l3_hdr_offset = hdsize;
            tx_desc->orig_l2_hdr_bytes = hdsize;
        }
        wh->i_fc[1] |= IEEE80211_FC1_WEP;
    }
    return A_OK;
}
Beispiel #13
0
void * __ahdecl
ath_hal_memcpy(void *dst, const void *src, adf_os_size_t n)
{
	adf_os_mem_copy(dst, src, n);
	return 0;
}
/* Target to host Msg/event  handler  for low priority messages*/
void
htt_t2h_lp_msg_handler(void *context, adf_nbuf_t htt_t2h_msg )
{
    struct htt_pdev_t *pdev = (struct htt_pdev_t *) context;
    u_int32_t *msg_word;
    enum htt_t2h_msg_type msg_type;

    msg_word = (u_int32_t *) adf_nbuf_data(htt_t2h_msg);
    msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
    switch (msg_type) {
    case HTT_T2H_MSG_TYPE_VERSION_CONF:
        {
            htc_pm_runtime_put(pdev->htc_pdev);
            pdev->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word);
            pdev->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word);
            adf_os_print("target uses HTT version %d.%d; host uses %d.%d\n",
                pdev->tgt_ver.major, pdev->tgt_ver.minor,
                HTT_CURRENT_VERSION_MAJOR, HTT_CURRENT_VERSION_MINOR);
            if (pdev->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR) {
                adf_os_print("*** Incompatible host/target HTT versions!\n");
            }
            /* abort if the target is incompatible with the host */
            adf_os_assert(pdev->tgt_ver.major == HTT_CURRENT_VERSION_MAJOR);
            if (pdev->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) {
                adf_os_print(
                    "*** Warning: host/target HTT versions are different, "
                    "though compatible!\n");
            }
            break;
        }
    case HTT_T2H_MSG_TYPE_RX_FLUSH:
        {
            u_int16_t peer_id;
            u_int8_t tid;
            int seq_num_start, seq_num_end;
            enum htt_rx_flush_action action;

            peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word);
            tid = HTT_RX_FLUSH_TID_GET(*msg_word);
            seq_num_start = HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word+1));
            seq_num_end = HTT_RX_FLUSH_SEQ_NUM_END_GET(*(msg_word+1));
            action =
                HTT_RX_FLUSH_MPDU_STATUS_GET(*(msg_word+1)) == 1 ?
                htt_rx_flush_release : htt_rx_flush_discard;
            ol_rx_flush_handler(
                pdev->txrx_pdev,
                peer_id, tid,
                seq_num_start,
                seq_num_end,
                action);
            break;
        }
    case  HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND:
        {
            int msdu_cnt;
            msdu_cnt = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(*msg_word);
            ol_rx_offload_deliver_ind_handler(
                pdev->txrx_pdev,
                htt_t2h_msg,
                msdu_cnt);
            break;
        }
    case  HTT_T2H_MSG_TYPE_RX_FRAG_IND:
        {
            u_int16_t peer_id;
            u_int8_t tid;

            peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word);
            tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word);
            HTT_RX_FRAG_SET_LAST_MSDU(pdev, htt_t2h_msg);

            ol_rx_frag_indication_handler(
                pdev->txrx_pdev,
                htt_t2h_msg,
                peer_id,
                tid);
            break;
        }
    case HTT_T2H_MSG_TYPE_RX_ADDBA:
        {
            u_int16_t peer_id;
            u_int8_t tid;
            u_int8_t win_sz;
            u_int16_t start_seq_num;

            /*
             * FOR NOW, the host doesn't need to know the initial
             * sequence number for rx aggregation.
             * Thus, any value will do - specify 0.
             */
            start_seq_num = 0;
            peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word);
            tid = HTT_RX_ADDBA_TID_GET(*msg_word);
            win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word);
            ol_rx_addba_handler(
                pdev->txrx_pdev, peer_id, tid, win_sz, start_seq_num,
                0 /* success */);
            break;
        }
    case HTT_T2H_MSG_TYPE_RX_DELBA:
        {
            u_int16_t peer_id;
            u_int8_t tid;

            peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word);
            tid = HTT_RX_DELBA_TID_GET(*msg_word);
            ol_rx_delba_handler(pdev->txrx_pdev, peer_id, tid);
            break;
        }
    case HTT_T2H_MSG_TYPE_PEER_MAP:
        {
            u_int8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN];
            u_int8_t *peer_mac_addr;
            u_int16_t peer_id;
            u_int8_t vdev_id;

            peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word);
            vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word);
            peer_mac_addr = htt_t2h_mac_addr_deswizzle(
                (u_int8_t *) (msg_word+1), &mac_addr_deswizzle_buf[0]);

            ol_rx_peer_map_handler(
                pdev->txrx_pdev, peer_id, vdev_id, peer_mac_addr, 1/*can tx*/);
            break;
        }
    case HTT_T2H_MSG_TYPE_PEER_UNMAP:
        {
            u_int16_t peer_id;
            peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word);

            ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id);
            break;
        }
    case HTT_T2H_MSG_TYPE_SEC_IND:
        {
            u_int16_t peer_id;
            enum htt_sec_type sec_type;
            int is_unicast;

            peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word);
            sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word);
            is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word);
            msg_word++; /* point to the first part of the Michael key */
            ol_rx_sec_ind_handler(
                pdev->txrx_pdev, peer_id, sec_type, is_unicast, msg_word, msg_word+2);
            break;
        }
    case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND:
        {
            struct htt_mgmt_tx_compl_ind *compl_msg;

            compl_msg = (struct htt_mgmt_tx_compl_ind *)(msg_word + 1);
            if (pdev->cfg.is_high_latency) {
                ol_tx_target_credit_update(pdev->txrx_pdev, 1);
            }
            ol_tx_single_completion_handler(
                pdev->txrx_pdev, compl_msg->status, compl_msg->desc_id);
            htc_pm_runtime_put(pdev->htc_pdev);
            HTT_TX_SCHED(pdev);
            break;
        }
#if TXRX_STATS_LEVEL != TXRX_STATS_LEVEL_OFF
    case HTT_T2H_MSG_TYPE_STATS_CONF:
        {
            u_int64_t cookie;
            u_int8_t *stats_info_list;

            cookie = *(msg_word + 1);
            cookie |= ((u_int64_t) (*(msg_word + 2))) << 32;

            stats_info_list = (u_int8_t *) (msg_word + 3);
            htc_pm_runtime_put(pdev->htc_pdev);
            ol_txrx_fw_stats_handler(pdev->txrx_pdev, cookie, stats_info_list);
            break;
        }
#endif
#ifndef REMOVE_PKT_LOG
    case HTT_T2H_MSG_TYPE_PKTLOG:
        {
            u_int32_t *pl_hdr;
            u_int32_t log_type;
            pl_hdr = (msg_word + 1);
            log_type = (*(pl_hdr + 1) & ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
                                            ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
            if (log_type == PKTLOG_TYPE_TX_CTRL ||
               (log_type) == PKTLOG_TYPE_TX_STAT ||
               (log_type) == PKTLOG_TYPE_TX_MSDU_ID ||
               (log_type) == PKTLOG_TYPE_TX_FRM_HDR ||
               (log_type) == PKTLOG_TYPE_TX_VIRT_ADDR) {
                wdi_event_handler(WDI_EVENT_TX_STATUS, pdev->txrx_pdev, pl_hdr);
            } else if ((log_type) == PKTLOG_TYPE_RC_FIND) {
                wdi_event_handler(WDI_EVENT_RATE_FIND, pdev->txrx_pdev, pl_hdr);
            } else if ((log_type) == PKTLOG_TYPE_RC_UPDATE) {
                wdi_event_handler(
                    WDI_EVENT_RATE_UPDATE, pdev->txrx_pdev, pl_hdr);
            } else if ((log_type) == PKTLOG_TYPE_RX_STAT) {
                wdi_event_handler(WDI_EVENT_RX_DESC, pdev->txrx_pdev, pl_hdr);
            }
            break;
        }
#endif
    case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
    {
        u_int32_t htt_credit_delta_abs;
        int32_t htt_credit_delta;
        int sign;

        htt_credit_delta_abs = HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word);
        sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1;
        htt_credit_delta = sign * htt_credit_delta_abs;
        ol_tx_credit_completion_handler(pdev->txrx_pdev, htt_credit_delta);
        break;
    }

#ifdef IPA_UC_OFFLOAD
    case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE:
        {
            u_int8_t op_code;
            u_int16_t len;
            u_int8_t *op_msg_buffer;
            u_int8_t *msg_start_ptr;

            htc_pm_runtime_put(pdev->htc_pdev);
            msg_start_ptr = (u_int8_t *)msg_word;
            op_code = HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word);
            msg_word++;
            len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word);

            op_msg_buffer = adf_os_mem_alloc(NULL,
                sizeof(struct htt_wdi_ipa_op_response_t) + len);
            if (!op_msg_buffer) {
                adf_os_print("OPCODE messsage buffer alloc fail");
                break;
            }
            adf_os_mem_copy(op_msg_buffer,
                    msg_start_ptr,
                    sizeof(struct htt_wdi_ipa_op_response_t) + len);
            ol_txrx_ipa_uc_op_response(pdev->txrx_pdev, op_msg_buffer);
            break;
        }
#endif /* IPA_UC_OFFLOAD */

    default:
        break;
    };
    /* Free the indication buffer */
    adf_nbuf_free(htt_t2h_msg);
}
Beispiel #15
0
void
ieee80211_add_vap_target(struct ieee80211vap *vap)
{
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211vap_target vt;
    int i;
    u_int8_t vapindex = 0;

#if 0
    /* Dump mac address */
    printk("%s, mac: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
        __FUNCTION__, vap->iv_myaddr[0], vap->iv_myaddr[1], vap->iv_myaddr[2],
        vap->iv_myaddr[3], vap->iv_myaddr[4], vap->iv_myaddr[5]);
#endif

    for (i = 0; i < HTC_MAX_VAP_NUM; i++) {
        /* avoid upper layer add the same vap twice */
        if (IEEE80211_ADDR_EQ(ic->target_vap_bitmap[i].vap_macaddr, vap->iv_myaddr)) {
            printk("%s: add the same vap twice\n", __FUNCTION__);
            return;
        }

        if (ic->target_vap_bitmap[i].vap_valid == 0) {
            printk("%s: target_vap_bitmap(%d) is invalid\n", __FUNCTION__, i);

            IEEE80211_ADDR_COPY(ic->target_vap_bitmap[i].vap_macaddr, vap->iv_myaddr);
            ic->target_vap_bitmap[i].vap_valid = 1;
            vapindex = i;
            break;
        }
        else {
#if 0        	
            printk("%s: target_vap_bitmap(%d) vap_valid = %d\n", __FUNCTION__, i,
            ic->target_vap_bitmap[i].vap_valid);
#endif            
        }
    }

    printk("%s: vap index: %d\n", __FUNCTION__, vapindex);

    /* If we can't find any suitable vap entry */
    if (i == HTC_MAX_VAP_NUM) {
        printk("%s: exceed maximum vap number\n", __FUNCTION__);
        return;
    }

    vt.iv_create_flags = cpu_to_be32(vap->iv_create_flags);
    vt.iv_vapindex = vapindex;
    vt.iv_opmode = cpu_to_be32(vap->iv_opmode);
    vt.iv_mcast_rate = 0;
    vt.iv_rtsthreshold = cpu_to_be16(2304);
    adf_os_mem_copy(&vt.iv_myaddr, &(vap->iv_myaddr), IEEE80211_ADDR_LEN);

#if ENCAP_OFFLOAD
    adf_os_mem_copy(&vt.iv_myaddr, &(vap->iv_myaddr), IEEE80211_ADDR_LEN);
#endif
    /* save information to vap target */
    ic->target_vap_bitmap[vapindex].iv_vapindex = vapindex;
    ic->target_vap_bitmap[vapindex].iv_opmode = vap->iv_opmode;
    ic->target_vap_bitmap[vapindex].iv_mcast_rate = vap->iv_mcast_rate;
    ic->target_vap_bitmap[vapindex].iv_rtsthreshold = 2304;

    ic->ic_add_vap_target(ic, &vt, sizeof(vt));

    //printk("%s Exit \n", __FUNCTION__);
}
Beispiel #16
0
static inline A_STATUS
ol_tx_encap_from_8023 (
    struct ol_txrx_vdev_t *vdev,
    struct ol_tx_desc_t *tx_desc,
    adf_nbuf_t msdu,
    struct ol_txrx_msdu_info_t *tx_msdu_info
)
{
    u_int8_t localbuf[ sizeof(struct ieee80211_qosframe_htc_addr4) \
                       + sizeof(struct llc_snap_hdr_t)];
    struct llc_snap_hdr_t *llc_hdr;
    struct ethernet_hdr_t *eth_hdr;
    struct ieee80211_frame *wh;
    u_int8_t hdsize, new_l2_hdsize, new_hdsize;
    struct ieee80211_qoscntl *qos_cntl;
    const u_int8_t ethernet_II_llc_snap_header_prefix[] = \
                                { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
    struct ol_txrx_peer_t *peer;
    u_int16_t ether_type;

    if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data)
        return A_OK;

    /*
     * for unicast,the peer should not be NULL.
     * for multicast, the peer is AP.
     */
    peer = tx_msdu_info->peer;

    eth_hdr = (struct ethernet_hdr_t *)adf_nbuf_data(msdu);
    hdsize = sizeof(struct ethernet_hdr_t);
    wh = (struct ieee80211_frame *)localbuf;
    wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
    *(u_int16_t *)wh->i_dur = 0;
    new_hdsize = 0;

    switch (vdev->opmode) {
    case wlan_op_mode_ap:
        /* DA , BSSID , SA*/
        adf_os_mem_copy(wh->i_addr1, eth_hdr->dest_addr,
                        IEEE80211_ADDR_LEN);
        adf_os_mem_copy(wh->i_addr2, &vdev->mac_addr.raw,
                        IEEE80211_ADDR_LEN);
        adf_os_mem_copy(wh->i_addr3, eth_hdr->src_addr,
                        IEEE80211_ADDR_LEN);
        wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
        new_hdsize = sizeof(struct ieee80211_frame);
        break;
    case wlan_op_mode_ibss:
        /* DA, SA, BSSID */
        adf_os_mem_copy(wh->i_addr1, eth_hdr->dest_addr,
                        IEEE80211_ADDR_LEN);
        adf_os_mem_copy(wh->i_addr2, eth_hdr->src_addr,
                        IEEE80211_ADDR_LEN);
         /* need to check the bssid behaviour for IBSS vdev */
        adf_os_mem_copy(wh->i_addr3, &vdev->mac_addr.raw,
                        IEEE80211_ADDR_LEN);
        wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
        new_hdsize = sizeof(struct ieee80211_frame);
        break;
    case wlan_op_mode_sta:
        /* BSSID, SA , DA*/
        adf_os_mem_copy(wh->i_addr1, &peer->mac_addr.raw,
                        IEEE80211_ADDR_LEN);
        adf_os_mem_copy(wh->i_addr2, eth_hdr->src_addr,
                        IEEE80211_ADDR_LEN);
        adf_os_mem_copy(wh->i_addr3, eth_hdr->dest_addr,
                        IEEE80211_ADDR_LEN);
        wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
        new_hdsize = sizeof(struct ieee80211_frame);
        break;
    case wlan_op_mode_monitor:
    default:
        return A_ERROR;
    }
    /*add qos cntl*/
    if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable ) {
        qos_cntl = (struct ieee80211_qoscntl*)(localbuf + new_hdsize);
        qos_cntl->i_qos[0] = tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID;
        wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
#if 0
        if ( wmmParam[ac].wmep_noackPolicy ) {
            qos_cntl->i_qos[0]|= 1 << IEEE80211_QOS_ACKPOLICY_S;
        }
#endif
        qos_cntl->i_qos[1] = 0;
        new_hdsize += sizeof(struct ieee80211_qoscntl);

        /*add ht control field if needed */
    }
    /* Set Protected Frame bit in MAC header */
    if (vdev->pdev->sw_pf_proc_enable && tx_msdu_info->htt.action.do_encrypt) {
        wh->i_fc[1] |= IEEE80211_FC1_WEP;
    }
    new_l2_hdsize = new_hdsize;
    /* add llc snap if needed */
    if (vdev->pdev->sw_tx_llc_proc_enable) {
        llc_hdr = (struct llc_snap_hdr_t *) (localbuf + new_hdsize);
        ether_type = (eth_hdr->ethertype[0]<<8) |(eth_hdr->ethertype[1]);
        if ( ether_type >= IEEE8023_MAX_LEN ) {
            adf_os_mem_copy(llc_hdr,
                            ethernet_II_llc_snap_header_prefix,
                            sizeof(ethernet_II_llc_snap_header_prefix));
            if ( ether_type == ETHERTYPE_AARP || ether_type == ETHERTYPE_IPX) {
                llc_hdr->org_code[2] = BTEP_SNAP_ORGCODE_2;// 0xf8; bridge tunnel header
            }
            llc_hdr->ethertype[0] = eth_hdr->ethertype[0];
            llc_hdr->ethertype[1] = eth_hdr->ethertype[1];
            new_hdsize += sizeof(struct llc_snap_hdr_t);
        }
        else {
            /*llc ready, and it's in payload pdu, do we need to move to BD pdu?*/
        }
    }
    adf_os_mem_copy(
                    (void*)htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc,new_l2_hdsize),
                    localbuf,
                    new_hdsize);
    adf_nbuf_pull_head(msdu,hdsize);
    tx_msdu_info->htt.info.l3_hdr_offset = new_l2_hdsize;
    tx_desc->orig_l2_hdr_bytes = hdsize;
    return A_OK;
}
Beispiel #17
0
static inline void
ol_rx_decap_to_8023 (
    struct ol_txrx_vdev_t *vdev,
    adf_nbuf_t msdu,
    struct ol_rx_decap_info_t *info,
    struct ethernet_hdr_t *ethr_hdr)
{
    struct llc_snap_hdr_t *llc_hdr;
    u_int16_t ether_type;
    u_int16_t l2_hdr_space;
    struct ieee80211_frame_addr4 *wh;
    u_int8_t local_buf[ETHERNET_HDR_LEN];
    u_int8_t *buf;

    /*
    * populate Ethernet header,
    * if ethr_hdr is null, rx frame is 802.11 format(HW ft disabled)
    * if ethr_hdr is not null, rx frame is "subfrm of amsdu".
    */
    buf = (u_int8_t *)adf_nbuf_data(msdu);
    llc_hdr = (struct llc_snap_hdr_t *)buf;
    ether_type = (llc_hdr->ethertype[0] << 8)|llc_hdr->ethertype[1];
    /* do llc remove if needed */
    l2_hdr_space = 0;
    if (IS_SNAP(llc_hdr)) {
        if (IS_BTEP(llc_hdr)) {
            /* remove llc*/
            l2_hdr_space += sizeof(struct llc_snap_hdr_t);
            llc_hdr = NULL;
        }
        else if (IS_RFC1042(llc_hdr)) {
            if ( !(ether_type == ETHERTYPE_AARP ||
                  ether_type == ETHERTYPE_IPX) ) {
                /* remove llc*/
                l2_hdr_space += sizeof(struct llc_snap_hdr_t);
                llc_hdr = NULL;
            }
        }
    }
    if (l2_hdr_space > ETHERNET_HDR_LEN) {
        buf = adf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN);
    }
    else if (l2_hdr_space <  ETHERNET_HDR_LEN) {
        buf = adf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space);
    }

    /* normal msdu(non-subfrm of A-MSDU) if ethr_hdr is null */
    if (ethr_hdr == NULL) {
        /* mpdu hdr should be present in info,re-create ethr_hdr based on mpdu hdr*/
        TXRX_ASSERT2(info->hdr_len != 0);
        wh = (struct ieee80211_frame_addr4 *)info->hdr;
        ethr_hdr = (struct ethernet_hdr_t *)local_buf;
        switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        case IEEE80211_FC1_DIR_NODS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr2, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_TODS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr2, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_FROMDS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr3, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_DSTODS:
            adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr4, ETHERNET_ADDR_LEN);
            break;
        }
    }
    if (llc_hdr == NULL) {
        ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff;
        ethr_hdr->ethertype[1] = (ether_type) & 0xff;
    }
Beispiel #18
0
static void usb_hif_usb_recv_bundle_complete(struct urb *urb)
{
	HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context;
	A_STATUS status = A_OK;
	adf_nbuf_t buf = NULL;
	HIF_USB_PIPE *pipe = urb_context->pipe;
	A_UINT8 *netdata, *netdata_new;
	A_UINT32 netlen, netlen_new;
	HTC_FRAME_HDR *HtcHdr;
	A_UINT16 payloadLen;
	adf_nbuf_t new_skb = NULL;

	AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, (
			 "+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p\n",
			 __func__,
			 pipe->logical_pipe_num,
			 urb->status, urb->actual_length,
			 urb));

	/* this urb is not pending anymore */
	usb_hif_remove_pending_transfer(urb_context);

	do {

		if (urb->status != 0) {
			status = A_ECOMM;
			switch (urb->status) {
			case -ECONNRESET:
			case -ENOENT:
			case -ESHUTDOWN:
				/* NOTE: no need to spew these errors when
				 * device is removed
				 * or urb is killed due to driver shutdown
				 */
				status = A_ECANCELED;
				break;
			default:
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
						 "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n",
						 __func__,
						 pipe->logical_pipe_num,
						 pipe->ep_address,
						 urb->status));
				break;
			}
			break;
		}

		if (urb->actual_length == 0)
			break;

		buf = urb_context->buf;

		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
			A_UINT8 *data;
			A_UINT32 len;
			adf_nbuf_peek_header(buf, &data, &len);
			DebugDumpBytes(data, len, "hif recv data");
		}

		adf_nbuf_peek_header(buf, &netdata, &netlen);
		netlen = urb->actual_length;

		do {
#if defined(AR6004_1_0_ALIGN_WAR)
			A_UINT8 extra_pad;
			A_UINT16 act_frame_len;
#endif
			A_UINT16 frame_len;

			/* Hack into HTC header for bundle processing */
			HtcHdr = (HTC_FRAME_HDR *) netdata;
			if (HtcHdr->EndpointID >= ENDPOINT_MAX) {
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
					("athusb: Rx: invalid EndpointID=%d\n",
					HtcHdr->EndpointID));
				break;
			}

			payloadLen = HtcHdr->PayloadLen;
			payloadLen = A_LE2CPU16(payloadLen);

#if defined(AR6004_1_0_ALIGN_WAR)
			act_frame_len = (HTC_HDR_LENGTH + payloadLen);

			if (HtcHdr->EndpointID == 0 ||
				HtcHdr->EndpointID == 1) {
				/* assumption: target won't pad on HTC endpoint
				 * 0 & 1.
				 */
				extra_pad = 0;
			} else {
				extra_pad =
				    A_GET_UINT8_FIELD((A_UINT8 *) HtcHdr,
						      HTC_FRAME_HDR,
						      ControlBytes[1]);
			}
#endif

			if (payloadLen > HIF_USB_RX_BUFFER_SIZE) {
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
					("athusb: payloadLen too long %u\n",
					payloadLen));
				break;
			}
#if defined(AR6004_1_0_ALIGN_WAR)
			frame_len = (act_frame_len + extra_pad);
#else
			frame_len = (HTC_HDR_LENGTH + payloadLen);
#endif

			if (netlen >= frame_len) {
				/* allocate a new skb and copy */
#if defined(AR6004_1_0_ALIGN_WAR)
				new_skb =
				    adf_nbuf_alloc(NULL, act_frame_len, 0, 4,
						   FALSE);
				if (new_skb == NULL) {
					AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
							 "athusb: allocate skb (len=%u) failed\n",
							 act_frame_len));
					break;
				}

				adf_nbuf_peek_header(new_skb, &netdata_new,
						     &netlen_new);
				adf_os_mem_copy(netdata_new, netdata,
						act_frame_len);
				adf_nbuf_put_tail(new_skb, act_frame_len);
#else
				new_skb =
				    adf_nbuf_alloc(NULL, frame_len, 0, 4,
						   FALSE);
				if (new_skb == NULL) {
					AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
							 "athusb: allocate skb (len=%u) failed\n",
							 frame_len));
					break;
				}

				adf_nbuf_peek_header(new_skb, &netdata_new,
						     &netlen_new);
				adf_os_mem_copy(netdata_new, netdata,
						frame_len);
				adf_nbuf_put_tail(new_skb, frame_len);
#endif
				skb_queue_tail(&pipe->io_comp_queue, new_skb);
				new_skb = NULL;

				netdata += frame_len;
				netlen -= frame_len;
			} else {
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
					 "athusb: subframe length %d not fitted into bundle packet length %d\n"
					 , netlen, frame_len));
				break;
			}

		} while (netlen);

		schedule_work(&pipe->io_complete_work);

	} while (FALSE);

	if (urb_context->buf == NULL) {
		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
				("athusb: buffer in urb_context is NULL\n"));
	}

	/* reset urb_context->buf ==> seems not necessary */
	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);

	if (A_SUCCESS(status)) {
		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
			/* our free urbs are piling up, post more transfers */
			usb_hif_post_recv_bundle_transfers(pipe, 0
			/* pass zero for not allocating urb-buffer again */
			    );
		}
	}

	AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-%s\n", __func__));
}