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

📄 core.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
{	int err = 0;	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);	if (dlci) {		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);		if (d) {			rfcomm_send_ua(s, dlci);			if (d->state == BT_CONNECT || d->state == BT_CONFIG)				err = ECONNREFUSED;			else				err = ECONNRESET;			d->state = BT_CLOSED;			__rfcomm_dlc_close(d, err);		} else 			rfcomm_send_dm(s, dlci);				} else {		rfcomm_send_ua(s, 0);		if (s->state == BT_CONNECT)			err = ECONNREFUSED;		else			err = ECONNRESET;		s->state = BT_CLOSED;		rfcomm_session_close(s, err);	}	return 0;}static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d){	struct sock *sk = d->session->sock->sk;	if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {		if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))			return 1;	} else if (d->link_mode & RFCOMM_LM_AUTH) {		if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))			return 1;	}	return 0;}static void rfcomm_dlc_accept(struct rfcomm_dlc *d){	BT_DBG("dlc %p", d);	rfcomm_send_ua(d->session, d->dlci);	rfcomm_dlc_lock(d);	d->state = BT_CONNECTED;	d->state_change(d, 0);	rfcomm_dlc_unlock(d);	rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);}static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci){	struct rfcomm_dlc *d;	u8 channel;	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);	if (!dlci) {		rfcomm_send_ua(s, 0);		if (s->state == BT_OPEN) {			s->state = BT_CONNECTED;			rfcomm_process_connect(s);		}		return 0;	}	/* Check if DLC exists */	d = rfcomm_dlc_get(s, dlci);	if (d) {		if (d->state == BT_OPEN) {			/* DLC was previously opened by PN request */			if (rfcomm_check_link_mode(d)) {				set_bit(RFCOMM_AUTH_PENDING, &d->flags);				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);				return 0;			}			rfcomm_dlc_accept(d);		}		return 0;	}	/* Notify socket layer about incoming connection */	channel = __srv_channel(dlci);	if (rfcomm_connect_ind(s, channel, &d)) {		d->dlci = dlci;		d->addr = __addr(s->initiator, dlci);		rfcomm_dlc_link(s, d);		if (rfcomm_check_link_mode(d)) {			set_bit(RFCOMM_AUTH_PENDING, &d->flags);			rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);			return 0;		}		rfcomm_dlc_accept(d);	} else {		rfcomm_send_dm(s, dlci);	}	return 0;}static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn){	struct rfcomm_session *s = d->session;	BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", 			d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);	if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {		d->cfc = s->cfc = RFCOMM_CFC_ENABLED;		d->tx_credits = pn->credits;	} else {		d->cfc = s->cfc = RFCOMM_CFC_DISABLED;		set_bit(RFCOMM_TX_THROTTLED, &d->flags);	}	d->priority = pn->priority;	d->mtu = s->mtu = btohs(pn->mtu);	return 0;}static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb){	struct rfcomm_pn *pn = (void *) skb->data;	struct rfcomm_dlc *d;	u8 dlci = pn->dlci;	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);	if (!dlci)		return 0;	d = rfcomm_dlc_get(s, dlci);	if (d) {		if (cr) {			/* PN request */			rfcomm_apply_pn(d, cr, pn);			rfcomm_send_pn(s, 0, d);		} else {			/* PN response */			switch (d->state) {			case BT_CONFIG:				rfcomm_apply_pn(d, cr, pn);				d->state = BT_CONNECT;				rfcomm_send_sabm(s, d->dlci);				break;			}		}	} else {		u8 channel = __srv_channel(dlci);		if (!cr)			return 0;		/* PN request for non existing DLC.		 * Assume incoming connection. */		if (rfcomm_connect_ind(s, channel, &d)) {			d->dlci = dlci;			d->addr = __addr(s->initiator, dlci);			rfcomm_dlc_link(s, d);			rfcomm_apply_pn(d, cr, pn);			d->state = BT_OPEN;			rfcomm_send_pn(s, 0, d);		} else {			rfcomm_send_dm(s, dlci);		}	}	return 0;}static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb){	struct rfcomm_rpn *rpn = (void *) skb->data;	u8 dlci = __get_dlci(rpn->dlci);	u8 bit_rate  = 0;	u8 data_bits = 0;	u8 stop_bits = 0;	u8 parity    = 0;	u8 flow_ctrl = 0;	u8 xon_char  = 0;	u8 xoff_char = 0;	u16 rpn_mask = RFCOMM_RPN_PM_ALL;		BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 	       dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,	       rpn->xon_char, rpn->xoff_char, rpn->param_mask);		if (!cr) 		return 0;		if (len == 1) {		/* request: return default setting */		bit_rate  = RFCOMM_RPN_BR_115200;		data_bits = RFCOMM_RPN_DATA_8;		stop_bits = RFCOMM_RPN_STOP_1;		parity    = RFCOMM_RPN_PARITY_NONE;		flow_ctrl = RFCOMM_RPN_FLOW_NONE;		xon_char  = RFCOMM_RPN_XON_CHAR;		xoff_char = RFCOMM_RPN_XOFF_CHAR;		goto rpn_out;	}	/* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,	                          no flow control lines, normal XON/XOFF chars */	if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {		bit_rate = rpn->bit_rate;		if (bit_rate != RFCOMM_RPN_BR_115200) {			BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);			bit_rate = RFCOMM_RPN_BR_115200;			rpn_mask ^= RFCOMM_RPN_PM_BITRATE;		}	}	if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {		data_bits = __get_rpn_data_bits(rpn->line_settings);		if (data_bits != RFCOMM_RPN_DATA_8) {			BT_DBG("RPN data bits mismatch 0x%x", data_bits);			data_bits = RFCOMM_RPN_DATA_8;			rpn_mask ^= RFCOMM_RPN_PM_DATA;		}	}	if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {		stop_bits = __get_rpn_stop_bits(rpn->line_settings);		if (stop_bits != RFCOMM_RPN_STOP_1) {			BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);			stop_bits = RFCOMM_RPN_STOP_1;			rpn_mask ^= RFCOMM_RPN_PM_STOP;		}	}	if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {		parity = __get_rpn_parity(rpn->line_settings);		if (parity != RFCOMM_RPN_PARITY_NONE) {			BT_DBG("RPN parity mismatch 0x%x", parity);			parity = RFCOMM_RPN_PARITY_NONE;			rpn_mask ^= RFCOMM_RPN_PM_PARITY;		}	}	if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {		flow_ctrl = rpn->flow_ctrl;		if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {			BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);			flow_ctrl = RFCOMM_RPN_FLOW_NONE;			rpn_mask ^= RFCOMM_RPN_PM_FLOW;		}	}	if (rpn->param_mask & RFCOMM_RPN_PM_XON) {		xon_char = rpn->xon_char;		if (xon_char != RFCOMM_RPN_XON_CHAR) {			BT_DBG("RPN XON char mismatch 0x%x", xon_char);			xon_char = RFCOMM_RPN_XON_CHAR;			rpn_mask ^= RFCOMM_RPN_PM_XON;		}	}	if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {		xoff_char = rpn->xoff_char;		if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {			BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);			xoff_char = RFCOMM_RPN_XOFF_CHAR;			rpn_mask ^= RFCOMM_RPN_PM_XOFF;		}	}rpn_out:	rfcomm_send_rpn(s, 0, dlci, 			bit_rate, data_bits, stop_bits, parity, flow_ctrl,			xon_char, xoff_char, rpn_mask);	return 0;}static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb){	struct rfcomm_rls *rls = (void *) skb->data;	u8 dlci = __get_dlci(rls->dlci);	BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);		if (!cr)		return 0;	/* FIXME: We should probably do something with this	   information here. But for now it's sufficient just	   to reply -- Bluetooth 1.1 says it's mandatory to 	   recognise and respond to RLS */	rfcomm_send_rls(s, 0, dlci, rls->status);	return 0;}static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb){	struct rfcomm_msc *msc = (void *) skb->data;	struct rfcomm_dlc *d;	u8 dlci = __get_dlci(msc->dlci);	BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);	d = rfcomm_dlc_get(s, dlci);	if (!d) 		return 0;	if (cr) {		if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)			set_bit(RFCOMM_TX_THROTTLED, &d->flags);		else			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);				rfcomm_dlc_lock(d);		if (d->modem_status)			d->modem_status(d, msc->v24_sig);		rfcomm_dlc_unlock(d);				rfcomm_send_msc(s, 0, dlci, msc->v24_sig);		d->mscex |= RFCOMM_MSCEX_RX;	} else 		d->mscex |= RFCOMM_MSCEX_TX;	return 0;}static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb){	struct rfcomm_mcc *mcc = (void *) skb->data;	u8 type, cr, len;	cr   = __test_cr(mcc->type);	type = __get_mcc_type(mcc->type);	len  = __get_mcc_len(mcc->len);	BT_DBG("%p type 0x%x cr %d", s, type, cr);	skb_pull(skb, 2);	switch (type) {	case RFCOMM_PN:		rfcomm_recv_pn(s, cr, skb);		break;	case RFCOMM_RPN:		rfcomm_recv_rpn(s, cr, len, skb);		break;	case RFCOMM_RLS:		rfcomm_recv_rls(s, cr, skb);		break;	case RFCOMM_MSC:		rfcomm_recv_msc(s, cr, skb);		break;	case RFCOMM_FCOFF:		if (cr) {			set_bit(RFCOMM_TX_THROTTLED, &s->flags);			rfcomm_send_fcoff(s, 0);		}		break;	case RFCOMM_FCON:		if (cr) {			clear_bit(RFCOMM_TX_THROTTLED, &s->flags);			rfcomm_send_fcon(s, 0);		}		break;	case RFCOMM_TEST:		if (cr)			rfcomm_send_test(s, 0, skb->data, skb->len);		break;	case RFCOMM_NSC:		break;	default:		BT_ERR("Unknown control type 0x%02x", type);		rfcomm_send_nsc(s, cr, type);		break;	}	return 0;}static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb){	struct rfcomm_dlc *d;	BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);	d = rfcomm_dlc_get(s, dlci);	if (!d) {		rfcomm_send_dm(s, dlci);		goto drop;	}	if (pf && d->cfc) {		u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);		d->tx_credits += credits;		if (d->tx_credits)			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);	}	if (skb->len && d->state == BT_CONNECTED) {		rfcomm_dlc_lock(d);		d->rx_credits--;		d->data_ready(d, skb);		rfcomm_dlc_unlock(d);		return 0;	}drop:	kfree_skb(skb);	return 0;}static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb){	struct rfcomm_hdr *hdr = (void *) skb->data;	u8 type, dlci, fcs;	dlci = __get_dlci(hdr->addr);	type = __get_type(hdr->ctrl);	/* Trim FCS */	skb->len--; skb->tail--;	fcs = *(u8 *) skb->tail;	if (__check_fcs(skb->data, type, fcs)) {		BT_ERR("bad checksum in packet");		kfree_skb(skb);		return -EILSEQ;	}	if (__test_ea(hdr->len))		skb_pull(skb, 3);	else		skb_pull(skb, 4);	switch (type) {	case RFCOMM_SABM:		if (__test_pf(hdr->ctrl))			rfcomm_recv_sabm(s, dlci);		break;	case RFCOMM_DISC:		if (__test_pf(hdr->ctrl))			rfcomm_recv_disc(s, dlci);		break;	case RFCOMM_UA:		if (__test_pf(hdr->ctrl))			rfcomm_recv_ua(s, dlci);		break;	case RFCOMM_DM:		rfcomm_recv_dm(s, dlci);		break;	case RFCOMM_UIH:		if (dlci)			return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);		rfcomm_recv_mcc(s, skb);		break;	default:		BT_ERR("Unknown packet type 0x%02x\n", type);		break;	}	kfree_skb(skb);	return 0;}/* ---- Connection and data processing ---- */static void rfcomm_process_connect(struct rfcomm_session *s){	struct rfcomm_dlc *d;	struct list_head *p, *n;	BT_DBG("session %p state %ld", s, s->state);	list_for_each_safe(p, n, &s->dlcs) {		d = list_entry(p, struct rfcomm_dlc, list);		if (d->state == BT_CONFIG) {			d->mtu = s->mtu;			rfcomm_send_pn(s, 1, d);		}	}}/* Send data queued for the DLC. * Return number of frames left in the queue. */static inline int rfcomm_process_tx(struct rfcomm_dlc *d){	struct sk_buff *skb;	int err;	BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d", 			d, d->state, d->cfc, d->rx_credits, d->tx_credits);	/* Send pending MSC */	if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))		rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); 	if (d->cfc) {		/* CFC enabled. 		 * Give them some credits */

⌨️ 快捷键说明

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