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

📄 rfcomm.c

📁 blue tooth protocol stack source code
💻 C
📖 第 1 页 / 共 5 页
字号:
/* The lower protocol layer, L2CAP, indicates that the lower layer    connection is about to disconnect */void rfcomm_disconnect_ind(l2cap_con *l2cap){	rfcomm_con *rfcomm;	DSYS(FNC "remote cid %d\n", l2cap->remote_cid);	if ((rfcomm = (rfcomm_con*)l2cap->upper_con)) {		/* This l2cap connection is going down, remove all rfcomm cons 		   and notify upper tty */		if (!l2cap->link_up) {			DSYS(FNC "Baseband is down, reset this RFCOMM session\n");#ifdef __KERNEL__			bt_unregister_rfcomm(rfcomm->line);#endif			bt_disconnect_ind(CREATE_RFCOMM_ID(rfcomm->line, 0));		}		rfcomm_reset_con(rfcomm->line);	}	/* always try to send back rsp (if link is down con is deleted) */	if (l2ca_disconnect_rsp(l2cap)) {		D_ERR(FNC "l2ca_disconnect_rsp failed\n");		return;	}}void rfcomm_disconnect_cfm(l2cap_con *l2cap){	rfcomm_con *rfcomm;  	D_CTRL(FNC"disconnected\n");	rfcomm = (rfcomm_con*) l2cap->upper_con;	/* fixme -- should we indicate to bt interface when rfcomm is 	   down or when l2cap for rfcomm is down ? */  	bt_disconnect_ind(CREATE_RFCOMM_ID(rfcomm->line, 0));	/* fixme -- add these glue layer functions in userstack */#ifdef __KERNEL__	bt_unregister_rfcomm(rfcomm->line);	/* wake up bt line */	bt_disconnect_cfm(CREATE_RFCOMM_ID(rfcomm->line, 0), 			  l2cap->c_result);#endif		rfcomm_reset_con(rfcomm->line);	}/* This function should be called from the L2CAP layer data should pos32 at   the beginning of the RFCOMM data, and len should be the length of that    data.*/void rfcomm_receive_data(l2cap_con *l2cap, u8 *data, u32 len){	rfcomm_con *rfcomm;	short_frame *short_pkt; 	long_frame *long_pkt;	u8* uih_data_start;	u32 uih_len;	u8 tmp_dlci;	RF_DATA(FNC"rfcomm_receive_data:",data,len);		D_REC(FNC"%d bytes, our cid is %d\n",len, 	      l2cap->remote_cid);	short_pkt = (short_frame*) data;	tmp_dlci = (((short_pkt->h.addr.server_chn & 0x1f) << 1) |		    (short_pkt->h.addr.d & 0x1));	switch (CLR_PF(short_pkt->h.control)) {	case SABM:		D_CTRL(FNC"SABM-packet received\n");    		if (crc_check((u8*) short_pkt, LONG_CRC_CHECK, 			      short_pkt->data[0]) < 0) {			break;		}		/* If the SABM command wants to open the control channel, we		   have to create a new rfcomm_con object */		if ((tmp_dlci) == 0) {			D_CTRL(FNC"server channel == 0\n");			rfcomm = ((rfcomm_con*) l2cap->upper_con);      			D_CTRL(FNC"setting l2cap_con, no serv.channel yet\n");			rfcomm->dlci[0].state = CONNECTED;                        D_CTRL(FNC"sending back UA - control channel\n");                        send_ua((rfcomm_con*) l2cap->upper_con, tmp_dlci);			bt_connect_ind(CREATE_RFCOMM_ID(rfcomm->line, 0));		}			/* If the channel isn't the control channel, we know that the		   object exist. If we haven't opened any other channel than		   the control channel we open the new channel here */		else if (valid_dlci(tmp_dlci)) {			rfcomm = ((rfcomm_con*) l2cap->upper_con);			D_REC(FNC"setting server channel %d\n",			      short_pkt->h.addr.server_chn);#ifdef CONFIG_BLUETOOTH_USE_SECURITY_MANAGER                        rfcomm_check_allowed_security(rfcomm->l2cap->remote_bd,                                                      tmp_dlci, rfcomm);			/* fixme -- check result and send neg response if not allowed */			#else			bt_connect_ind(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci));			rfcomm->dlci[tmp_dlci].state = CONNECTED;			/* registers in bt driver */                        bt_register_rfcomm(rfcomm, tmp_dlci);			/* wake up any blocking connect/waits */ 			bt_connect_cfm(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci), 0 /* status ok*/ );                        D_CTRL(FNC"sending back UA - other channel\n");                                                send_ua(rfcomm, tmp_dlci);#endif /* CONFIG_BLUETOOTH_USE_SECURITY_MANAGER */		} else {			D_CTRL(FNC"no server on channel %d, sending DM\n",			      tmp_dlci);      			send_dm(((rfcomm_con*) l2cap->upper_con),tmp_dlci);		}		break;    	case UA:		rfcomm = ((rfcomm_con*) l2cap->upper_con);		if (rfcomm->magic != RFCOMM_MAGIC) {			D_ERR(FNC"Invalid magic number\n");			break;		}				D_CTRL(FNC"UA packet received on line %d\n", rfcomm->line);		if (rfcomm->dlci[0].state == CONNECTING) {			/* Now we are the initiating side and we have got a			   respons to our SABM command. We then send a PN			   messages to negotiat the frame length */			rfcomm->dlci[0].state = CONNECTED;			tmp_dlci = ((rfcomm->server_chn << 1) |				    ((~rfcomm->initiator) & 0x1));						/* must fit in l2cap mtu incl rfcomm hdrs */			send_pn_msg(rfcomm, 7, rfcomm->dlci[tmp_dlci].mtu, 0,				    0, tmp_dlci, TRUE);			rfcomm->dlci[tmp_dlci].state = NEGOTIATING;		} else if (rfcomm->dlci[tmp_dlci].state == NEGOTIATING) {			rfcomm->dlci[tmp_dlci].state = CONNECTED;			/* registers in bt driver */                        bt_register_rfcomm(rfcomm, tmp_dlci); 			/* wake up any blocking connect/waits */ 			bt_connect_cfm(CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci), 0 /* status ok*/ );						D_CTRL(FNC"successfully connected on DLCI:%d\n",			       tmp_dlci);						/* FIXME: Should we always do this ? */			rfcomm_msc_msg(rfcomm, EA | RTC | RTR | DV, MCC_CMD,				       tmp_dlci);			rfcomm->dlci[tmp_dlci].initiator = TRUE;		} else if (rfcomm->dlci[tmp_dlci].state == DISCONNECTING) {		  			if (tmp_dlci == 0) {				/* Control channel */#ifdef __KERNEL__				release_wq_timer(&rfcomm_timer);#endif				DSYS(FNC"RFCOMM disconnected ctrl ch (local) on line [%d]\n", rfcomm->line);				rfcomm->dlci[0].state = DISCONNECTED;								/* this will take down l2cap aswell */				wake_up_interruptible(&rfcomm_disconnect_wq);							} else {				/* Data channel */				s32 tmp;				rfcomm->dlci[tmp_dlci].state = DISCONNECTED;				tmp = get_connected_dlci(rfcomm);				if (tmp >= 0) {					rfcomm->dlci[tmp].state = DISCONNECTING;					send_disc(rfcomm, tmp);				} else {					D_ERR("Could not find connected DLCI\n");				}							}		} else if (rfcomm->dlci[tmp_dlci].state == DISCONNECTED) {			rfcomm->dlci[tmp_dlci].state = CONNECTED;		} else {			D_WARN(FNC" Something wrong receiving UA packet\n");		}    		break;    		/* Disconnect mode, 'NAK on SABM/DISC' */	case DM:		D_CTRL(FNC"DM packet received\n");		rfcomm = ((rfcomm_con*) l2cap->upper_con);		rfcomm->dlci[tmp_dlci].state = DISCONNECTED;		/* Notify upper tty */		/* bt_disconnect_ind() ? */		break;    	case DISC:		D_CTRL(FNC"DISC packet received\n");		if (crc_check(data, LONG_CRC_CHECK, short_pkt->data[0]) < 0) {			break;		}		rfcomm = ((rfcomm_con*) l2cap->upper_con);		/* When the serverchannel is closing the whole connection		   should be removed */		if (rfcomm->dlci[tmp_dlci].state == DISCONNECTED) {			send_dm(rfcomm, tmp_dlci);		} else if ((short_pkt->h.addr.server_chn) == 0) {			rfcomm->dlci[0].state = DISCONNECTED;			DSYS("RFCOMM control ch disconnected (remotely) [line:%d]\n", 			       rfcomm->line);			send_ua(rfcomm, 0);		} else {			rfcomm->dlci[tmp_dlci].state = DISCONNECTED;			send_ua(rfcomm, tmp_dlci);			D_CTRL("dlci %d was disconnected\n", tmp_dlci);			bt_disconnect_ind(CREATE_RFCOMM_ID(rfcomm->line, 							   tmp_dlci));#ifdef __KERNEL__			bt_unregister_rfcomm(rfcomm->line);#endif		}		break;    	case UIH:   		rfcomm = ((rfcomm_con*) l2cap->upper_con);		if ((short_pkt->h.length.ea) == 0) {			/* Then we cast the rfcomm packet to a long rfcomm			   packet */ 			D_REC(FNC"Long UIH packet received\n");			long_pkt = (long_frame*) data;			swap_long_frame(long_pkt);			uih_len = long_pkt->h.length.bits.len;			uih_data_start = long_pkt->h.data;			D_REC(FNC"long packet length %d\n",			      uih_len);			if (uih_len > (len - 5)) {				D_WARN(FNC", Long packet length doesn't match, setting length to l2cap len - 5\n");				uih_len = len - 5;			}					} else {			D_REC(FNC"Short UIH pkt received\n");			uih_len = short_pkt->h.length.len;			uih_data_start = short_pkt->data;			if (uih_len > (len - 4)) {				D_WARN(FNC", Short packet length doesn't match, setting length to l2cap len - 4\n");				uih_len = len - 4;			}		}		if (GET_PF(short_pkt->h.control)) {			D_REC(FNC" %d more credits on dlci:%d...\n", 			       *uih_data_start, tmp_dlci);			rfcomm->dlci[tmp_dlci].local_credits += uih_data_start[0];#ifdef __KERNEL__			bt_feedstack();#endif			D_REC(FNC"Local_credits:%d\n", rfcomm->dlci[tmp_dlci].local_credits); 			uih_data_start++;			if (uih_len == 0) {				break;			}						/* feed uih data to tty if any */		}		if (crc_check(data, SHORT_CRC_CHECK,			      *(uih_data_start + uih_len)) < 0) {			break;		}    		if (short_pkt->h.addr.server_chn == 0) {			D_REC(FNC"UIH on serv_channel 0\n");			process_mcc(data, len, rfcomm,				    !(short_pkt->h.length.ea));		} else {			u32 con_id = CREATE_RFCOMM_ID(rfcomm->line, tmp_dlci);			if (rfcomm->credit_flow) {				--rfcomm->dlci[tmp_dlci].remote_credits;				D_CTRL(FNC": Remote credits: %d\n",rfcomm->dlci[tmp_dlci].remote_credits);				if (rfcomm->dlci[tmp_dlci].remote_credits < MIN_CREDITS) {					u8 newcredits = MAX_CREDITS - rfcomm->dlci[tmp_dlci].remote_credits;					rfcomm_send_credits(rfcomm, tmp_dlci, newcredits);					rfcomm->dlci[tmp_dlci].remote_credits += newcredits;										D_SND(FNC"Remote credits: %d\n",rfcomm->dlci[tmp_dlci].remote_credits);									}			}						bt_receive_top(con_id, uih_data_start, uih_len);		}		break;    	default:		D_REC(FNC"illegal packet\n");		break;	}}/* Copies the tty data into the stack and creates headers and FCS, then the   packet is sent to the lower layer L2CAP. The packet must not be larger   than the actual MTU for the L2CAP layer. */s32 rfcomm_send_data(u32 con_id, u8 *data, u32 count){	u32 c;	u32 total = 0;	u8 line;	u8 dlci;	rfcomm_con *rfcomm;	line = GET_LINE(con_id);	dlci = GET_RFCOMMDLCI(con_id);		if (dlci == 0) {		D_ERR(FNC"Not allowed to send data on DLCI 0\n");		return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_NO_DATA_ALLOWED);	}		rfcomm = &rfcomm_con_list[line];	RF_DATA(FNC, data, count);	if (rfcomm == NULL) {		D_ERR(FNC" ERROR rfcomm_con == NULL\n");		return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_NO_CONNECTION);	} else if (rfcomm->magic != RFCOMM_MAGIC) {		D_ERR(FNC"ERROR magic test failed\n");		return -MSGCODE(MSG_LAYER_RFCOMM, RFCOMM_BAD_MAGIC_NUMBER);	} else if(rfcomm->dlci[0].state == FLOW_STOPPED) {		D_SND(FNC"Flow stopped on all channels, returning zero\n");		return 0;	} else if (rfcomm->dlci[dlci].state == FLOW_STOPPED) {		D_SND(FNC"Flow stopped, returning zero\n");		return 0;	}	/* Check whether there are any data channels connected */	else if (rfcomm->dlci[dlci].state == CONNECTED) {		D_SND(FNC"trying to send %d bytes\n", count);		while (count) {				if (rfcomm->credit_flow &&(rfcomm->dlci[dlci].local_credits <= 0)) {				D_SND(FNC"Flow stopped, no credits returning %d\n", total);				return total;			}						/* As long as there are anything to send we try to send			   it. We split the data into parts not bigger than the			   current MTU size. */						c = MIN(count, rfcomm->dlci[dlci].mtu);						/* FIXME: Optimize c! If we try to send 200 bytes and			   there are only 150 bytes space in buffer, set c to			   150 - sizeof(rfcomm_tx_buf)			*/			c = send_uih(data, c, rfcomm, dlci);			if (c < 0) {				return c; /* error */			} else if (c == 0) {				return total;			} else {				if (rfcomm->credit_flow) {					--rfcomm->dlci[dlci].local_credits;					D_SND(FNC"Local credits:%d\n", rfcomm->dlci[dlci].local_credits);				}				total += c;				data += c;				count -= c;			}		}		D_SND(FNC"sent %d bytes\n", total);		return total;	} else {		D_ERR(FNC"DLCI %d not connected\n", dlci);#ifdef __KERNEL__		/* FIXME - should we return an _error_ if rfcomm isn't up 		   yet or only tell user process that 0 bytes was written 		   ??? */		return 0;#else		return -1;#endif	}}s32rfcomm_flow_stop(u8 line, u8 dlci){	if (rfcomm_con_list[line].credit_flow &&(rfcomm_con_list[line].dlci[dlci].local_credits <= 0)) {		return TRUE;	} else if (rfcomm_con_list[line].dlci[dlci].state == FLOW_STOPPED) {		return TRUE;	} else if (rfcomm_con_list[line].dlci[0].state == FLOW_STOPPED) {		return TRUE;	} else {		return FALSE;	}}void rfcomm_send_testdata(u32 count, u8 line){	static u8 testdata[1024];	static s32 testdata_init = 0;	s32 i;	u32 con_id = CREATE_RFCOMM_ID(line, PPP_DLCI);	DSYS("rfcomm_send_testdata: sending %d bytes\n",count);	if (!testdata_init) {		for (i = 0; i < 1024; i++) {			testdata[i] = (i%25)+ 65;		}	} 	rfcomm_send_data(con_id, testdata, count);}/* Parses a multiplexer control channel packet */void process_mcc(u8* data, u32 len, rfcomm_con *rfcomm, s32 longpkt){	mcc_short_frame *mcc_short_pkt;    	D_CTRL("process_mcc\n");	if (longpkt) {		mcc_short_pkt = (mcc_short_frame*)(((long_frame*)data)->data);	} else {		mcc_short_pkt = (mcc_short_frame*)(((short_frame*)data)->data);	}  	switch (mcc_short_pkt->h.type.type) {	case TEST:		if (mcc_short_pkt->h.type.cr == MCC_RSP) {			D_CTRL(FNC"Received test command\n");		} else {			if ((mcc_short_pkt->h.length.ea) == 0) {				mcc_long_frame *mcc_long_pkt;				mcc_long_pkt = (mcc_long_frame*) mcc_short_pkt;				swap_mcc_long_frame(mcc_long_pkt);				rfcomm_test_msg(rfcomm, mcc_long_pkt->value,					      mcc_long_pkt->h.length.bits.len,					      MCC_RSP);			} else {				rfcomm_test_msg(rfcomm, mcc_short_pkt->value, 

⌨️ 快捷键说明

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