⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l2cap.c

📁 蓝牙协议源代码 bluetooth stack for lwip
💻 C
📖 第 1 页 / 共 4 页
字号:
    ret = l2cap_signal(pcb, L2CAP_CONN_REQ, 0, &(pcb->remote_bdaddr), data); /* Send l2cap_conn_req signal */
    
    pcb->state = W4_L2CAP_CONNECT_RSP;
  }
  
  L2CAP_REG(&l2cap_active_pcbs, pcb);
  
  return ret;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2ca_config_req():
 * 
 * Requests the initial configuration (or reconfiguration) of a channel to a new set 
 * of channel parameters. Input parameters are the local CID endpoint, new incoming 
 * receivable MTU (InMTU), new outgoing flow specification, and flush and link 
 * timeouts. Also specify the function to be called when a confirm has been received.
 */
/*-----------------------------------------------------------------------------------*/
err_t
l2ca_config_req(struct l2cap_pcb *pcb)
{
  struct pbuf *p, *q;
  struct l2cap_cfgopt_hdr *opthdr;
  err_t ret;

  switch(pcb->state) {
  case L2CAP_OPEN:
     LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_config_req: state = L2CAP_OPEN. Suspend transmission\n"));
     /* Note: Application should have suspended data transmission, otherwise outgoing data will be 
	dropped */
    pcb->state = L2CAP_CONFIG;
    /* Fallthrough */
  case L2CAP_CONFIG:
    LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_config_req: state = L2CAP_CONFIG\n"));

    if((p = pbuf_alloc(PBUF_RAW, L2CAP_CFG_REQ_SIZE, PBUF_RAM)) == NULL) {
      LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_config_req: Could not allocate memory for pbuf\n"));
      return ERR_MEM;
    }

    /* Assemble config request packet. Only options that has to be changed will be
       sent */
    ((u16_t *)p->payload)[0] = pcb->dcid;
    /* In this implementation we do not send multiple cmds in one
       signal packet. Therefore we will never send a config_req packet
       that will cause the signal to be larger than the minimum L2CAP MTU
       48 bytes. Hence, this flag will always be cleared */
    ((u16_t *)p->payload)[1] = 0; 
    
    /* Add MTU and out flush timeout to cfg packet if not default value. QoS (Best effort) is always 
       set to default and can be skipped */
    if(pcb->cfg.inmtu != L2CAP_CFG_DEFAULT_INMTU) {
      if((q = pbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + L2CAP_MTU_LEN, PBUF_RAM)) == NULL) {
	pbuf_free(p);
	LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_config_req: Could not allocate memory for pbuf\n"));
	return ERR_MEM;
      }
      opthdr = q->payload;
      opthdr->type = L2CAP_CFG_MTU;
      opthdr->len = L2CAP_MTU_LEN;
      ((u16_t *)q->payload)[1] = pcb->cfg.inmtu;
      pbuf_chain(p, q);
      pbuf_free(q);
    }

    if(L2CAP_OUT_FLUSHTO != L2CAP_CFG_DEFAULT_OUTFLUSHTO) {
      if((q = pbuf_alloc(PBUF_RAW, L2CAP_CFGOPTHDR_LEN + L2CAP_FLUSHTO_LEN, PBUF_RAM)) == NULL) {
	pbuf_free(p);
	LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_config_req: Could not allocate memory for pbuf\n"));
	return ERR_MEM;
      }
      opthdr = q->payload;
      opthdr->type = L2CAP_FLUSHTO;
      opthdr->len = L2CAP_FLUSHTO_LEN;
      ((u16_t *)q->payload)[1] = pcb->cfg.outflushto = L2CAP_OUT_FLUSHTO;
      pbuf_chain(p, q);
      pbuf_free(q);
    }

    /* Send config request signal */
    ret = l2cap_signal(pcb, L2CAP_CFG_REQ, 0, &(pcb->remote_bdaddr), p);
    break;
  default:
    LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_config_req: state = L2CAP_?. Invalid state\n"));
    return ERR_CONN; /* Invalid state. Connection is not in OPEN or CONFIG state */
  }
  return ret;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2ca_disconnect_req():
 * 
 * Requests the disconnection of the channel. Also specify the function to be called
 * when a confirm is received
 */
