📄 rfcomm.c
字号:
/* * Copyright (c) 2003 EISLAB, Lulea University of Technology. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwBT Bluetooth stack. * * Author: Conny Ohult <conny@sm.luth.se> * *//*-----------------------------------------------------------------------------------*//* rfcomm.c * * Implementation of the RFCOMM protocol. A subset of the ETSI TS 07.10 standard with * some Bluetooth-specific adaptations. *//*-----------------------------------------------------------------------------------*/#include "netif/lwbt/l2cap.h"#include "netif/lwbt/rfcomm.h"#include "netif/lwbt/lwbt_memp.h"#include "netif/lwbt/fcs.h"#include "lwbtopts.h"#include "lwip/debug.h"struct rfcomm_pcb_listen *rfcomm_listen_pcbs; /* List of all RFCOMM PCBs listening for an incomming connection on a specific server channel */struct rfcomm_pcb *rfcomm_active_pcbs; /* List of all active RFCOMM PCBs */struct rfcomm_pcb *rfcomm_tmp_pcb;/* Forward declarations */struct rfcomm_pcb *rfcomm_get_active_pcb(u8_t cn, struct bd_addr *bdaddr);/*-----------------------------------------------------------------------------------*//* * rfcomm_init(): * * Initializes the rfcomm layer. *//*-----------------------------------------------------------------------------------*/voidrfcomm_init(void){ /* Clear globals */ rfcomm_listen_pcbs = NULL; rfcomm_active_pcbs = NULL; rfcomm_tmp_pcb = NULL;}/*-----------------------------------------------------------------------------------*//* * rfcomm_tmr(): * * Called every 1s and implements the command timer that * removes a DLC if it has been waiting for a response enough * time. *//*-----------------------------------------------------------------------------------*/voidrfcomm_tmr(void){ struct rfcomm_pcb *pcb, *tpcb; err_t ret; /* Step through all of the active pcbs */ for(pcb = rfcomm_active_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->to != 0) { --pcb->to; LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_tmr: %d\n", pcb->to)); if(pcb->to == 0) { /* Timeout */ if(pcb->cn == 0) { /* If DLC 0 timed out, disconnect all other DLCs on this multiplexer session first */ for(tpcb = rfcomm_active_pcbs; tpcb != NULL; tpcb = tpcb->next) { if(tpcb->cn != 0 && bd_addr_cmp(&(tpcb->l2cappcb->remote_bdaddr), &(pcb->l2cappcb->remote_bdaddr))) { //RFCOMM_RMV(&rfcomm_active_pcbs, tpcb); /* Remove pcb from active list */ tpcb->state = RFCOMM_CLOSED; RFCOMM_EVENT_DISCONNECTED(tpcb,ERR_OK,ret); /* Notify upper layer */ } } } /* Disconnect this DLC */ LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_tmr: Timeout! Disconnect this DLC. State = %d\n", pcb->state)); //RFCOMM_RMV(&rfcomm_active_pcbs, pcb); /* Remove pcb from active list */ pcb->state = RFCOMM_CLOSED; RFCOMM_EVENT_DISCONNECTED(pcb,ERR_OK,ret); /* Notify upper layer */ } } }}/*-----------------------------------------------------------------------------------*//* * rfcomm_lp_disconnected(): * * Called by the application to indicate that the lower protocol disconnected. Closes * any active PCBs in the lists *//*-----------------------------------------------------------------------------------*/err_trfcomm_lp_disconnected(struct l2cap_pcb *l2cappcb){ struct rfcomm_pcb *pcb, *tpcb; err_t ret = ERR_OK; pcb = rfcomm_active_pcbs; while(pcb != NULL) { tpcb = pcb->next; if(bd_addr_cmp(&(l2cappcb->remote_bdaddr), &(pcb->l2cappcb->remote_bdaddr))) { pcb->state = RFCOMM_CLOSED; RFCOMM_EVENT_DISCONNECTED(pcb,ERR_OK,ret); /* Notify upper layer */ } pcb = tpcb; } return ret;}/*-----------------------------------------------------------------------------------*//* * rfcomm_new(): * * Creates a new RFCOMM protocol control block but doesn't place it on * any of the RFCOMM PCB lists. *//*-----------------------------------------------------------------------------------*/struct rfcomm_pcb *rfcomm_new(struct l2cap_pcb *l2cappcb) { struct rfcomm_pcb *pcb; pcb = lwbt_memp_malloc(MEMP_RFCOMM_PCB); if(pcb != NULL) { memset(pcb, 0, sizeof(struct rfcomm_pcb)); pcb->l2cappcb = l2cappcb; pcb->cl = RFCOMM_CL; /* Default convergence layer */ pcb->n = RFCOMM_N; /* Default maximum frame size */ pcb->state = RFCOMM_CLOSED; return pcb; } LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_new: Could not allocate a new pcb\n")); return NULL;}/*-----------------------------------------------------------------------------------*//* * rfcomm_close(): * * Closes the RFCOMM protocol control block. *//*-----------------------------------------------------------------------------------*/voidrfcomm_close(struct rfcomm_pcb *pcb) {#if RFCOMM_FLOW_QUEUEING if(pcb->buf != NULL) { pbuf_free(pcb->buf); }#endif if(pcb->state == RFCOMM_LISTEN) { RFCOMM_RMV((struct rfcomm_pcb **)&rfcomm_listen_pcbs, pcb); lwbt_memp_free(MEMP_RFCOMM_PCB_LISTEN, pcb); } else { RFCOMM_RMV(&rfcomm_active_pcbs, pcb); lwbt_memp_free(MEMP_RFCOMM_PCB, pcb); } pcb = NULL;}/*-----------------------------------------------------------------------------------*//* * rfcomm_reset_all(): * * Closes all active and listening RFCOMM protocol control blocks. *//*-----------------------------------------------------------------------------------*/voidrfcomm_reset_all(void) { struct rfcomm_pcb *pcb, *tpcb; struct rfcomm_pcb_listen *lpcb, *tlpcb; for(pcb = rfcomm_active_pcbs; pcb != NULL;) { tpcb = pcb->next; rfcomm_close(pcb); pcb = tpcb; } for(lpcb = rfcomm_listen_pcbs; lpcb != NULL;) { tlpcb = lpcb->next; rfcomm_close((struct rfcomm_pcb *)lpcb); lpcb = tlpcb; } rfcomm_init();}/*-----------------------------------------------------------------------------------*//* * rfcomm_get_multiplexer(): * * Return the active PCB with the matching Bluetooth address and channel number. *//*-----------------------------------------------------------------------------------*/struct rfcomm_pcb *rfcomm_get_active_pcb(u8_t cn, struct bd_addr *bdaddr) { struct rfcomm_pcb *pcb; for(pcb = rfcomm_active_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->cn == cn && bd_addr_cmp(&(pcb->l2cappcb->remote_bdaddr), bdaddr)) { break; } } return pcb;}/*-----------------------------------------------------------------------------------*//* * rfcomm_dm(): * * Sends a RFCOMM disconnected mode frame in response to a command when disconnected. *//*-----------------------------------------------------------------------------------*/static err_trfcomm_dm(struct l2cap_pcb *pcb, struct rfcomm_hdr *hdr) { struct pbuf *p; struct rfcomm_hdr *rfcommhdr; err_t ret; LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_dm\n")); if((p = pbuf_alloc(PBUF_RAW, RFCOMM_DM_LEN, PBUF_RAM)) == NULL) { /* Could not allocate memory for pbuf */ LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_dm: Could not allocate memory for pbuf\n")); return ERR_MEM; } rfcommhdr = p->payload; rfcommhdr->addr = hdr->addr & 0xFB; /* Set direction bit to 0 for the response */ rfcommhdr->ctrl = RFCOMM_DM; rfcommhdr->len = 1; /* EA bit set to 1 to indicate a 7 bit length field */ ((u8_t *)p->payload)[RFCOMM_HDR_LEN_1] = fcs8_crc_calc(p, RFCOMM_CRC_CHECK_LEN); ret = l2ca_datawrite(pcb, p); pbuf_free(p); return ret;}/*-----------------------------------------------------------------------------------*//* * rfcomm_connect(): * * Sends a RFCOMM start asynchronous balanced mode frame to startup the channel. Also * specify the function to be called when the channel has been connected. *//*-----------------------------------------------------------------------------------*/err_trfcomm_connect(struct rfcomm_pcb *pcb, u8_t cn, err_t (* connected)(void *arg, struct rfcomm_pcb *tpcb, err_t err)){ struct rfcomm_hdr *hdr; struct pbuf *p; err_t ret; struct rfcomm_pcb *tpcb; LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_connect\n")); pcb->connected = connected; pcb->cn = cn; pcb->rfcommcfg |= RFCOMM_CFG_IR; /* Set role to initiator */ /* Create multiplexer session if one does not already exist */ if(cn != 0) { tpcb = rfcomm_get_active_pcb(0, &pcb->l2cappcb->remote_bdaddr); if(tpcb == NULL) { pcb->state = W4_RFCOMM_MULTIPLEXER; RFCOMM_REG(&rfcomm_active_pcbs, pcb); pcb = rfcomm_new(pcb->l2cappcb); pcb->rfcommcfg |= RFCOMM_CFG_IR; /* Set role to initiator */ } } if((p = pbuf_alloc(PBUF_RAW, RFCOMM_SABM_LEN, PBUF_RAM)) == NULL) { /* Could not allocate memory for pbuf */ LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_connect: Could not allocate memory for pbuf\n")); return ERR_MEM; } hdr = p->payload; hdr->addr = (1 << 0) | ((pcb->rfcommcfg & RFCOMM_CFG_IR) << 1) | (((pcb->rfcommcfg & RFCOMM_CFG_IR) ^ 1) << 2) | (pcb->cn << 3); hdr->ctrl = RFCOMM_SABM; hdr->len = (1 << 0) | (0 << 1); ((u8_t *)p->payload)[RFCOMM_HDR_LEN_1] = fcs8_crc_calc(p, RFCOMM_CRC_CHECK_LEN); if((ret = l2ca_datawrite(pcb->l2cappcb, p)) == ERR_OK) { pcb->state = W4_RFCOMM_SABM_RSP; pcb->to = 5*RFCOMM_TO; /* Set acknowledgement timer, 50-300s (5*10-60s) */ } if((tpcb = rfcomm_get_active_pcb(pcb->cn, &pcb->l2cappcb->remote_bdaddr)) == NULL) { RFCOMM_REG(&rfcomm_active_pcbs, pcb); } pbuf_free(p); return ret;}/*-----------------------------------------------------------------------------------*//* * rfcomm_disconnect(): * * Sends a RFCOMM disconnect frame to close the channel. *//*-----------------------------------------------------------------------------------*/err_trfcomm_disconnect(struct rfcomm_pcb *pcb){ struct rfcomm_hdr *hdr; struct pbuf *p; err_t ret; LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_disconnect\n")); if((p = pbuf_alloc(PBUF_RAW, RFCOMM_DISC_LEN, PBUF_RAM)) == NULL) { /* Could not allocate memory for pbuf */ LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_disconnect: Could not allocate memory for pbuf\n")); return ERR_MEM; } p = pbuf_alloc(PBUF_RAW, RFCOMM_DISC_LEN, PBUF_RAM); hdr = p->payload; hdr->addr = (1 << 0) | ((pcb->rfcommcfg & RFCOMM_CFG_IR) << 1) | (((pcb->rfcommcfg & RFCOMM_CFG_IR) ^ 1) << 2) | (pcb->cn << 3); hdr->ctrl = RFCOMM_DISC; hdr->len = (1 << 0) | (0 << 1); ((u8_t *)p->payload)[RFCOMM_HDR_LEN_1] = fcs8_crc_calc(p, RFCOMM_CRC_CHECK_LEN); pcb->state = W4_RFCOMM_DISC_RSP; if((ret = l2ca_datawrite(pcb->l2cappcb, p)) == ERR_OK) { pcb->to = RFCOMM_TO; /* Set acknowledgement timer, 10-60s */ } pbuf_free(p); return ret;}/*-----------------------------------------------------------------------------------*//* * rfcomm_ua(): * * Sends a RFCOMM unnumbered acknowledgement to respond to a connection request. *//*-----------------------------------------------------------------------------------*/static err_t //RESPONDERrfcomm_ua(struct l2cap_pcb *pcb, struct rfcomm_hdr *hdr)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -