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

📄 core.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&			       	d->rx_credits <= (d->cfc >> 2)) {			rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);			d->rx_credits = d->cfc;		}	} else {		/* CFC disabled.		 * Give ourselves some credits */		d->tx_credits = 5;	}	if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))		return skb_queue_len(&d->tx_queue);	while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {		err = rfcomm_send_frame(d->session, skb->data, skb->len);		if (err < 0) {			skb_queue_head(&d->tx_queue, skb);			break;		}		kfree_skb(skb);		d->tx_credits--;	}	if (d->cfc && !d->tx_credits) {		/* We're out of TX credits.		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */		set_bit(RFCOMM_TX_THROTTLED, &d->flags);	}	return skb_queue_len(&d->tx_queue);}static inline void rfcomm_process_dlcs(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 (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {			__rfcomm_dlc_close(d, ETIMEDOUT);			continue;		}		if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {			rfcomm_dlc_clear_timer(d);			rfcomm_dlc_accept(d);			if (d->link_mode & RFCOMM_LM_SECURE) {				struct sock *sk = s->sock->sk;				hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);			}			continue;		} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {			rfcomm_dlc_clear_timer(d);			rfcomm_send_dm(s, d->dlci);			__rfcomm_dlc_close(d, ECONNREFUSED);			continue;		}		if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))			continue;		if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&				d->mscex == RFCOMM_MSCEX_OK)			rfcomm_process_tx(d);	}}static inline void rfcomm_process_rx(struct rfcomm_session *s){	struct socket *sock = s->sock;	struct sock *sk = sock->sk;	struct sk_buff *skb;	BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->sk_receive_queue));	/* Get data directly from socket receive queue without copying it. */	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {		skb_orphan(skb);		rfcomm_recv_frame(s, skb);	}	if (sk->sk_state == BT_CLOSED) {		if (!s->initiator)			rfcomm_session_put(s);		rfcomm_session_close(s, sk->sk_err);	}}static inline void rfcomm_accept_connection(struct rfcomm_session *s){	struct socket *sock = s->sock, *nsock;	int err;	/* Fast check for a new connection.	 * Avoids unnesesary socket allocations. */	if (list_empty(&bt_sk(sock->sk)->accept_q))		return;	BT_DBG("session %p", s);	if (sock_create_lite(PF_BLUETOOTH, sock->type, BTPROTO_L2CAP, &nsock))		return;	nsock->ops  = sock->ops;	__module_get(nsock->ops->owner);	err = sock->ops->accept(sock, nsock, O_NONBLOCK);	if (err < 0) {		sock_release(nsock);		return;	}	/* Set our callbacks */	nsock->sk->sk_data_ready   = rfcomm_l2data_ready;	nsock->sk->sk_state_change = rfcomm_l2state_change;	s = rfcomm_session_add(nsock, BT_OPEN);	if (s) {		rfcomm_session_hold(s);		rfcomm_schedule(RFCOMM_SCHED_RX);	} else		sock_release(nsock);}static inline void rfcomm_check_connection(struct rfcomm_session *s){	struct sock *sk = s->sock->sk;	BT_DBG("%p state %ld", s, s->state);	switch(sk->sk_state) {	case BT_CONNECTED:		s->state = BT_CONNECT;		/* We can adjust MTU on outgoing sessions.		 * L2CAP MTU minus UIH header and FCS. */		s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;		rfcomm_send_sabm(s, 0);		break;	case BT_CLOSED:		s->state = BT_CLOSED;		rfcomm_session_close(s, sk->sk_err);		break;	}}static inline void rfcomm_process_sessions(void){	struct list_head *p, *n;	rfcomm_lock();	list_for_each_safe(p, n, &session_list) {		struct rfcomm_session *s;		s = list_entry(p, struct rfcomm_session, list);		if (s->state == BT_LISTEN) {			rfcomm_accept_connection(s);			continue;		}		rfcomm_session_hold(s);		switch (s->state) {		case BT_BOUND:			rfcomm_check_connection(s);			break;		default:			rfcomm_process_rx(s);			break;		}		rfcomm_process_dlcs(s);		rfcomm_session_put(s);	}	rfcomm_unlock();}static void rfcomm_worker(void){	BT_DBG("");	while (!atomic_read(&terminate)) {		if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {			/* No pending events. Let's sleep.			 * Incoming connections and data will wake us up. */			set_current_state(TASK_INTERRUPTIBLE);			schedule();		}		/* Process stuff */		clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);		rfcomm_process_sessions();	}	set_current_state(TASK_RUNNING);	return;}static int rfcomm_add_listener(bdaddr_t *ba){	struct sockaddr_l2 addr;	struct socket *sock;	struct sock *sk;	struct rfcomm_session *s;	int    err = 0;	/* Create socket */	err = rfcomm_l2sock_create(&sock);	if (err < 0) { 		BT_ERR("Create socket failed %d", err);		return err;	}	/* Bind socket */	bacpy(&addr.l2_bdaddr, ba);	addr.l2_family = AF_BLUETOOTH;	addr.l2_psm    = htobs(RFCOMM_PSM);	err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));	if (err < 0) {		BT_ERR("Bind failed %d", err);		goto failed;	}	/* Set L2CAP options */	sk = sock->sk;	lock_sock(sk);	l2cap_pi(sk)->imtu = RFCOMM_MAX_L2CAP_MTU;	release_sock(sk);	/* Start listening on the socket */	err = sock->ops->listen(sock, 10);	if (err) {		BT_ERR("Listen failed %d", err);		goto failed;	}	/* Add listening session */	s = rfcomm_session_add(sock, BT_LISTEN);	if (!s)		goto failed;	rfcomm_session_hold(s);	return 0;failed:	sock_release(sock);	return err;}static void rfcomm_kill_listener(void){	struct rfcomm_session *s;	struct list_head *p, *n;	BT_DBG("");	list_for_each_safe(p, n, &session_list) {		s = list_entry(p, struct rfcomm_session, list);		rfcomm_session_del(s);	}}static int rfcomm_run(void *unused){	rfcomm_thread = current;	atomic_inc(&running);	daemonize("krfcommd");	set_user_nice(current, -10);	current->flags |= PF_NOFREEZE;	BT_DBG("");	rfcomm_add_listener(BDADDR_ANY);	rfcomm_worker();	rfcomm_kill_listener();	atomic_dec(&running);	return 0;}static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status){	struct rfcomm_session *s;	struct rfcomm_dlc *d;	struct list_head *p, *n;	BT_DBG("conn %p status 0x%02x", conn, status);	s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);	if (!s)		return;	rfcomm_session_hold(s);	list_for_each_safe(p, n, &s->dlcs) {		d = list_entry(p, struct rfcomm_dlc, list);		if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE))			continue;		if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))			continue;		if (!status)			set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);		else			set_bit(RFCOMM_AUTH_REJECT, &d->flags);	}	rfcomm_session_put(s);	rfcomm_schedule(RFCOMM_SCHED_AUTH);}static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt){	struct rfcomm_session *s;	struct rfcomm_dlc *d;	struct list_head *p, *n;	BT_DBG("conn %p status 0x%02x encrypt 0x%02x", conn, status, encrypt);	s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);	if (!s)		return;	rfcomm_session_hold(s);	list_for_each_safe(p, n, &s->dlcs) {		d = list_entry(p, struct rfcomm_dlc, list);		if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))			continue;		if (!status && encrypt)			set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);		else			set_bit(RFCOMM_AUTH_REJECT, &d->flags);	}	rfcomm_session_put(s);	rfcomm_schedule(RFCOMM_SCHED_AUTH);}static struct hci_cb rfcomm_cb = {	.name		= "RFCOMM",	.auth_cfm	= rfcomm_auth_cfm,	.encrypt_cfm	= rfcomm_encrypt_cfm};/* ---- Proc fs support ---- */#ifdef CONFIG_PROC_FSstatic void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos){	struct rfcomm_session *s;	struct list_head *pp, *p;	loff_t l = *pos;	rfcomm_lock();	list_for_each(p, &session_list) {		s = list_entry(p, struct rfcomm_session, list);		list_for_each(pp, &s->dlcs)			if (!l--) {				seq->private = s;				return pp;			}	}	return NULL;}static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos){	struct rfcomm_session *s = seq->private;	struct list_head *pp, *p = e;	(*pos)++;	if (p->next != &s->dlcs)		return p->next;	list_for_each(p, &session_list) {		s = list_entry(p, struct rfcomm_session, list);		__list_for_each(pp, &s->dlcs) {			seq->private = s;			return pp;		}	}	return NULL;}static void rfcomm_seq_stop(struct seq_file *seq, void *e){	rfcomm_unlock();}static int  rfcomm_seq_show(struct seq_file *seq, void *e){	struct rfcomm_session *s = seq->private;	struct sock *sk = s->sock->sk;	struct rfcomm_dlc *d = list_entry(e, struct rfcomm_dlc, list);	seq_printf(seq, "%s %s %ld %d %d %d %d\n",			batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),			d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);	return 0;}static struct seq_operations rfcomm_seq_ops = {	.start  = rfcomm_seq_start,	.next   = rfcomm_seq_next,	.stop   = rfcomm_seq_stop,	.show   = rfcomm_seq_show };static int rfcomm_seq_open(struct inode *inode, struct file *file){	return seq_open(file, &rfcomm_seq_ops);}static struct file_operations rfcomm_seq_fops = {	.owner	 = THIS_MODULE,	.open    = rfcomm_seq_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release,};static int  __init rfcomm_proc_init(void){        struct proc_dir_entry *p;	proc_bt_rfcomm = proc_mkdir("rfcomm", proc_bt);	if (proc_bt_rfcomm) {		proc_bt_rfcomm->owner = THIS_MODULE;        	p = create_proc_entry("dlc", S_IRUGO, proc_bt_rfcomm);		if (p)        		p->proc_fops = &rfcomm_seq_fops;	}        return 0;}static void __exit rfcomm_proc_cleanup(void){        remove_proc_entry("dlc", proc_bt_rfcomm);	remove_proc_entry("rfcomm", proc_bt);}#else /* CONFIG_PROC_FS */static int  __init rfcomm_proc_init(void){        return 0;}static void __exit rfcomm_proc_cleanup(void){        return;}#endif /* CONFIG_PROC_FS *//* ---- Initialization ---- */static int __init rfcomm_init(void){	l2cap_load();	hci_register_cb(&rfcomm_cb);	kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);	BT_INFO("RFCOMM ver %s", VERSION);	rfcomm_proc_init();	rfcomm_init_sockets();#ifdef CONFIG_BT_RFCOMM_TTY	rfcomm_init_ttys();#endif	return 0;}static void __exit rfcomm_exit(void){	hci_unregister_cb(&rfcomm_cb);	/* Terminate working thread.	 * ie. Set terminate flag and wake it up */	atomic_inc(&terminate);	rfcomm_schedule(RFCOMM_SCHED_STATE);	/* Wait until thread is running */	while (atomic_read(&running))		schedule();#ifdef CONFIG_BT_RFCOMM_TTY	rfcomm_cleanup_ttys();#endif	rfcomm_cleanup_sockets();	rfcomm_proc_cleanup();}module_init(rfcomm_init);module_exit(rfcomm_exit);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);MODULE_VERSION(VERSION);MODULE_LICENSE("GPL");MODULE_ALIAS("bt-proto-3");

⌨️ 快捷键说明

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