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

📄 rfcomm.c

📁 blue tooth 核心协议栈在linux上的实现
💻 C
📖 第 1 页 / 共 5 页
字号:
{	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, 					      mcc_short_pkt->h.length.len,					      MCC_RSP);			}		}		break;    	case FCON:  /* Flow control on command */		D_CTRL(FNC"Received Flow control on command\n");		if (mcc_short_pkt->h.type.cr == MCC_CMD) {			rfcomm->dlci[0].state = CONNECTED;			rfcomm_fcon_msg(rfcomm, MCC_RSP);		}		break;    	case FCOFF:  /* Flow control off command */		D_CTRL(FNC"Received Flow control off command\n");		if (mcc_short_pkt->h.type.cr == MCC_CMD) {			rfcomm->dlci[0].state = FLOW_STOPPED;			rfcomm_fcoff_msg(rfcomm, MCC_RSP);		}		break;    	case MSC:  /* Modem status command */	{		u8 dlci;		u8 v24_sigs;				dlci = (mcc_short_pkt->value[0]) >> 2;		v24_sigs = mcc_short_pkt->value[1];		if (rfcomm->dlci[dlci].state == DISCONNECTED) {			send_dm(rfcomm, dlci);			break;		}		if (mcc_short_pkt->h.type.cr == MCC_CMD) {			D_CTRL(FNC"Received Modem status command\n");			if (v24_sigs & 2) {				D_CTRL(FNC"Device unable to accept frames\n");				rfcomm->dlci[dlci].state = FLOW_STOPPED;			} else {				rfcomm->dlci[dlci].state = CONNECTED;				D_CTRL(FNC"Flow ON, dlci %d\n", dlci);  			}			rfcomm_msc_msg(rfcomm, v24_sigs, MCC_RSP, dlci);						if (!(rfcomm->dlci[dlci].initiated) && !(rfcomm->dlci[dlci].initiator)) {				rfcomm_msc_msg(rfcomm, EA | RTR | RTC | DV,					       MCC_CMD, dlci);				rfcomm->dlci[dlci].initiated = TRUE;			}		} else {			D_CTRL(FNC"Received Modem status response\n");			if (v24_sigs & 2) {				D_CTRL(FNC"Flow stop accepted\n");			}		}		break;	}    	case RPN:  /* Remote port negotiation command */	{		u8 tmp_dlci;		tmp_dlci = (mcc_short_pkt->value[0]) >> 2;				if (mcc_short_pkt->h.type.cr == MCC_CMD) {			if (mcc_short_pkt->h.length.len == 1) {				D_CTRL(FNC"Received Remote port negotiation command\n");				rfcomm_rpn_msg(rfcomm, MCC_RSP, tmp_dlci, 0);			} else {				/* Accept the other sides settings (accept all				   for now) */				D_CTRL(FNC"Received Remote port negotiation respons\n");				memcpy(&rpn_val, &mcc_short_pkt->value[1], 8);				rfcomm_rpn_msg(rfcomm, MCC_RSP, tmp_dlci, 0);

⌨️ 快捷键说明

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