void ds3wiibt_initialize(struct ds3wiibt_context *ctx, struct bd_addr *addr) { bd_addr_set(&ctx->bdaddr, addr); memset(&ctx->input, 0, sizeof(ctx->input)); ds3wiibt_set_led(ctx, 1); ds3wiibt_set_rumble(ctx, 0x00, 0x00, 0x00, 0x00); ctx->usrdata = NULL; ctx->connect_cb = NULL; ctx->disconnect_cb = NULL; ctx->status = DS3WIIBT_STATUS_DISCONNECTED; }
void l2cap_process_sig(struct pbuf *q, struct l2cap_hdr *l2caphdr, struct bd_addr *bdaddr) { struct l2cap_sig_hdr *sighdr; struct l2cap_sig *sig = NULL; struct l2cap_pcb *pcb = NULL; struct l2cap_pcb_listen *lpcb; struct l2cap_cfgopt_hdr *opthdr; u16_t result, status, flags, psm, dcid, scid; u16_t len; u16_t siglen; struct pbuf *p, *r = NULL, *s = NULL, *data; err_t ret; u8_t i; u16_t rspstate = L2CAP_CFG_SUCCESS; if(q->len != q->tot_len) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Fragmented packet received. Reassemble into one buffer\n")); if((p = pbuf_alloc(PBUF_RAW, q->tot_len, PBUF_RAM)) != NULL) { i = 0; for(r = q; r != NULL; r = r->next) { memcpy(((u8_t *)p->payload) + i, r->payload, r->len); i += r->len; } } else { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Could not allocate buffer for fragmented packet\n")); return; } } else { p = q; } len = l2caphdr->len; while(len > 0) { /* Set up signal header */ sighdr = p->payload; pbuf_header(p, -L2CAP_SIGHDR_LEN); /* Check if this is a response/reject signal, and if so, find the matching request */ if(sighdr->code % 2) { /* if odd this is a resp/rej signal */ LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Response/reject signal received id = %d code = %d\n", sighdr->id, sighdr->code)); for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { for(sig = pcb->unrsp_sigs; sig != NULL; sig = sig->next) { if(sig->sigid == sighdr->id) { break; /* found */ } } if(sig != NULL) { break; } } } else { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Request signal received id = %d code = %d\n", sighdr->id, sighdr->code)); } /* Reject packet if length exceeds MTU */ if(l2caphdr->len > L2CAP_MTU) { /* Alloc size of reason in cmd rej + MTU */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+2, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = L2CAP_MTU_EXCEEDED; ((u16_t *)data->payload)[1] = L2CAP_MTU; l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); } break; } switch(sighdr->code) { case L2CAP_CMD_REJ: /* Remove signal from unresponded list and deallocate it */ L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); pbuf_free(sig->p); lwbt_memp_free(MEMP_L2CAP_SIG, sig); LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Our command was rejected so we disconnect\n")); l2ca_disconnect_req(pcb, NULL); break; case L2CAP_CONN_REQ: psm = ((u16_t *)p->payload)[0]; /* Search for a listening pcb */ for(lpcb = l2cap_listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if(lpcb->psm == psm) { /* Found a listening pcb with the correct PSM */ break; } } /* If no matching pcb was found, send a connection rsp neg (PSM) */ if(lpcb == NULL) { /* Alloc size of data in conn rsp signal */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = L2CAP_CONN_REF_PSM; ((u16_t *)data->payload)[1] = 0; /* No further info available */ ret = l2cap_signal(pcb, L2CAP_CONN_RSP, sighdr->id, &(pcb->remote_bdaddr), data); } } else { /* Initiate a new active pcb */ pcb = l2cap_new(); if(pcb == NULL) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: could not allocate PCB\n")); /* Send a connection rsp neg (no resources available) and alloc size of data in conn rsp signal */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = L2CAP_CONN_REF_RES; ((u16_t *)data->payload)[1] = 0; /* No further info available */ ret = l2cap_signal(pcb, L2CAP_CONN_RSP, sighdr->id, &(pcb->remote_bdaddr), data); } } bd_addr_set(&(pcb->remote_bdaddr),bdaddr); pcb->scid = l2cap_cid_alloc(); pcb->dcid = ((u16_t *)p->payload)[1]; pcb->psm = psm; pcb->callback_arg = lpcb->callback_arg; pcb->l2ca_connect_ind = lpcb->l2ca_connect_ind; pcb->state = L2CAP_CONFIG; L2CAP_REG(&l2cap_active_pcbs, pcb); LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: A connection request was received. Send a response\n")); data = pbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM); if(data == NULL) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_connect_rsp: Could not allocate memory for pbuf\n")); break; } ((u16_t *)data->payload)[0] = pcb->scid; ((u16_t *)data->payload)[1] = pcb->dcid; ((u16_t *)data->payload)[2] = L2CAP_CONN_SUCCESS; ((u16_t *)data->payload)[3] = 0x0000; /* No further information available */ /* Send the response */ ret = l2cap_signal(pcb, L2CAP_CONN_RSP, sighdr->id, &(pcb->remote_bdaddr), data); } break; case L2CAP_CONN_RSP: if(pcb == NULL) { /* A response without a matching request is silently discarded */ break; } LWIP_ASSERT("l2cap_process_sig: conn rsp, active pcb->state == W4_L2CAP_CONNECT_RSP\n", pcb->state == W4_L2CAP_CONNECT_RSP); result = ((u16_t *)p->payload)[2]; status = ((u16_t *)p->payload)[3]; switch(result) { case L2CAP_CONN_SUCCESS: LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Conn_rsp_sucess, status %d\n", status)); LWIP_ASSERT("l2cap_process_sig: conn rsp success, pcb->scid == ((u16_t *)p->payload)[1]\n", pcb->scid == ((u16_t *)p->payload)[1]); /* Set destination connection id */ pcb->dcid = ((u16_t *)p->payload)[0]; /* Remove signal from unresponded list and deallocate it */ L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); pbuf_free(sig->p); lwbt_memp_free(MEMP_L2CAP_SIG, sig); /* Configure connection */ pcb->state = L2CAP_CONFIG; /* If initiator send a configuration request */ if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { l2ca_config_req(pcb); pcb->cfg.l2capcfg |= L2CAP_CFG_OUT_REQ; } break; case L2CAP_CONN_PND: LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Conn_rsp_pnd, status %d\n", status)); /* Disable rtx and enable ertx */ sig->rtx = 0; sig->ertx = L2CAP_ERTX; break; default: LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Conn_rsp_neg, result %d\n", result)); /* Remove signal from unresponded list and deallocate it */ L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); pbuf_free(sig->p); lwbt_memp_free(MEMP_L2CAP_SIG, sig); L2CA_ACTION_CONN_CFM(pcb,result,status,ret); break; } break; case L2CAP_CFG_REQ: siglen = sighdr->len; dcid = ((u16_t *)p->payload)[0]; flags = ((u16_t *)p->payload)[1]; siglen -= 4; pbuf_header(p, -4); LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Congfiguration request, flags = %d\n", flags)); /* Find PCB with matching cid */ for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: dcid = 0x%x, pcb->scid = 0x%x, pcb->dcid = 0x%x\n\n", dcid, pcb->scid, pcb->dcid)); if(pcb->scid == dcid) { /* Matching cid found */ break; } } /* If no matching cid was found, send a cmd reject (Invalid cid) */ if(pcb == NULL) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Cfg req: no matching cid was found\n")); /* Alloc size of reason in cmd rej + data (dcid + scid) */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+4, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = L2CAP_INVALID_CID; ((u16_t *)data->payload)[1] = dcid; /* Requested local cid */ ((u16_t *)data->payload)[2] = L2CAP_NULL_CID; /* Remote cid not known */ ret = l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); } } else { /* Handle config request */ LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Handle configuration request\n")); pcb->ursp_id = sighdr->id; /* Set id of request to respond to */ /* Parse options and add to pcb */ while(siglen > 0) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Siglen = %d\n", siglen)); opthdr = p->payload; /* Check if type of action bit indicates a non-hint. Hints are ignored */ LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Type of action bit = %d\n", L2CAP_OPTH_TOA(opthdr))); if(L2CAP_OPTH_TOA(opthdr) == 0) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Type = %d\n", L2CAP_OPTH_TYPE(opthdr))); LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Length = %d\n", opthdr->len)); switch(L2CAP_OPTH_TYPE(opthdr)) { case L2CAP_CFG_MTU: LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Out MTU = %d\n", ((u16_t *)p->payload)[1])); pcb->cfg.outmtu = ((u16_t *)p->payload)[1]; break; case L2CAP_FLUSHTO: LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: In flush timeout = %d\n", ((u16_t *)p->payload)[1])); pcb->cfg.influshto = ((u16_t *)p->payload)[1]; break; case L2CAP_QOS: /* If service type is Best Effort or No Traffic the remainder fields will be ignored */ if(((u8_t *)p->payload)[3] == L2CAP_QOS_GUARANTEED) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: This implementation does not support the guaranteed QOS service type")); if(rspstate == L2CAP_CFG_SUCCESS) { rspstate = L2CAP_CFG_UNACCEPT; if(pcb->cfg.opt != NULL) { pbuf_free(pcb->cfg.opt); pcb->cfg.opt = NULL; } } s = pbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + opthdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, L2CAP_CFGOPTHDR_LEN + opthdr->len); if(pcb->cfg.opt == NULL) { pcb->cfg.opt = s; } else { pbuf_chain(pcb->cfg.opt, s); pbuf_free(s); } } break; default: if(rspstate != L2CAP_CFG_REJ) { /* Unknown option. Add to unknown option type buffer */ if(rspstate != L2CAP_CFG_UNKNOWN) { rspstate = L2CAP_CFG_UNKNOWN; if(pcb->cfg.opt != NULL) { pbuf_free(pcb->cfg.opt); pcb->cfg.opt = NULL; } } s = pbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + opthdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, L2CAP_CFGOPTHDR_LEN + opthdr->len); if(pcb->cfg.opt == NULL) { pcb->cfg.opt = s; } else { pbuf_chain(pcb->cfg.opt, s); pbuf_free(s); } } break; } /* switch */ } /* if(L2CAP_OPTH_TOA(opthdr) == 0) */ pbuf_header(p, -(L2CAP_CFGOPTHDR_LEN + opthdr->len)); siglen -= L2CAP_CFGOPTHDR_LEN + opthdr->len; } /* while */ /* If continuation flag is set we don't send the final response just yet */ if((flags & 0x0001) == 1) { /* Send success result with no options until the full request has been received */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CFG_RSP_SIZE, PBUF_RAM)) == NULL) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Could not allocate memory for pbuf\n")); break; } ((u16_t *)data->payload)[0] = pcb->dcid; ((u16_t *)data->payload)[1] = 0; ((u16_t *)data->payload)[2] = L2CAP_CFG_SUCCESS; ret = l2cap_signal(pcb, L2CAP_CFG_RSP, pcb->ursp_id, &(pcb->remote_bdaddr), data); break; } /* Send a configure request for outgoing link if it hasnt been configured */ if(!(pcb->cfg.l2capcfg & L2CAP_CFG_IR) && !(pcb->cfg.l2capcfg & L2CAP_CFG_OUT_REQ)) { l2ca_config_req(pcb); pcb->cfg.l2capcfg |= L2CAP_CFG_OUT_REQ; } /* Send response to configuration request */ LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Send response to configuration request\n")); if((data = pbuf_alloc(PBUF_RAW, L2CAP_CFG_RSP_SIZE, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = pcb->dcid; ((u16_t *)data->payload)[1] = 0; /* Flags (No continuation) */ ((u16_t *)data->payload)[2] = rspstate; /* Result */ if(pcb->cfg.opt != NULL) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: pcb->cfg.opt->len = %d\n", pcb->cfg.opt->len)); pbuf_chain(data, pcb->cfg.opt); /* Add option type buffer to data buffer */ pbuf_free(pcb->cfg.opt); pcb->cfg.opt = NULL; } ret = l2cap_signal(pcb, L2CAP_CFG_RSP, pcb->ursp_id, &(pcb->remote_bdaddr), data); } if(rspstate == L2CAP_CFG_SUCCESS) { pcb->cfg.l2capcfg |= L2CAP_CFG_OUT_SUCCESS; /* L2CAP connection established if a successful configuration response has been sent */ if(pcb->cfg.l2capcfg & L2CAP_CFG_IN_SUCCESS) { /* IPCP connection established, notify upper layer that connection is open */ pcb->state = L2CAP_OPEN; if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { L2CA_ACTION_CONN_CFM(pcb, L2CAP_CONN_SUCCESS, 0x0000, ret); } else { L2CA_ACTION_CONN_IND(pcb, ERR_OK, ret); } } } } /* else */ break; case L2CAP_CFG_RSP: if(pcb == NULL) { /* A response without a matching request is silently discarded */ break; } /* Remove signal from unresponded list and deallocate it */ L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); pbuf_free(sig->p); lwbt_memp_free(MEMP_L2CAP_SIG, sig); LWIP_ASSERT(("l2cap_process_sig: cfg rsp, active pcb->state == L2CAP_CONFIG\n"), pcb->state == L2CAP_CONFIG); siglen = sighdr->len; scid = ((u16_t *)p->payload)[0]; flags = ((u16_t *)p->payload)[1]; result = ((u16_t *)p->payload)[2]; siglen -= 6; pbuf_header(p, -6); LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Outgoing configuration result == %d continuation flag == %d\n", result, flags)); /* Handle config request */ switch(result) { case L2CAP_CFG_SUCCESS: LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Successfull outgoing configuration\n")); pcb->cfg.l2capcfg |= L2CAP_CFG_IN_SUCCESS; /* Local side of the connection has been configured for outgoing data */ pcb->cfg.cfgto = L2CAP_CFG_TO; /* Reset configuration timeout */ if(pcb->cfg.outflushto != L2CAP_CFG_DEFAULT_OUTFLUSHTO) { lp_write_flush_timeout(&pcb->remote_bdaddr, pcb->cfg.outflushto); } /* L2CAP connection established if a successful configuration response has been sent */ if(pcb->cfg.l2capcfg & L2CAP_CFG_OUT_SUCCESS) { pcb->state = L2CAP_OPEN; if(pcb->cfg.l2capcfg & L2CAP_CFG_IR) { L2CA_ACTION_CONN_CFM(pcb, L2CAP_CONN_SUCCESS, 0x0000, ret); } else { L2CA_ACTION_CONN_IND(pcb, ERR_OK, ret); } } break; case L2CAP_CFG_UNACCEPT: /* Parse and add options to pcb */ while(siglen > 0) { opthdr = p->payload; /* Check if type of action bit indicates a non-hint. Hints are ignored */ if(L2CAP_OPTH_TOA(opthdr) == 0) { switch(L2CAP_OPTH_TYPE(opthdr)) { case L2CAP_CFG_MTU: if(L2CAP_MTU > ((u16_t *)p->payload)[1]) { pcb->cfg.outmtu = ((u16_t *)p->payload)[1]; } else { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Configuration of MTU failed\n")); l2ca_disconnect_req(pcb, NULL); return; } break; case L2CAP_FLUSHTO: pcb->cfg.influshto = ((u16_t *)p->payload)[1]; break; case L2CAP_QOS: /* If service type Best Effort is not accepted we will close the connection */ if(((u8_t *)p->payload)[3] != L2CAP_QOS_BEST_EFFORT) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Unsupported service type\n")); l2ca_disconnect_req(pcb, NULL); return; } break; default: /* Should not happen, skip option */ break; } /* switch */ } /* if(L2CAP_OPTH_TOA(opthdr) == 0) */ pbuf_header(p, -(L2CAP_CFGOPTHDR_LEN + opthdr->len)); siglen -= L2CAP_CFGOPTHDR_LEN + opthdr->len; } /* while */ /* Send out a new configuration request if the continuation flag isn't set */ if((flags & 0x0001) == 0) { l2ca_config_req(pcb); } break; case L2CAP_CFG_REJ: /* Fallthrough */ case L2CAP_CFG_UNKNOWN: /* Fallthrough */ default: if((flags & 0x0001) == 0) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Configuration failed\n")); l2ca_disconnect_req(pcb, NULL); return; } break; } /* switch(result) */ /* If continuation flag is set we must send a NULL configuration request */ if((flags & 0x0001) == 1) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Continuation flag is set. Send empty (default) config request signal\n")); if((data = pbuf_alloc(PBUF_RAW, L2CAP_CFG_REQ_SIZE, PBUF_RAM)) == NULL) { LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Could not allocate memory for pbuf\n")); return; } /* Assemble config request packet */ ((u16_t *)data->payload)[0] = pcb->scid; ((u16_t *)data->payload)[2] = 0; l2cap_signal(pcb, L2CAP_CFG_REQ, 0, &(pcb->remote_bdaddr), data); } break; case L2CAP_DISCONN_REQ: siglen = sighdr->len; dcid = ((u16_t *)p->payload)[0]; siglen = siglen - 2; flags = ((u16_t *)p->payload)[1]; siglen = siglen - 2; pbuf_header(p, -4); /* Find PCB with matching cid */ for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->scid == dcid) { /* Matching cid found */ break; } } /* If no matching cid was found, send a cmd reject (Invalid cid) */ if(pcb == NULL) { /* Alloc size of reason in cmd rej + data (dcid + scid) */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE+4, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = L2CAP_INVALID_CID; ((u16_t *)data->payload)[1] = dcid; /* Requested local cid */ ((u16_t *)data->payload)[2] = L2CAP_NULL_CID; /* Remote cid not known */ ret = l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); } } else { /* Handle disconnection request */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_DISCONN_RSP_SIZE, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = pcb->scid; ((u16_t *)data->payload)[1] = pcb->dcid; ret = l2cap_signal(pcb, L2CAP_DISCONN_RSP, sighdr->id, &(pcb->remote_bdaddr), data); /* Give upper layer indication */ pcb->state = L2CAP_CLOSED; LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_process_sig: Disconnection request\n")); L2CA_ACTION_DISCONN_IND(pcb,ERR_OK,ret); } } break; case L2CAP_DISCONN_RSP: if(pcb == NULL) { /* A response without a matching request is silently discarded */ break; } /* Remove signal from unresponded list and deallocate it */ L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); pbuf_free(sig->p); lwbt_memp_free(MEMP_L2CAP_SIG, sig); L2CA_ACTION_DISCONN_CFM(pcb,ret); /* NOTE: Application should now close the connection */ break; case L2CAP_ECHO_REQ: if( pcb != NULL) { pcb->ursp_id = sighdr->id; ret = l2cap_signal(pcb, L2CAP_ECHO_RSP, sighdr->id, &(pcb->remote_bdaddr), p); } else { ret = l2cap_signal(NULL, L2CAP_ECHO_RSP, sighdr->id, bdaddr, p); } pbuf_free(p); break; case L2CAP_ECHO_RSP: if(pcb == NULL) { /* A response without a matching request is silently discarded */ break; } /* Remove signal from unresponded list and deallocate it */ L2CAP_SIG_RMV(&(pcb->unrsp_sigs), sig); pbuf_free(sig->p); lwbt_memp_free(MEMP_L2CAP_SIG, sig); /* Remove temporary pcb from active list */ L2CAP_RMV(&l2cap_active_pcbs, pcb); L2CA_ACTION_PING_CFM(pcb,L2CAP_ECHO_RCVD,ret); break; default: /* Alloc size of reason in cmd rej */ if((data = pbuf_alloc(PBUF_RAW, L2CAP_CMD_REJ_SIZE, PBUF_RAM)) != NULL) { ((u16_t *)data->payload)[0] = L2CAP_CMD_NOT_UNDERSTOOD; ret = l2cap_signal(NULL, L2CAP_CMD_REJ, sighdr->id, bdaddr, data); } break; } /* switch */ len = len - (sighdr->len + L2CAP_SIGHDR_LEN); pbuf_header(p, -(sighdr->len)); } /* while */ }