예제 #1
0
rpc_buf_t *
bcm_rpc_tp_buf_alloc(rpc_tp_info_t * rpc_th, int len)
{
	rpc_buf_t * b;
	size_t tp_len = len + BCM_RPC_TP_ENCAP_LEN;
	size_t padlen;

#ifdef BCMUSBDEV
	padlen = MAX(BCM_RPC_TP_DNGL_TOTLEN_BAD_PAD, BCM_RPC_TP_DNGL_ZLP_PAD);
	padlen = ROUNDUP(padlen, sizeof(int));
#else
	padlen = 0;
#endif /* BCMUSBDEV */

	/* get larger packet with  padding which might be required due to USB ZLP */
	b = (rpc_buf_t*)PKTGET(rpc_th->osh, tp_len + padlen, FALSE);

	if (b != NULL) {
		rpc_th->bufalloc++;
		rpc_th->buf_cnt_inuse++;
		/* set the len back to tp_len */
		bcm_rpc_buf_len_set(rpc_th, b, tp_len);
		PKTPULL(rpc_th->osh, b, BCM_RPC_TP_ENCAP_LEN);
	}

	return b;
}
static void
dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh)
{
	int prec;
	struct pktq *q;
	uint count = 0;

	q = dhd_bus_txq(pub->bus);
	if (q == NULL)
		return;

	DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh));

	dhd_os_sdlock_txq(pub);

	/* Walk through the txq and toss all HCI ACL data packets */
	PKTQ_PREC_ITER(q, prec) {
		void *head_pkt = NULL;

		while (pktq_ppeek(q, prec) != head_pkt) {
			void *pkt = pktq_pdeq(q, prec);
			int ifidx;

			PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus));
			dhd_prot_hdrpull(pub, &ifidx, pkt);

			if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
				struct ether_header *eh =
				        (struct ether_header *)PKTDATA(pub->osh, pkt);

				if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
					struct dot11_llc_snap_header *lsh =
					        (struct dot11_llc_snap_header *)&eh[1];

					if (bcmp(lsh, BT_SIG_SNAP_MPROT,
					         DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
					    ntoh16(lsh->type) == BTA_PROT_L2CAP) {
						amp_hci_ACL_data_t *ACL_data =
						        (amp_hci_ACL_data_t *)&lsh[1];
						uint16 handle = ltoh16(ACL_data->handle);

						if (HCI_ACL_DATA_HANDLE(handle) == llh) {
							PKTFREE(pub->osh, pkt, TRUE);
							count ++;
							continue;
						}
					}
				}
			}

			dhd_prot_hdrpush(pub, ifidx, pkt);
			PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus));

			if (head_pkt == NULL)
				head_pkt = pkt;
			pktq_penq(q, prec, pkt);
		}
	}
예제 #3
0
/* external pkt allocation, with extra BCM_RPC_TP_ENCAP_LEN */
rpc_buf_t *
bcm_rpc_tp_buf_alloc(rpc_tp_info_t * rpcb, int len)
{
	rpc_buf_t *b;
	size_t tp_len = len + BCM_RPC_TP_ENCAP_LEN + BCM_RPC_BUS_HDR_LEN;

	b = bcm_rpc_tp_pktget(rpcb, tp_len, TRUE);

	if (b != NULL)
		PKTPULL(rpcb->osh, b, BCM_RPC_TP_ENCAP_LEN + BCM_RPC_BUS_HDR_LEN);

	return b;
}
예제 #4
0
int
dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
{
#ifdef BDC
	struct bdc_header *h;
#endif
	uint8 bdc_ver;

	DHD_TRACE(("%s: Enter\n", __FUNCTION__));

#ifdef BDC
	/* Pop BDC header used to convey priority for buses that don't */

	if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
		DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
		           PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
		return BCME_ERROR;
	}

	h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);

	if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) {
		DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
		           __FUNCTION__, *ifidx));
		return BCME_ERROR;
	}

	bdc_ver = (h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT;

	if ((bdc_ver != BDC_PROTO_VER) && (bdc_ver != 2)) {
		DHD_ERROR(("%s: non-BDC packet received, flags 0x%x, BDC %d\n",
		           dhd_ifname(dhd, *ifidx), h->flags, bdc_ver));
		return BCME_ERROR;
	}

	if (h->flags & BDC_FLAG_SUM_GOOD) {
		DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
		          dhd_ifname(dhd, *ifidx), h->flags));
		PKTSETSUMGOOD(pktbuf, TRUE);
	}

	PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));

	PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
#endif /* BDC */

	return 0;
}
예제 #5
0
/* totally bogus -- d11 hdr only + tx hdrs */
static void *
wlc_olpc_get_pkt(wlc_info_t *wlc, uint ac, uint* fifo)
{
    int buflen = (TXOFF + WL_OLPC_PKT_LEN);
    void* p = NULL;
    osl_t *osh = wlc->osh;
    const char* macaddr = NULL;
    struct dot11_header *hdr = NULL;

    if ((p = PKTGET(osh, buflen, TRUE)) == NULL) {
        WL_ERROR(("wl%d: %s: pktget error for len %d \n",
                  wlc->pub->unit, __FUNCTION__, buflen));
        goto fatal;
    }
    macaddr = WLC_MACADDR(wlc);

    WL_NONE(("pkt manip\n"));
    /* reserve TXOFF bytes of headroom */
    PKTPULL(osh, p, TXOFF);
    PKTSETLEN(osh, p, WL_OLPC_PKT_LEN);

    WL_NONE(("d11_hdr\n"));
    hdr = (struct dot11_header*)PKTDATA(osh, p);
    bzero((char*)hdr, WL_OLPC_PKT_LEN);
    hdr->fc = htol16(FC_DATA);
    hdr->durid = 0;
    bcopy((const char*)macaddr, (char*)&(hdr->a1.octet), ETHER_ADDR_LEN);
    bcopy((const char*)macaddr, (char*)&(hdr->a2.octet), ETHER_ADDR_LEN);
    bcopy((const char*)macaddr, (char*)&(hdr->a3.octet), ETHER_ADDR_LEN);
    hdr->seq = 0;
    WL_NONE(("prep raw 80211\n"));
    wlc->olpc_info->tx_cal_pkts = TRUE;
    /* frameid returned here -- ignore for now -- may speed up using this */
    (void)wlc_prep80211_raw(wlc, NULL, ac, TRUE, p, fifo);
    wlc->olpc_info->tx_cal_pkts = FALSE;

    return p;
fatal:
    return (NULL);
}
예제 #6
0
unsigned char*
bcm_rpc_buf_pull(rpc_tp_info_t * rpc_th, rpc_buf_t* b, uint bytes)
{
	return PKTPULL(rpc_th->osh, b, bytes);
}
예제 #7
0
void
bcm_rpc_tp_rx_from_dnglbus(rpc_tp_info_t *rpc_th, struct lbuf *lb)
{
	void *orig_p, *p;
	void *rpc_p, *rpc_prev;
	uint pktlen, tp_len, iter = 0;
	osl_t *osh;
	bool dbg_agg;
	uint dbg_data[16], i;	/* must fit host agg limit BCM_RPC_TP_HOST_AGG_MAX_SFRAME+1 */

	dbg_agg = FALSE;

	rpc_th->rx_cnt++;

	if (rpc_th->rx_pkt == NULL) {
		RPC_TP_ERR(("%s: no rpc rx fn, dropping\n", __FUNCTION__));
		rpc_th->rxdrop_cnt++;
		lb_free(lb);
		return;
	}
	orig_p = PKTFRMNATIVE(rpc_th->osh, lb);


	osh = rpc_th->osh;

	/* take ownership of the dnglbus packet chain
	 * since it will be freed by bcm_rpc_tp_buf_free()
	 */
	rpc_th->buf_cnt_inuse += pktsegcnt(rpc_th->osh, orig_p);

	dbg_data[0] = pktsegcnt(rpc_th->osh, orig_p);

	pktlen = PKTLEN(osh, orig_p);

	p = orig_p;

	/* while we have more data in the TP frame's packet chain,
	 *   create a packet chain(could be cloned) for the next RPC frame
	 *   then give it away to high layer for process(buffer not freed)
	 */
	while (p != NULL) {
		iter++;

		/* read TP_HDR(len of rpc frame) and pull the data pointer past the length word */
		if (pktlen >= BCM_RPC_TP_ENCAP_LEN) {
			ASSERT(((uint)PKTDATA(osh, p) & 0x3) == 0); /* ensure aligned word read */
			tp_len = ltoh32(*(uint32*)PKTDATA(osh, p));
			PKTPULL(osh, p, BCM_RPC_TP_ENCAP_LEN);
			pktlen -= BCM_RPC_TP_ENCAP_LEN;
		} else {
			/* error case: less data than the encapsulation size
			 * treat as an empty tp buffer, at end of current buffer
			 */
			tp_len = 0;
			pktlen = 0;

			rpc_th->tp_dngl_deagg_cnt_badsflen++;	/* bad sf len */
		}

		/* if TP header finished a buffer(rpc header in next chained buffer), open next */
		if (pktlen == 0) {
			void *next_p = PKTNEXT(osh, p);
			PKTSETNEXT(osh, p, NULL);
			rpc_th->buf_cnt_inuse--;
			PKTFREE(osh, p, FALSE);
			p = next_p;
			if (p)
				pktlen = PKTLEN(osh, p);
		}

		dbg_data[iter] = tp_len;

		if (tp_len < pktlen || dbg_agg) {
			dbg_agg = TRUE;
			RPC_TP_DEAGG(("DEAGG: [%d] p %p data %p pktlen %d tp_len %d\n",
				iter, p, PKTDATA(osh, p), pktlen, tp_len));
			rpc_th->tp_dngl_deagg_cnt_sf++;
			rpc_th->tp_dngl_deagg_cnt_bytes += tp_len;
		}

		/* empty TP buffer (special case: use tp_len to pad for some USB pktsize bugs) */
		if (tp_len == 0) {
			rpc_th->tp_dngl_deagg_cnt_pass++;
			continue;
		} else if (tp_len > 10000 ) {	/* something is wrong */
			/* print out msgs according to value of p  -- in case it is NULL */
			if (p != NULL) {
				RPC_TP_ERR(("DEAGG: iter %d, p(%p data %p pktlen %d)\n",
					iter, p, PKTDATA(osh, p), PKTLEN(osh, p)));
			} else {
				RPC_TP_ERR(("DEAGG: iter %d, p is NULL", iter));
			}
		}

		/* ========= For this TP subframe, find the end, build a chain, sendup ========= */

		/* RPC frame packet chain starts with this packet */
		rpc_prev = NULL;
		rpc_p = p;
		ASSERT(p != NULL);

		/* find the last frag in this rpc chain */
		while ((tp_len >= pktlen) && p) {
			if (dbg_agg)
				RPC_TP_DEAGG(("DEAGG: tp_len %d consumes p(%p pktlen %d)\n", tp_len,
					p, pktlen));
			rpc_prev = p;
			p = PKTNEXT(osh, p);
			tp_len -= pktlen;

			if (p != NULL) {
				pktlen = PKTLEN(osh, p);
			} else {
				if (tp_len != 0) {
					uint totlen, seg;
					totlen = pkttotlen(osh, rpc_p);
					seg = pktsegcnt(rpc_th->osh, rpc_p);

					RPC_TP_ERR(("DEAGG, toss[%d], orig_p %p segcnt %d",
					       iter, orig_p, dbg_data[0]));
					RPC_TP_ERR(("DEAGG,rpc_p %p totlen %d pktl %d tp_len %d\n",
					       rpc_p, totlen, pktlen, tp_len));
					for (i = 1; i <= iter; i++)
						RPC_TP_ERR(("tplen[%d] = %d  ", i, dbg_data[i]));
					RPC_TP_ERR(("\n"));
					p = rpc_p;
					while (p != NULL) {
						RPC_TP_ERR(("this seg len %d\n", PKTLEN(osh, p)));
						p = PKTNEXT(osh, p);
					}

					rpc_th->buf_cnt_inuse -= seg;
					PKTFREE(osh, rpc_p, FALSE);
					rpc_th->tp_dngl_deagg_cnt_badfmt++;

					/* big hammer to recover USB
					 * extern void dngl_reboot(void); dngl_reboot();
					 */
					goto end;
				}
				pktlen = 0;
				break;
			}
		}

		/* fix up the last frag */
		if (tp_len == 0) {
			/* if the whole RPC buffer chain ended at the end of the prev TP buffer,
			 *    end the RPC buffer chain. we are done
			 */
			if (dbg_agg)
				RPC_TP_DEAGG(("DEAGG: END rpc chain p %p len %d\n\n", rpc_prev,
					pktlen));

			PKTSETNEXT(osh, rpc_prev, NULL);
			if (iter > 1) {
				rpc_th->tp_dngl_deagg_cnt_chain++;
				RPC_TP_DEAGG(("this frag %d totlen %d\n", pktlen,
					pkttotlen(osh, orig_p)));
			}

		} else {
			/* if pktlen has more bytes than tp_len, another tp frame must follow
			 *   create a clone of the sub-range of the current TP buffer covered
			 *   by the RPC buffer, attach to the end of the RPC buffer chain
			 *   (cut off the original chain link)
			 *   continue chain looping(p != NULL)
			 */
			void *new_p;
			ASSERT(p != NULL);

			RPC_TP_DEAGG(("DEAGG: cloning %d bytes out of p(%p data %p) len %d\n",
				tp_len, p, PKTDATA(osh, p), pktlen));

			new_p = osl_pktclone(osh, p, 0, tp_len);
			rpc_th->buf_cnt_inuse++;
			rpc_th->tp_dngl_deagg_cnt_clone++;

			RPC_TP_DEAGG(("DEAGG: after clone, newp(%p data %p pktlen %d)\n",
				new_p, PKTDATA(osh, new_p), PKTLEN(osh, new_p)));

			if (rpc_prev) {
				RPC_TP_DEAGG(("DEAGG: chaining: %p->%p(clone)\n", rpc_prev,
					new_p));
				PKTSETNEXT(osh, rpc_prev, new_p);
			} else {
				RPC_TP_DEAGG(("DEAGG: clone %p is a complete rpc pkt\n", new_p));
				rpc_p = new_p;
			}

			PKTPULL(osh, p, tp_len);
			pktlen -= tp_len;
			RPC_TP_DEAGG(("DEAGG: remainder packet p %p data %p pktlen %d\n",
				p, PKTDATA(osh, p), PKTLEN(osh, p)));
		}

		/* !! send up */
		(rpc_th->rx_pkt)(rpc_th->rx_context, rpc_p);
	}

end:
	ASSERT(p == NULL);
}
예제 #8
0
unsigned char* BCMFASTPATH
bcm_rpc_buf_pull(rpc_tp_info_t * rpcb, rpc_buf_t* b, uint bytes)
{
	return PKTPULL(rpcb->osh, b, bytes);
}