static bool wpa_recv(hndrte_dev_t *dev, void *ctx, struct lbuf *lb, uint16 ethtype) { uint8 *pkt = lb->data; int len = lb->len; nas_wksp_t *nwksp = (nas_wksp_t *)ctx; nas_wpa_cb_t *nwcb; bcm_event_t *pvt_data = (bcm_event_t *)pkt; /* recv wpa message from relay */ /* validate the recv packet */ if (nas_validate_wlpvt_message(len, pkt) != 0) { goto error0; } pvt_data = (bcm_event_t *)pkt; nwcb = nas_wksp_find_nwcb_by_mac(nwksp, pvt_data->eth.ether_dhost, pvt_data->event.ifname); if (nwcb && !(nwcb->flags & NAS_WPA_CB_FLAG_ERROR)) nas_handle_wlpvt_messages(nwcb, (void *)pvt_data, len, 1); lb_free(lb); return TRUE; error0: /* way to say not our message */ NASDBG("Not a WPA NAS packet, returning pkt to relay 0x%p\n", lb); return FALSE; }
/* sb_resize: * change the maximum number of lines in the screen buffer to <size> * discard lines at the top if necessary */ void sb_resize(LPSB sb, uint size) { LPLB lb; uint sidx, idx, count; uint len; /* allocate new buffer */ lb = calloc(size + 1, sizeof(LB)); len = sb_internal_length(sb); sidx = (size > len) ? 0 : (len - size); count = (size > len) ? len : size; /* free elements if necessary */ for(idx = 0; idx < sidx; idx++) lb_free(sb_internal_get(sb, idx)); /* copy elements to new buffer */ for(idx = 0; idx < count; idx++, sidx++) lb_copy(&(lb[idx]), sb_internal_get(sb, sidx)); /* replace old buffer by new one */ free(sb->lb); sb->lb = lb; sb->size = size + 1; sb->head = 0; sb->tail = count; }
/* sb_free: * free all line buffers of a screen buffer */ void sb_free(LPSB sb) { uint idx, len; assert(sb != NULL); assert(sb->lb != NULL); /* free all line buffers */ len = sb_internal_length(sb); for(idx = 0; idx < len; idx++) lb_free(&(sb->lb[idx])); free(sb->lb); sb->lb = NULL; sb->head = sb->tail = 0; sb->size = 0; }
static int bcm_rpc_tp_buf_send_internal(rpc_tp_info_t * rpcb, rpc_buf_t *b, uint32 tx_ep_index) { int err; struct lbuf *lb = (struct lbuf *)b; hndrte_dev_t *chained = rpcb->ctx->chained; uint pktlen; ASSERT(chained); ASSERT(b != NULL); pktlen = bcm_rpc_buf_totlen_get(rpcb, b); if (pktlen == BCM_RPC_TP_DNGL_TOTLEN_BAD) { RPC_TP_AGG(("%s, pkt is %d bytes, padding %d bytes\n", __FUNCTION__, BCM_RPC_TP_DNGL_TOTLEN_BAD, BCM_RPC_TP_DNGL_TOTLEN_BAD_PAD)); bcm_rpc_tp_buf_pad(rpcb, b, BCM_RPC_TP_DNGL_TOTLEN_BAD_PAD); } else if (pktlen % BCM_RPC_TP_DNGL_BULKEP_MPS == 0) { RPC_TP_AGG(("%s, tp pkt is multiple of %d bytes, padding %d bytes\n", __FUNCTION__, BCM_RPC_TP_DNGL_BULKEP_MPS, BCM_RPC_TP_DNGL_ZLP_PAD)); bcm_rpc_tp_buf_pad(rpcb, b, BCM_RPC_TP_DNGL_ZLP_PAD); } lb = PKTTONATIVE(rpcb->osh, b); /* send through data endpoint */ if ((err = chained->funcs->xmit(rpcb->ctx, chained, lb)) != 0) { RPC_TP_ERR(("%s: xmit failed; free pkt %p\n", __FUNCTION__, lb)); rpcb->txerr_cnt++; lb_free(lb); } else { rpcb->tx_cnt++; /* give pkt ownership to usb driver, decrement the counter */ rpcb->buf_cnt_inuse -= pktsegcnt(rpcb->osh, b); } return err; }
int bcm_rpc_tp_send_callreturn(rpc_tp_info_t * rpc_th, rpc_buf_t *b) { int err, pktlen; struct lbuf *lb; hndrte_dev_t *chained = rpc_th->ctx->chained; ASSERT(chained); /* Add the TP encapsulation */ bcm_rpc_tp_tx_encap(rpc_th, b); /* Pad if pkt size is a multiple of MPS */ pktlen = bcm_rpc_buf_totlen_get(rpc_th, b); if (pktlen % BCM_RPC_TP_DNGL_CTRLEP_MPS == 0) { RPC_TP_AGG(("%s, tp pkt is multiple of %d bytes, padding %d bytes\n", __FUNCTION__, BCM_RPC_TP_DNGL_CTRLEP_MPS, BCM_RPC_TP_DNGL_ZLP_PAD)); bcm_rpc_tp_buf_pad(rpc_th, b, BCM_RPC_TP_DNGL_ZLP_PAD); } lb = PKTTONATIVE(rpc_th->osh, b); if (rpc_th->has_2nd_bulk_in_ep) { err = chained->funcs->xmit2(rpc_th->ctx, chained, lb, USBDEV_BULK_IN_EP2); } else { err = chained->funcs->xmit_ctl(rpc_th->ctx, chained, lb); } /* send through control endpoint */ if (err != 0) { RPC_TP_ERR(("%s: xmit failed; free pkt %p\n", __FUNCTION__, lb)); rpc_th->txerr_cnt++; lb_free(lb); } else { rpc_th->tx_cnt++; /* give pkt ownership to usb driver, decrement the counter */ rpc_th->buf_cnt_inuse -= pktsegcnt(rpc_th->osh, b); } return err; }
/* sb_append: * append a line buffer at the end of the screen buffer, * if the screen buffer is full discard the first line; * the line is _copied_ to the screen buffer */ int sb_append(LPSB sb, LPLB lb) { uint idx; int y_correction = 0; assert(sb != NULL); assert(lb != NULL); idx = sb->tail; sb->tail = (sb->tail + 1) % sb->size; if (sb->tail == sb->head) { y_correction = sb_lines(sb, &(sb->lb[sb->head])); lb_free(&(sb->lb[sb->head])); sb->head = (sb->head + 1) % sb->size; } lb_copy(&(sb->lb[idx]), lb); sb->length += sb_lines(sb, lb) - y_correction; return y_correction; }
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); }