예제 #1
0
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;
}
예제 #2
0
	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 */
}