| .. | .. |
|---|
| 68 | 68 | bdaddr_t dst; |
|---|
| 69 | 69 | __u32 flags; |
|---|
| 70 | 70 | __u16 setting; |
|---|
| 71 | + __u8 cmsg_mask; |
|---|
| 71 | 72 | struct sco_conn *conn; |
|---|
| 72 | 73 | }; |
|---|
| 73 | 74 | |
|---|
| .. | .. |
|---|
| 279 | 280 | return err; |
|---|
| 280 | 281 | } |
|---|
| 281 | 282 | |
|---|
| 282 | | -static int sco_send_frame(struct sock *sk, void *buf, int len, |
|---|
| 283 | | - unsigned int msg_flags) |
|---|
| 283 | +static int sco_send_frame(struct sock *sk, struct sk_buff *skb) |
|---|
| 284 | 284 | { |
|---|
| 285 | 285 | struct sco_conn *conn = sco_pi(sk)->conn; |
|---|
| 286 | | - struct sk_buff *skb; |
|---|
| 287 | | - int err; |
|---|
| 286 | + int len = skb->len; |
|---|
| 288 | 287 | |
|---|
| 289 | 288 | /* Check outgoing MTU */ |
|---|
| 290 | 289 | if (len > conn->mtu) |
|---|
| .. | .. |
|---|
| 292 | 291 | |
|---|
| 293 | 292 | BT_DBG("sk %p len %d", sk, len); |
|---|
| 294 | 293 | |
|---|
| 295 | | - skb = bt_skb_send_alloc(sk, len, msg_flags & MSG_DONTWAIT, &err); |
|---|
| 296 | | - if (!skb) |
|---|
| 297 | | - return err; |
|---|
| 298 | | - |
|---|
| 299 | | - memcpy(skb_put(skb, len), buf, len); |
|---|
| 300 | 294 | hci_send_sco(conn->hcon, skb); |
|---|
| 301 | 295 | |
|---|
| 302 | 296 | return len; |
|---|
| .. | .. |
|---|
| 451 | 445 | release_sock(sk); |
|---|
| 452 | 446 | } |
|---|
| 453 | 447 | |
|---|
| 448 | +static void sco_skb_put_cmsg(struct sk_buff *skb, struct msghdr *msg, |
|---|
| 449 | + struct sock *sk) |
|---|
| 450 | +{ |
|---|
| 451 | + if (sco_pi(sk)->cmsg_mask & SCO_CMSG_PKT_STATUS) |
|---|
| 452 | + put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_STATUS, |
|---|
| 453 | + sizeof(bt_cb(skb)->sco.pkt_status), |
|---|
| 454 | + &bt_cb(skb)->sco.pkt_status); |
|---|
| 455 | +} |
|---|
| 456 | + |
|---|
| 454 | 457 | static void sco_sock_init(struct sock *sk, struct sock *parent) |
|---|
| 455 | 458 | { |
|---|
| 456 | 459 | BT_DBG("sk %p", sk); |
|---|
| .. | .. |
|---|
| 459 | 462 | sk->sk_type = parent->sk_type; |
|---|
| 460 | 463 | bt_sk(sk)->flags = bt_sk(parent)->flags; |
|---|
| 461 | 464 | security_sk_clone(parent, sk); |
|---|
| 465 | + } else { |
|---|
| 466 | + bt_sk(sk)->skb_put_cmsg = sco_skb_put_cmsg; |
|---|
| 462 | 467 | } |
|---|
| 463 | 468 | } |
|---|
| 464 | 469 | |
|---|
| .. | .. |
|---|
| 523 | 528 | struct sock *sk = sock->sk; |
|---|
| 524 | 529 | int err = 0; |
|---|
| 525 | 530 | |
|---|
| 526 | | - BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr); |
|---|
| 527 | | - |
|---|
| 528 | 531 | if (!addr || addr_len < sizeof(struct sockaddr_sco) || |
|---|
| 529 | 532 | addr->sa_family != AF_BLUETOOTH) |
|---|
| 530 | 533 | return -EINVAL; |
|---|
| 534 | + |
|---|
| 535 | + BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr); |
|---|
| 531 | 536 | |
|---|
| 532 | 537 | lock_sock(sk); |
|---|
| 533 | 538 | |
|---|
| .. | .. |
|---|
| 563 | 568 | addr->sa_family != AF_BLUETOOTH) |
|---|
| 564 | 569 | return -EINVAL; |
|---|
| 565 | 570 | |
|---|
| 566 | | - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) |
|---|
| 567 | | - return -EBADFD; |
|---|
| 571 | + lock_sock(sk); |
|---|
| 572 | + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { |
|---|
| 573 | + err = -EBADFD; |
|---|
| 574 | + goto done; |
|---|
| 575 | + } |
|---|
| 568 | 576 | |
|---|
| 569 | | - if (sk->sk_type != SOCK_SEQPACKET) |
|---|
| 570 | | - return -EINVAL; |
|---|
| 577 | + if (sk->sk_type != SOCK_SEQPACKET) { |
|---|
| 578 | + err = -EINVAL; |
|---|
| 579 | + goto done; |
|---|
| 580 | + } |
|---|
| 571 | 581 | |
|---|
| 572 | 582 | hdev = hci_get_route(&sa->sco_bdaddr, &sco_pi(sk)->src, BDADDR_BREDR); |
|---|
| 573 | | - if (!hdev) |
|---|
| 574 | | - return -EHOSTUNREACH; |
|---|
| 583 | + if (!hdev) { |
|---|
| 584 | + err = -EHOSTUNREACH; |
|---|
| 585 | + goto done; |
|---|
| 586 | + } |
|---|
| 575 | 587 | hci_dev_lock(hdev); |
|---|
| 576 | | - |
|---|
| 577 | | - lock_sock(sk); |
|---|
| 578 | 588 | |
|---|
| 579 | 589 | /* Set destination address and psm */ |
|---|
| 580 | 590 | bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr); |
|---|
| .. | .. |
|---|
| 710 | 720 | size_t len) |
|---|
| 711 | 721 | { |
|---|
| 712 | 722 | struct sock *sk = sock->sk; |
|---|
| 713 | | - void *buf; |
|---|
| 723 | + struct sk_buff *skb; |
|---|
| 714 | 724 | int err; |
|---|
| 715 | 725 | |
|---|
| 716 | 726 | BT_DBG("sock %p, sk %p", sock, sk); |
|---|
| .. | .. |
|---|
| 722 | 732 | if (msg->msg_flags & MSG_OOB) |
|---|
| 723 | 733 | return -EOPNOTSUPP; |
|---|
| 724 | 734 | |
|---|
| 725 | | - buf = kmalloc(len, GFP_KERNEL); |
|---|
| 726 | | - if (!buf) |
|---|
| 727 | | - return -ENOMEM; |
|---|
| 728 | | - |
|---|
| 729 | | - if (memcpy_from_msg(buf, msg, len)) { |
|---|
| 730 | | - kfree(buf); |
|---|
| 731 | | - return -EFAULT; |
|---|
| 732 | | - } |
|---|
| 735 | + skb = bt_skb_sendmsg(sk, msg, len, len, 0, 0); |
|---|
| 736 | + if (IS_ERR(skb)) |
|---|
| 737 | + return PTR_ERR(skb); |
|---|
| 733 | 738 | |
|---|
| 734 | 739 | lock_sock(sk); |
|---|
| 735 | 740 | |
|---|
| 736 | 741 | if (sk->sk_state == BT_CONNECTED) |
|---|
| 737 | | - err = sco_send_frame(sk, buf, len, msg->msg_flags); |
|---|
| 742 | + err = sco_send_frame(sk, skb); |
|---|
| 738 | 743 | else |
|---|
| 739 | 744 | err = -ENOTCONN; |
|---|
| 740 | 745 | |
|---|
| 741 | 746 | release_sock(sk); |
|---|
| 742 | | - kfree(buf); |
|---|
| 747 | + |
|---|
| 748 | + if (err < 0) |
|---|
| 749 | + kfree_skb(skb); |
|---|
| 743 | 750 | return err; |
|---|
| 744 | 751 | } |
|---|
| 745 | 752 | |
|---|
| .. | .. |
|---|
| 815 | 822 | } |
|---|
| 816 | 823 | |
|---|
| 817 | 824 | static int sco_sock_setsockopt(struct socket *sock, int level, int optname, |
|---|
| 818 | | - char __user *optval, unsigned int optlen) |
|---|
| 825 | + sockptr_t optval, unsigned int optlen) |
|---|
| 819 | 826 | { |
|---|
| 820 | 827 | struct sock *sk = sock->sk; |
|---|
| 821 | 828 | int len, err = 0; |
|---|
| .. | .. |
|---|
| 834 | 841 | break; |
|---|
| 835 | 842 | } |
|---|
| 836 | 843 | |
|---|
| 837 | | - if (get_user(opt, (u32 __user *) optval)) { |
|---|
| 844 | + if (copy_from_sockptr(&opt, optval, sizeof(u32))) { |
|---|
| 838 | 845 | err = -EFAULT; |
|---|
| 839 | 846 | break; |
|---|
| 840 | 847 | } |
|---|
| .. | .. |
|---|
| 855 | 862 | voice.setting = sco_pi(sk)->setting; |
|---|
| 856 | 863 | |
|---|
| 857 | 864 | len = min_t(unsigned int, sizeof(voice), optlen); |
|---|
| 858 | | - if (copy_from_user((char *)&voice, optval, len)) { |
|---|
| 865 | + if (copy_from_sockptr(&voice, optval, len)) { |
|---|
| 859 | 866 | err = -EFAULT; |
|---|
| 860 | 867 | break; |
|---|
| 861 | 868 | } |
|---|
| .. | .. |
|---|
| 868 | 875 | } |
|---|
| 869 | 876 | |
|---|
| 870 | 877 | sco_pi(sk)->setting = voice.setting; |
|---|
| 878 | + break; |
|---|
| 879 | + |
|---|
| 880 | + case BT_PKT_STATUS: |
|---|
| 881 | + if (copy_from_sockptr(&opt, optval, sizeof(u32))) { |
|---|
| 882 | + err = -EFAULT; |
|---|
| 883 | + break; |
|---|
| 884 | + } |
|---|
| 885 | + |
|---|
| 886 | + if (opt) |
|---|
| 887 | + sco_pi(sk)->cmsg_mask |= SCO_CMSG_PKT_STATUS; |
|---|
| 888 | + else |
|---|
| 889 | + sco_pi(sk)->cmsg_mask &= SCO_CMSG_PKT_STATUS; |
|---|
| 871 | 890 | break; |
|---|
| 872 | 891 | |
|---|
| 873 | 892 | default: |
|---|
| .. | .. |
|---|
| 946 | 965 | struct sock *sk = sock->sk; |
|---|
| 947 | 966 | int len, err = 0; |
|---|
| 948 | 967 | struct bt_voice voice; |
|---|
| 968 | + u32 phys; |
|---|
| 969 | + int pkt_status; |
|---|
| 949 | 970 | |
|---|
| 950 | 971 | BT_DBG("sk %p", sk); |
|---|
| 951 | 972 | |
|---|
| .. | .. |
|---|
| 978 | 999 | if (copy_to_user(optval, (char *)&voice, len)) |
|---|
| 979 | 1000 | err = -EFAULT; |
|---|
| 980 | 1001 | |
|---|
| 1002 | + break; |
|---|
| 1003 | + |
|---|
| 1004 | + case BT_PHY: |
|---|
| 1005 | + if (sk->sk_state != BT_CONNECTED) { |
|---|
| 1006 | + err = -ENOTCONN; |
|---|
| 1007 | + break; |
|---|
| 1008 | + } |
|---|
| 1009 | + |
|---|
| 1010 | + phys = hci_conn_get_phy(sco_pi(sk)->conn->hcon); |
|---|
| 1011 | + |
|---|
| 1012 | + if (put_user(phys, (u32 __user *) optval)) |
|---|
| 1013 | + err = -EFAULT; |
|---|
| 1014 | + break; |
|---|
| 1015 | + |
|---|
| 1016 | + case BT_PKT_STATUS: |
|---|
| 1017 | + pkt_status = (sco_pi(sk)->cmsg_mask & SCO_CMSG_PKT_STATUS); |
|---|
| 1018 | + |
|---|
| 1019 | + if (put_user(pkt_status, (int __user *)optval)) |
|---|
| 1020 | + err = -EFAULT; |
|---|
| 1021 | + break; |
|---|
| 1022 | + |
|---|
| 1023 | + case BT_SNDMTU: |
|---|
| 1024 | + case BT_RCVMTU: |
|---|
| 1025 | + if (sk->sk_state != BT_CONNECTED) { |
|---|
| 1026 | + err = -ENOTCONN; |
|---|
| 1027 | + break; |
|---|
| 1028 | + } |
|---|
| 1029 | + |
|---|
| 1030 | + if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval)) |
|---|
| 1031 | + err = -EFAULT; |
|---|
| 981 | 1032 | break; |
|---|
| 982 | 1033 | |
|---|
| 983 | 1034 | default: |
|---|
| .. | .. |
|---|
| 1197 | 1248 | return 0; |
|---|
| 1198 | 1249 | } |
|---|
| 1199 | 1250 | |
|---|
| 1200 | | -static int sco_debugfs_open(struct inode *inode, struct file *file) |
|---|
| 1201 | | -{ |
|---|
| 1202 | | - return single_open(file, sco_debugfs_show, inode->i_private); |
|---|
| 1203 | | -} |
|---|
| 1204 | | - |
|---|
| 1205 | | -static const struct file_operations sco_debugfs_fops = { |
|---|
| 1206 | | - .open = sco_debugfs_open, |
|---|
| 1207 | | - .read = seq_read, |
|---|
| 1208 | | - .llseek = seq_lseek, |
|---|
| 1209 | | - .release = single_release, |
|---|
| 1210 | | -}; |
|---|
| 1251 | +DEFINE_SHOW_ATTRIBUTE(sco_debugfs); |
|---|
| 1211 | 1252 | |
|---|
| 1212 | 1253 | static struct dentry *sco_debugfs; |
|---|
| 1213 | 1254 | |
|---|
| .. | .. |
|---|
| 1224 | 1265 | .recvmsg = sco_sock_recvmsg, |
|---|
| 1225 | 1266 | .poll = bt_sock_poll, |
|---|
| 1226 | 1267 | .ioctl = bt_sock_ioctl, |
|---|
| 1268 | + .gettstamp = sock_gettstamp, |
|---|
| 1227 | 1269 | .mmap = sock_no_mmap, |
|---|
| 1228 | 1270 | .socketpair = sock_no_socketpair, |
|---|
| 1229 | 1271 | .shutdown = sco_sock_shutdown, |
|---|