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

📄 core.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    RFCOMM implementation for Linux Bluetooth stack (BlueZ).   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License version 2 as   published by the Free Software Foundation;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS    SOFTWARE IS DISCLAIMED.*//*    RPN support    -    Dirk Husemann <hud@zurich.ibm.com>*//* * RFCOMM core. * * $Id: core.c,v 1.46 2002/10/18 20:12:12 maxk Exp $ */#define __KERNEL_SYSCALLS__#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/init.h>#include <linux/wait.h>#include <linux/net.h>#include <linux/proc_fs.h>#include <net/sock.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <net/bluetooth/bluetooth.h>#include <net/bluetooth/l2cap.h>#include <net/bluetooth/rfcomm.h>#define VERSION "1.1"#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG#undef  BT_DBG#define BT_DBG(D...)#endifstruct task_struct *rfcomm_thread;DECLARE_MUTEX(rfcomm_sem);unsigned long rfcomm_event;static LIST_HEAD(session_list);static atomic_t terminate, running;static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);static int rfcomm_queue_disc(struct rfcomm_dlc *d);static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);static void rfcomm_process_connect(struct rfcomm_session *s);/* ---- RFCOMM frame parsing macros ---- */#define __get_dlci(b)     ((b & 0xfc) >> 2)#define __get_channel(b)  ((b & 0xf8) >> 3)#define __get_dir(b)      ((b & 0x04) >> 2)#define __get_type(b)     ((b & 0xef))#define __test_ea(b)      ((b & 0x01))#define __test_cr(b)      ((b & 0x02))#define __test_pf(b)      ((b & 0x10))#define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)#define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))#define __dlci(dir, chn)       (((chn & 0x1f) << 1) | dir)#define __srv_channel(dlci)    (dlci >> 1)#define __dir(dlci)            (dlci & 0x01)#define __len8(len)       (((len) << 1) | 1)#define __len16(len)      ((len) << 1)/* MCC macros */#define __mcc_type(cr, type)   (((type << 2) | (cr << 1) | 0x01))#define __get_mcc_type(b) ((b & 0xfc) >> 2)#define __get_mcc_len(b)  ((b & 0xfe) >> 1)/* RPN macros */#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))#define __get_rpn_data_bits(line) ((line) & 0x3)#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)/* ---- RFCOMM FCS computation ---- *//* CRC on 2 bytes */#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])/* FCS on 2 bytes */ static inline u8 __fcs(u8 *data){	return (0xff - __crc(data));}/* FCS on 3 bytes */ static inline u8 __fcs2(u8 *data){	return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);}/* Check FCS */static inline int __check_fcs(u8 *data, int type, u8 fcs){	u8 f = __crc(data);	if (type != RFCOMM_UIH)		f = rfcomm_crc_table[f ^ data[2]];	return rfcomm_crc_table[f ^ fcs] != 0xcf;}/* ---- L2CAP callbacks ---- */static void rfcomm_l2state_change(struct sock *sk){	BT_DBG("%p state %d", sk, sk->state);	rfcomm_schedule(RFCOMM_SCHED_STATE);}static void rfcomm_l2data_ready(struct sock *sk, int bytes){	BT_DBG("%p bytes %d", sk, bytes);	rfcomm_schedule(RFCOMM_SCHED_RX);}static int rfcomm_l2sock_create(struct socket **sock){	int err;	BT_DBG("");	err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);	if (!err) {		struct sock *sk = (*sock)->sk;		sk->data_ready   = rfcomm_l2data_ready;		sk->state_change = rfcomm_l2state_change;	}	return err;}/* ---- RFCOMM DLCs ---- */static void rfcomm_dlc_timeout(unsigned long arg){	struct rfcomm_dlc *d = (void *) arg;	BT_DBG("dlc %p state %ld", d, d->state);	set_bit(RFCOMM_TIMED_OUT, &d->flags);	rfcomm_dlc_put(d);	rfcomm_schedule(RFCOMM_SCHED_TIMEO);}static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout){	BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);	if (!mod_timer(&d->timer, jiffies + timeout))		rfcomm_dlc_hold(d);}static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d){	BT_DBG("dlc %p state %ld", d, d->state);	if (timer_pending(&d->timer) && del_timer(&d->timer))		rfcomm_dlc_put(d);}static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d){	BT_DBG("%p", d);	d->state      = BT_OPEN;	d->flags      = 0;	d->mscex      = 0;	d->mtu        = RFCOMM_DEFAULT_MTU;	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;	d->cfc        = RFCOMM_CFC_DISABLED;	d->rx_credits = RFCOMM_DEFAULT_CREDITS;}struct rfcomm_dlc *rfcomm_dlc_alloc(int prio){	struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);	if (!d)		return NULL;	memset(d, 0, sizeof(*d));	init_timer(&d->timer);	d->timer.function = rfcomm_dlc_timeout;	d->timer.data = (unsigned long) d;	skb_queue_head_init(&d->tx_queue);	spin_lock_init(&d->lock);	atomic_set(&d->refcnt, 1);	rfcomm_dlc_clear_state(d);		BT_DBG("%p", d);	return d;}void rfcomm_dlc_free(struct rfcomm_dlc *d){	BT_DBG("%p", d);	skb_queue_purge(&d->tx_queue);	kfree(d);}static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d){	BT_DBG("dlc %p session %p", d, s);	rfcomm_session_hold(s);	rfcomm_dlc_hold(d);	list_add(&d->list, &s->dlcs);	d->session = s;}static void rfcomm_dlc_unlink(struct rfcomm_dlc *d){	struct rfcomm_session *s = d->session;	BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);	list_del(&d->list);	d->session = NULL;	rfcomm_dlc_put(d);	rfcomm_session_put(s);}static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci){	struct rfcomm_dlc *d;	struct list_head *p;	list_for_each(p, &s->dlcs) {		d = list_entry(p, struct rfcomm_dlc, list);		if (d->dlci == dlci)			return d;	}	return NULL;}static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel){	struct rfcomm_session *s;	int err = 0;	u8 dlci;	BT_DBG("dlc %p state %ld %s %s channel %d", 			d, d->state, batostr(src), batostr(dst), channel);	if (channel < 1 || channel > 30)		return -EINVAL;	if (d->state != BT_OPEN && d->state != BT_CLOSED)		return 0;	s = rfcomm_session_get(src, dst);	if (!s) {		s = rfcomm_session_create(src, dst, &err);		if (!s)			return err;	}	dlci = __dlci(!s->initiator, channel);	/* Check if DLCI already exists */	if (rfcomm_dlc_get(s, dlci))		return -EBUSY;	rfcomm_dlc_clear_state(d);	d->dlci     = dlci;	d->addr     = __addr(s->initiator, dlci);	d->priority = 7;	d->state    = BT_CONFIG;	rfcomm_dlc_link(s, d);	d->mtu = s->mtu;	d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;	if (s->state == BT_CONNECTED)		rfcomm_send_pn(s, 1, d);	rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);	return 0;}int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel){	mm_segment_t fs;	int r;	rfcomm_lock();	fs = get_fs(); set_fs(KERNEL_DS);	r = __rfcomm_dlc_open(d, src, dst, channel);	set_fs(fs);	rfcomm_unlock();	return r;}static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err){	struct rfcomm_session *s = d->session;	if (!s)		return 0;	BT_DBG("dlc %p state %ld dlci %d err %d session %p",			d, d->state, d->dlci, err, s);	switch (d->state) {	case BT_CONNECTED:	case BT_CONFIG:	case BT_CONNECT:		d->state = BT_DISCONN;		if (skb_queue_empty(&d->tx_queue)) {			rfcomm_send_disc(s, d->dlci);			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);		} else {			rfcomm_queue_disc(d);			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);		}		break;	default:		rfcomm_dlc_clear_timer(d);		rfcomm_dlc_lock(d);		d->state = BT_CLOSED;		d->state_change(d, err);		rfcomm_dlc_unlock(d);		skb_queue_purge(&d->tx_queue);		rfcomm_dlc_unlink(d);	}	return 0;}int rfcomm_dlc_close(struct rfcomm_dlc *d, int err){	mm_segment_t fs;	int r;	rfcomm_lock();	fs = get_fs(); set_fs(KERNEL_DS);	r = __rfcomm_dlc_close(d, err);	set_fs(fs);	rfcomm_unlock();	return r;}int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb){	int len = skb->len;	if (d->state != BT_CONNECTED)		return -ENOTCONN;	BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);	if (len > d->mtu)		return -EINVAL;	rfcomm_make_uih(skb, d->addr);	skb_queue_tail(&d->tx_queue, skb);	if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))		rfcomm_schedule(RFCOMM_SCHED_TX);	return len;}void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d){	BT_DBG("dlc %p state %ld", d, d->state);	if (!d->cfc) {		d->v24_sig |= RFCOMM_V24_FC;		set_bit(RFCOMM_MSC_PENDING, &d->flags);	}	rfcomm_schedule(RFCOMM_SCHED_TX);}void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d){	BT_DBG("dlc %p state %ld", d, d->state);	if (!d->cfc) {		d->v24_sig &= ~RFCOMM_V24_FC;		set_bit(RFCOMM_MSC_PENDING, &d->flags);	}	rfcomm_schedule(RFCOMM_SCHED_TX);}/*    Set/get modem status functions use _local_ status i.e. what we report   to the other side.   Remote status is provided by dlc->modem_status() callback. */int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig){	BT_DBG("dlc %p state %ld v24_sig 0x%x", 			d, d->state, v24_sig);	if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))		v24_sig |= RFCOMM_V24_FC;	else		v24_sig &= ~RFCOMM_V24_FC;		d->v24_sig = v24_sig;	if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))		rfcomm_schedule(RFCOMM_SCHED_TX);	return 0;}int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig){	BT_DBG("dlc %p state %ld v24_sig 0x%x", 			d, d->state, d->v24_sig);	*v24_sig = d->v24_sig;	return 0;}/* ---- RFCOMM sessions ---- */struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state){	struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);	if (!s)		return NULL;	memset(s, 0, sizeof(*s));		BT_DBG("session %p sock %p", s, sock);	INIT_LIST_HEAD(&s->dlcs);	s->state = state;	s->sock  = sock;	s->mtu   = RFCOMM_DEFAULT_MTU;	s->cfc   = RFCOMM_CFC_UNKNOWN;		list_add(&s->list, &session_list);	/* Do not increment module usage count for listeting sessions.	 * Otherwise we won't be able to unload the module. */	if (state != BT_LISTEN)		MOD_INC_USE_COUNT;	return s;}void rfcomm_session_del(struct rfcomm_session *s){	int state = s->state;		BT_DBG("session %p state %ld", s, s->state);	list_del(&s->list);	if (state == BT_CONNECTED)		rfcomm_send_disc(s, 0);	sock_release(s->sock);	kfree(s);	if (state != BT_LISTEN)		MOD_DEC_USE_COUNT;}struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst){	struct rfcomm_session *s;	struct list_head *p, *n;	struct bluez_pinfo *pi;	list_for_each_safe(p, n, &session_list) {		s = list_entry(p, struct rfcomm_session, list);		pi = bluez_pi(s->sock->sk); 		if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&				!bacmp(&pi->dst, dst))			return s;	}	return NULL;}void rfcomm_session_close(struct rfcomm_session *s, int err){	struct rfcomm_dlc *d;	struct list_head *p, *n;	BT_DBG("session %p state %ld err %d", s, s->state, err);	rfcomm_session_hold(s);	s->state = BT_CLOSED;	/* Close all dlcs */	list_for_each_safe(p, n, &s->dlcs) {		d = list_entry(p, struct rfcomm_dlc, list);		d->state = BT_CLOSED;		__rfcomm_dlc_close(d, err);	}	rfcomm_session_put(s);}struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err){	struct rfcomm_session *s = NULL;	struct sockaddr_l2 addr;	struct l2cap_options opts;	struct socket *sock;	int    size;	BT_DBG("%s %s", batostr(src), batostr(dst));	*err = rfcomm_l2sock_create(&sock);	if (*err < 0)		return NULL;	bacpy(&addr.l2_bdaddr, src);	addr.l2_family = AF_BLUETOOTH;	addr.l2_psm    = 0;	*err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));	if (*err < 0)		goto failed;	/* Set L2CAP options */	size = sizeof(opts);	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);		opts.imtu = RFCOMM_MAX_L2CAP_MTU;	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);	s = rfcomm_session_add(sock, BT_BOUND);	if (!s) {		*err = -ENOMEM;		goto failed;	}	s->initiator = 1;	bacpy(&addr.l2_bdaddr, dst);	addr.l2_family = AF_BLUETOOTH;	addr.l2_psm    = htobs(RFCOMM_PSM);	*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);	if (*err == 0 || *err == -EAGAIN)		return s;	rfcomm_session_del(s);	return NULL;failed:	sock_release(sock);	return NULL;}void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst){	struct sock *sk = s->sock->sk;	if (src)		bacpy(src, &bluez_pi(sk)->src);	if (dst)		bacpy(dst, &bluez_pi(sk)->dst);}/* ---- RFCOMM frame sending ---- */static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len){	struct socket *sock = s->sock;	struct iovec iv = { data, len };	struct msghdr msg;	int err;	BT_DBG("session %p len %d", s, len);	memset(&msg, 0, sizeof(msg));	msg.msg_iovlen = 1;	msg.msg_iov = &iv;	err = sock->ops->sendmsg(sock, &msg, len, 0);	return err;}static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci){	struct rfcomm_cmd cmd;	BT_DBG("%p dlci %d", s, dlci);	cmd.addr = __addr(s->initiator, dlci);	cmd.ctrl = __ctrl(RFCOMM_SABM, 1);	cmd.len  = __len8(0);	cmd.fcs  = __fcs2((u8 *) &cmd);	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));}static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci){	struct rfcomm_cmd cmd;	BT_DBG("%p dlci %d", s, dlci);	cmd.addr = __addr(!s->initiator, dlci);	cmd.ctrl = __ctrl(RFCOMM_UA, 1);	cmd.len  = __len8(0);	cmd.fcs  = __fcs2((u8 *) &cmd);	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));

⌨️ 快捷键说明

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