/*-----------------------------------------------------------------------------------*/
err_t
l2ca_disconnect_req(struct l2cap_pcb *pcb, err_t (* l2ca_disconnect_cfm)(void *arg, struct l2cap_pcb *pcb))
{
  struct pbuf *data;
  err_t ret;

  if(pcb->state == L2CAP_OPEN || pcb->state == L2CAP_CONFIG) {
    if((data = pbuf_alloc(PBUF_RAW, L2CAP_DISCONN_REQ_SIZE, PBUF_RAM)) == NULL) {
     LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_disconnect_req: Could not allocate memory for pbuf\n")); 
      return ERR_MEM;
    }
    pcb->l2ca_disconnect_cfm = l2ca_disconnect_cfm;

    ((u16_t *)data->payload)[0] = pcb->dcid;
    ((u16_t *)data->payload)[1] = pcb->scid;

    ret = l2cap_signal(pcb, L2CAP_DISCONN_REQ, 0, &(pcb->remote_bdaddr), data);
  
    if(ret == ERR_OK) {
      pcb->state = W4_L2CAP_DISCONNECT_RSP;  
    }
  } else {
    return ERR_CONN; /* Signal not supported in this state */
  }

  return ret;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2ca_datawrite():
 * 
 * Transfers data across the channel.
 */
/*-----------------------------------------------------------------------------------*/
err_t
l2ca_datawrite(struct l2cap_pcb *pcb, struct pbuf *p)
{
  err_t ret;
  struct l2cap_hdr *l2caphdr;
  struct pbuf *q;

  if(pcb->state != L2CAP_OPEN) {
    LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_datawrite: State != L2CAP_OPEN. Dropping data\n"));
    return ERR_CONN;
  }

  /* Build L2CAP header */
  if((q = pbuf_alloc(PBUF_RAW, L2CAP_HDR_LEN, PBUF_RAM)) == NULL) {
    LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_datawrite: Could not allocate memory for pbuf\n"));
    return ERR_MEM;
  }
  pbuf_chain(q, p);

  l2caphdr = q->payload;
  l2caphdr->cid = pcb->dcid;
  
  /* If length of the data exceeds the OutMTU then only the first OutMTU bytes are sent */
  if(p->tot_len > pcb->cfg.outmtu) {
    /* Send peer L2CAP data */
    l2caphdr->len = pcb->cfg.outmtu;
    if((ret = l2cap_write(&(pcb->remote_bdaddr), q, pcb->cfg.outmtu + L2CAP_HDR_LEN)) == ERR_OK) {
      LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_datawrite: Length of data exceeds the OutMTU p->tot_len = %d\n", p->tot_len));
      ret = ERR_BUF; /* Length of data exceeds the OutMTU */ 
    }
  } else {
    /* Send peer L2CAP data */
    l2caphdr->len = p->tot_len;
    LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_datawrite: q->tot_len = %d\n", q->tot_len));
    ret = l2cap_write(&(pcb->remote_bdaddr), q, q->tot_len);
  }

  /* Free L2CAP header. Higher layers will handle rest of packet */
  p = pbuf_dechain(q);
  pbuf_free(q);

  return ret;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2ca_ping():
 * 
 * Sends an empty L2CAP echo request message. Also specify the function that should
 * be called when a L2CAP echo reply has been received.
 */
/*-----------------------------------------------------------------------------------*/
err_t
l2ca_ping(struct bd_addr *bdaddr, struct l2cap_pcb *tpcb,
	  err_t (* l2ca_pong)(void *arg, struct l2cap_pcb *pcb, u8_t result))
{
  err_t ret;
  
  if(!lp_is_connected(bdaddr)) {
    return ERR_CONN;
  }

  bd_addr_set(&(tpcb->remote_bdaddr), bdaddr);
  tpcb->l2ca_pong = l2ca_pong;
  
  L2CAP_REG(&l2cap_active_pcbs, tpcb);
  
  ret = l2cap_signal(tpcb, L2CAP_ECHO_REQ, 0, &(tpcb->remote_bdaddr), NULL); /* Send l2cap_echo_req signal */
  
  return ret;
}
/*-----------------------------------------------------------------------------------*/
/* Lower-Layer to L2CAP signaling events
 */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* 
 * lp_connect_cfm():
 * 
 * Confirms the request to establish a lower layer (Baseband) connection.
 */
/*-----------------------------------------------------------------------------------*/
void
lp_connect_cfm(struct bd_addr *bdaddr, u8_t encrypt_mode, err_t err)
{
  struct l2cap_pcb *pcb;
  struct pbuf *data;
  err_t ret;
  
  for(pcb = l2cap_active_pcbs; pcb != NULL; pcb = pcb->next) {
    if(bd_addr_cmp(&(pcb->remote_bdaddr), bdaddr)) {
      break;
    }
  }
  if(pcb == NULL) {
    /* Silently discard */
    LWIP_DEBUGF(L2CAP_DEBUG, ("lp_connect_cfm: Silently discard\n")); 
  } else {
    if(err == ERR_OK) {
      pcb->encrypt = encrypt_mode;
      /* Send l2cap_conn_req signal if no error */
      if((data = pbuf_alloc(PBUF_RAW, L2CAP_CONN_REQ_SIZE, PBUF_RAM)) != NULL) {
	((u16_t *)data->payload)[0] = pcb->psm;
	((u16_t *)data->payload)[1] = pcb->scid;
	if((ret = l2cap_signal(pcb, L2CAP_CONN_REQ, 0, &(pcb->remote_bdaddr), data)) == ERR_OK) {
	  pcb->state = W4_L2CAP_CONNECT_RSP;
	} else {
	  L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available? */
	}
	LWIP_DEBUGF(L2CAP_DEBUG, ("lp_connect_cfm: l2cap_conn_req signal sent. err = %d\nPSM = 0x%x\nscid = 0x%x\nencrypt mode = 0x%x\n", err, pcb->psm, pcb->scid, pcb->encrypt)); 
      } else {
	LWIP_DEBUGF(L2CAP_DEBUG, ("lp_connect_cfm: No resources available\n")); 
	L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available */
      }
    } else {
      LWIP_DEBUGF(L2CAP_DEBUG, ("lp_connect_cfm: Connection falied\n")); 
      L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available */
    }
  }
}
/*-----------------------------------------------------------------------------------*/
/* 
 * lp_connect_ind():
 * 
 * Indicates the lower protocol has successfully established a connection.
 */
/*-----------------------------------------------------------------------------------*/
void
lp_connect_ind(struct bd_addr *bdaddr)
{
  LWIP_DEBUGF(L2CAP_DEBUG, ("lp_connect_ind\n")); 
}
/*-----------------------------------------------------------------------------------*/
/* 
 * lp_disconnect_ind():
 * 
 * Indicates the lower protocol (Baseband) has been shut down by LMP commands or a 
 * timeout event..
 */
/*-----------------------------------------------------------------------------------*/
void
lp_disconnect_ind(struct bd_addr *bdaddr)
{
  struct l2cap_pcb *pcb, *tpcb;
  err_t ret;
  
  for(pcb = l2cap_active_pcbs; pcb != NULL;) {
    tpcb = pcb->next;
    LWIP_DEBUGF(L2CAP_DEBUG, ("lp_disconnect_ind: Find a pcb with a matching Bluetooth address\n"));
    /* All PCBs with matching Bluetooth address have been disconnected */
    if(bd_addr_cmp(&(pcb->remote_bdaddr), bdaddr)) {// && pcb->state != L2CAP_CLOSED) {
      pcb->state = L2CAP_CLOSED;
      LWIP_DEBUGF(L2CAP_DEBUG, ("lp_disconnect_ind: Notify application\n"));
      L2CA_ACTION_DISCONN_IND(pcb,ERR_OK,ret);
    }
    pcb = tpcb;
  }
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2cap_next_sigid():
 * 
 * Issues a signal identifier that helps matching a request with the reply.
 */
/*-----------------------------------------------------------------------------------*/
u8_t
l2cap_next_sigid(void)
{
  ++sigid_nxt;
  if(sigid_nxt == 0) {
    sigid_nxt = 1;
  }
  return sigid_nxt;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2cap_arg():
 * 
 * Used to specify the argument that should be passed callback functions.
 */
/*-----------------------------------------------------------------------------------*/
void
l2cap_arg(struct l2cap_pcb *pcb, void *arg)
{
  pcb->callback_arg = arg;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2cap_connect_ind():
 * 
 * Set the state of the connection to be LISTEN, which means that it is able to accept 
 * incoming connections. The protocol control block is reallocated in order to consume 
 * less memory. Setting the connection to LISTEN is an irreversible process. Also 
 * specify the function that should be called when the channel has received a 
 * connection request.
 */
/*-----------------------------------------------------------------------------------*/
#if LWBT_LAP
err_t
l2cap_connect_ind(struct l2cap_pcb *npcb, u8_t psm,
		  err_t (* l2ca_connect_ind)(void *arg, struct l2cap_pcb *pcb, err_t err))
{
  struct l2cap_pcb_listen *lpcb;

  lpcb = lwbt_memp_malloc(MEMP_L2CAP_PCB_LISTEN);
  if(lpcb == NULL) {
    LWIP_DEBUGF(L2CAP_DEBUG, ("l2cap_connect_ind: Could not allocate memory for lpcb\n"));
    return ERR_MEM;
  }
  lpcb->psm = psm;
  lpcb->l2ca_connect_ind = l2ca_connect_ind;
  lpcb->state = L2CAP_LISTEN;
  lpcb->callback_arg = npcb->callback_arg;
  lwbt_memp_free(MEMP_L2CAP_PCB, npcb);
  L2CAP_REG((struct l2cap_pcb **)&l2cap_listen_pcbs, (struct l2cap_pcb *)lpcb);
  return ERR_OK;
}
#endif /* LWBT_LAP */
/*-----------------------------------------------------------------------------------*/
/* 
 * l2cap_disconnect_ind():
 * 
 * Used to specify the a function to be called when a disconnection request has been 
 * received from a remote device or the remote device has been disconnected because it 
 * has failed to respond to a signalling request.
 */
/*-----------------------------------------------------------------------------------*/
void
l2cap_disconnect_ind(struct l2cap_pcb *pcb,
		     err_t (* l2ca_disconnect_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err))
{
  pcb->l2ca_disconnect_ind = l2ca_disconnect_ind;
}
/*-----------------------------------------------------------------------------------*/
/*
 * l2cap_timeout_ind():
 * 
 * Used to specify the function to be called when RTX or ERTX timer has expired.
 */
/*-----------------------------------------------------------------------------------*/
void
l2cap_timeout_ind(struct l2cap_pcb *pcb,
		  err_t (* l2ca_timeout_ind)(void *arg, struct l2cap_pcb *newpcb, err_t err))
{
  pcb->l2ca_timeout_ind = l2ca_timeout_ind;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * l2cap_recv():
 * 
 * Used to specify the function that should be called when a L2CAP connection receives 
 * data.
 */
/*-----------------------------------------------------------------------------------*/
void
l2cap_recv(struct l2cap_pcb *pcb,
	   err_t (* l2ca_recv)(void *arg, struct l2cap_pcb *pcb, struct pbuf *p, err_t err))
{
  pcb->l2ca_recv = l2ca_recv;
}
/*-----------------------------------------------------------------------------------*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -