📄 core.c
字号:
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 + -