📄 sco.c
字号:
if ((err = sco_connect(sk))) goto done; err = bluez_sock_w4_connect(sk, flags);done: release_sock(sk); return err;}int sco_sock_listen(struct socket *sock, int backlog){ struct sock *sk = sock->sk; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); lock_sock(sk); if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { err = -EBADFD; goto done; } sk->max_ack_backlog = backlog; sk->ack_backlog = 0; sk->state = BT_LISTEN;done: release_sock(sk); return err;}int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags){ DECLARE_WAITQUEUE(wait, current); struct sock *sk = sock->sk, *ch; long timeo; int err = 0; lock_sock(sk); if (sk->state != BT_LISTEN) { err = -EBADFD; goto done; } timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ add_wait_queue_exclusive(sk->sleep, &wait); while (!(ch = bluez_accept_dequeue(sk, newsock))) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { err = -EAGAIN; break; } release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); if (sk->state != BT_LISTEN) { err = -EBADFD; break; } if (signal_pending(current)) { err = sock_intr_errno(timeo); break; } } set_current_state(TASK_RUNNING); remove_wait_queue(sk->sleep, &wait); if (err) goto done; newsock->state = SS_CONNECTED; BT_DBG("new socket %p", ch);done: release_sock(sk); return err;}static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer){ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; BT_DBG("sock %p, sk %p", sock, sk); addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_sco); if (peer) bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst); else bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src); return 0;}static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm){ struct sock *sk = sock->sk; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); if (sk->err) return sock_error(sk); if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; lock_sock(sk); if (sk->state == BT_CONNECTED) err = sco_send_frame(sk, msg, len); else err = -ENOTCONN; release_sock(sk); return err;}int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen){ struct sock *sk = sock->sk; int err = 0; BT_DBG("sk %p", sk); lock_sock(sk); switch (optname) { default: err = -ENOPROTOOPT; break; }; release_sock(sk); return err;}int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen){ struct sock *sk = sock->sk; struct sco_options opts; struct sco_conninfo cinfo; int len, err = 0; BT_DBG("sk %p", sk); if (get_user(len, optlen)) return -EFAULT; lock_sock(sk); switch (optname) { case SCO_OPTIONS: if (sk->state != BT_CONNECTED) { err = -ENOTCONN; break; } opts.mtu = sco_pi(sk)->conn->mtu; BT_INFO("mtu %d", opts.mtu); len = MIN(len, sizeof(opts)); if (copy_to_user(optval, (char *)&opts, len)) err = -EFAULT; break; case SCO_CONNINFO: if (sk->state != BT_CONNECTED) { err = -ENOTCONN; break; } cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; len = MIN(len, sizeof(cinfo)); if (copy_to_user(optval, (char *)&cinfo, len)) err = -EFAULT; break; default: err = -ENOPROTOOPT; break; }; release_sock(sk); return err;}static int sco_sock_release(struct socket *sock){ struct sock *sk = sock->sk; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; sock_orphan(sk); sco_sock_close(sk); return 0;}static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent){ BT_DBG("conn %p", conn); sco_pi(sk)->conn = conn; conn->sk = sk; if (parent) bluez_accept_enqueue(parent, sk);}static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent){ int err = 0; sco_conn_lock(conn); if (conn->sk) { err = -EBUSY; } else { __sco_chan_add(conn, sk, parent); } sco_conn_unlock(conn); return err;}static inline struct sock * sco_chan_get(struct sco_conn *conn){ struct sock *sk = NULL; sco_conn_lock(conn); sk = conn->sk; sco_conn_unlock(conn); return sk;}/* Delete channel. * Must be called on the locked socket. */static void sco_chan_del(struct sock *sk, int err){ struct sco_conn *conn; conn = sco_pi(sk)->conn; BT_DBG("sk %p, conn %p, err %d", sk, conn, err); if (conn) { sco_conn_lock(conn); conn->sk = NULL; sco_pi(sk)->conn = NULL; sco_conn_unlock(conn); hci_conn_put(conn->hcon); } sk->state = BT_CLOSED; sk->err = err; sk->state_change(sk); sk->zapped = 1;}static void sco_conn_ready(struct sco_conn *conn){ struct sock *parent, *sk; BT_DBG("conn %p", conn); sco_conn_lock(conn); if ((sk = conn->sk)) { sco_sock_clear_timer(sk); bh_lock_sock(sk); sk->state = BT_CONNECTED; sk->state_change(sk); bh_unlock_sock(sk); } else { parent = sco_get_sock_listen(conn->src); if (!parent) goto done; bh_lock_sock(parent); sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); goto done; } sco_sock_init(sk, parent); bacpy(&bluez_pi(sk)->src, conn->src); bacpy(&bluez_pi(sk)->dst, conn->dst); hci_conn_hold(conn->hcon); __sco_chan_add(conn, sk, parent); sk->state = BT_CONNECTED; /* Wake up parent */ parent->data_ready(parent, 1); bh_unlock_sock(parent); }done: sco_conn_unlock(conn);}/* ----- SCO interface with lower layer (HCI) ----- */int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type){ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); /* Always accept connection */ return HCI_LM_ACCEPT;}int sco_connect_cfm(struct hci_conn *hcon, __u8 status){ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); if (hcon->type != SCO_LINK) return 0; if (!status) { struct sco_conn *conn; conn = sco_conn_add(hcon, status); if (conn) sco_conn_ready(conn); } else sco_conn_del(hcon, bterr(status)); return 0;}int sco_disconn_ind(struct hci_conn *hcon, __u8 reason){ BT_DBG("hcon %p reason %d", hcon, reason); if (hcon->type != SCO_LINK) return 0; sco_conn_del(hcon, bterr(reason)); return 0;}int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb){ struct sco_conn *conn = hcon->sco_data; if (!conn) goto drop; BT_DBG("conn %p len %d", conn, skb->len); if (skb->len) { sco_recv_frame(conn, skb); return 0; }drop: kfree_skb(skb); return 0;}/* ----- Proc fs support ------ */static int sco_sock_dump(char *buf, struct bluez_sock_list *list){ struct sco_pinfo *pi; struct sock *sk; char *ptr = buf; write_lock_bh(&list->lock); for (sk = list->head; sk; sk = sk->next) { pi = sco_pi(sk); ptr += sprintf(ptr, "%s %s %d\n", batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), sk->state); } write_unlock_bh(&list->lock); ptr += sprintf(ptr, "\n"); return ptr - buf;}static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv){ char *ptr = buf; int len; BT_DBG("count %d, offset %ld", count, offset); ptr += sco_sock_dump(ptr, &sco_sk_list); len = ptr - buf; if (len <= count + offset) *eof = 1; *start = buf + offset; len -= offset; if (len > count) len = count; if (len < 0) len = 0; return len;}static struct proto_ops sco_sock_ops = { family: PF_BLUETOOTH, release: sco_sock_release, bind: sco_sock_bind, connect: sco_sock_connect, listen: sco_sock_listen, accept: sco_sock_accept, getname: sco_sock_getname, sendmsg: sco_sock_sendmsg, recvmsg: bluez_sock_recvmsg, poll: bluez_sock_poll, socketpair: sock_no_socketpair, ioctl: sock_no_ioctl, shutdown: sock_no_shutdown, setsockopt: sco_sock_setsockopt, getsockopt: sco_sock_getsockopt, mmap: sock_no_mmap};static struct net_proto_family sco_sock_family_ops = { family: PF_BLUETOOTH, create: sco_sock_create};static struct hci_proto sco_hci_proto = { name: "SCO", id: HCI_PROTO_SCO, connect_ind: sco_connect_ind, connect_cfm: sco_connect_cfm, disconn_ind: sco_disconn_ind, recv_scodata: sco_recv_scodata,};int __init sco_init(void){ int err; if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) { BT_ERR("Can't register SCO socket layer"); return err; } if ((err = hci_register_proto(&sco_hci_proto))) { BT_ERR("Can't register SCO protocol"); return err; } create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL); BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); return 0;}void sco_cleanup(void){ int err; remove_proc_entry("bluetooth/sco", NULL); /* Unregister socket, protocol and notifier */ if ((err = bluez_sock_unregister(BTPROTO_SCO))) BT_ERR("Can't unregister SCO socket layer %d", err); if ((err = hci_unregister_proto(&sco_hci_proto))) BT_ERR("Can't unregister SCO protocol %d", err);}module_init(sco_init);module_exit(sco_cleanup);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -