diff options
Diffstat (limited to 'net/bluetooth/sco.c')
-rw-r--r-- | net/bluetooth/sco.c | 91 |
1 files changed, 55 insertions, 36 deletions
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index cb4fb7837e5..c0b9ad0524e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/debugfs.h> | 41 | #include <linux/debugfs.h> |
42 | #include <linux/seq_file.h> | 42 | #include <linux/seq_file.h> |
43 | #include <linux/list.h> | 43 | #include <linux/list.h> |
44 | #include <linux/security.h> | ||
44 | #include <net/sock.h> | 45 | #include <net/sock.h> |
45 | 46 | ||
46 | #include <asm/system.h> | 47 | #include <asm/system.h> |
@@ -177,6 +178,7 @@ static int sco_connect(struct sock *sk) | |||
177 | { | 178 | { |
178 | bdaddr_t *src = &bt_sk(sk)->src; | 179 | bdaddr_t *src = &bt_sk(sk)->src; |
179 | bdaddr_t *dst = &bt_sk(sk)->dst; | 180 | bdaddr_t *dst = &bt_sk(sk)->dst; |
181 | __u16 pkt_type = sco_pi(sk)->pkt_type; | ||
180 | struct sco_conn *conn; | 182 | struct sco_conn *conn; |
181 | struct hci_conn *hcon; | 183 | struct hci_conn *hcon; |
182 | struct hci_dev *hdev; | 184 | struct hci_dev *hdev; |
@@ -192,10 +194,12 @@ static int sco_connect(struct sock *sk) | |||
192 | 194 | ||
193 | if (lmp_esco_capable(hdev) && !disable_esco) | 195 | if (lmp_esco_capable(hdev) && !disable_esco) |
194 | type = ESCO_LINK; | 196 | type = ESCO_LINK; |
195 | else | 197 | else { |
196 | type = SCO_LINK; | 198 | type = SCO_LINK; |
199 | pkt_type &= SCO_ESCO_MASK; | ||
200 | } | ||
197 | 201 | ||
198 | hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); | 202 | hcon = hci_connect(hdev, type, pkt_type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); |
199 | if (IS_ERR(hcon)) { | 203 | if (IS_ERR(hcon)) { |
200 | err = PTR_ERR(hcon); | 204 | err = PTR_ERR(hcon); |
201 | goto done; | 205 | goto done; |
@@ -403,8 +407,10 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) | |||
403 | { | 407 | { |
404 | BT_DBG("sk %p", sk); | 408 | BT_DBG("sk %p", sk); |
405 | 409 | ||
406 | if (parent) | 410 | if (parent) { |
407 | sk->sk_type = parent->sk_type; | 411 | sk->sk_type = parent->sk_type; |
412 | security_sk_clone(parent, sk); | ||
413 | } | ||
408 | } | 414 | } |
409 | 415 | ||
410 | static struct proto sco_proto = { | 416 | static struct proto sco_proto = { |
@@ -460,18 +466,22 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol, | |||
460 | return 0; | 466 | return 0; |
461 | } | 467 | } |
462 | 468 | ||
463 | static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 469 | static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) |
464 | { | 470 | { |
465 | struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; | 471 | struct sockaddr_sco sa; |
466 | struct sock *sk = sock->sk; | 472 | struct sock *sk = sock->sk; |
467 | bdaddr_t *src = &sa->sco_bdaddr; | 473 | bdaddr_t *src = &sa.sco_bdaddr; |
468 | int err = 0; | 474 | int len, err = 0; |
469 | 475 | ||
470 | BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); | 476 | BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr)); |
471 | 477 | ||
472 | if (!addr || addr->sa_family != AF_BLUETOOTH) | 478 | if (!addr || addr->sa_family != AF_BLUETOOTH) |
473 | return -EINVAL; | 479 | return -EINVAL; |
474 | 480 | ||
481 | memset(&sa, 0, sizeof(sa)); | ||
482 | len = min_t(unsigned int, sizeof(sa), alen); | ||
483 | memcpy(&sa, addr, len); | ||
484 | |||
475 | lock_sock(sk); | 485 | lock_sock(sk); |
476 | 486 | ||
477 | if (sk->sk_state != BT_OPEN) { | 487 | if (sk->sk_state != BT_OPEN) { |
@@ -485,7 +495,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le | |||
485 | err = -EADDRINUSE; | 495 | err = -EADDRINUSE; |
486 | } else { | 496 | } else { |
487 | /* Save source address */ | 497 | /* Save source address */ |
488 | bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); | 498 | bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr); |
499 | sco_pi(sk)->pkt_type = sa.sco_pkt_type; | ||
489 | sk->sk_state = BT_BOUND; | 500 | sk->sk_state = BT_BOUND; |
490 | } | 501 | } |
491 | 502 | ||
@@ -498,27 +509,34 @@ done: | |||
498 | 509 | ||
499 | static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) | 510 | static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) |
500 | { | 511 | { |
501 | struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; | ||
502 | struct sock *sk = sock->sk; | 512 | struct sock *sk = sock->sk; |
503 | int err = 0; | 513 | struct sockaddr_sco sa; |
504 | 514 | int len, err = 0; | |
505 | 515 | ||
506 | BT_DBG("sk %p", sk); | 516 | BT_DBG("sk %p", sk); |
507 | 517 | ||
508 | if (alen < sizeof(struct sockaddr_sco) || | 518 | if (!addr || addr->sa_family != AF_BLUETOOTH) |
509 | addr->sa_family != AF_BLUETOOTH) | ||
510 | return -EINVAL; | 519 | return -EINVAL; |
511 | 520 | ||
512 | if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) | 521 | memset(&sa, 0, sizeof(sa)); |
513 | return -EBADFD; | 522 | len = min_t(unsigned int, sizeof(sa), alen); |
514 | 523 | memcpy(&sa, addr, len); | |
515 | if (sk->sk_type != SOCK_SEQPACKET) | ||
516 | return -EINVAL; | ||
517 | 524 | ||
518 | lock_sock(sk); | 525 | lock_sock(sk); |
519 | 526 | ||
527 | if (sk->sk_type != SOCK_SEQPACKET) { | ||
528 | err = -EINVAL; | ||
529 | goto done; | ||
530 | } | ||
531 | |||
532 | if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { | ||
533 | err = -EBADFD; | ||
534 | goto done; | ||
535 | } | ||
536 | |||
520 | /* Set destination address and psm */ | 537 | /* Set destination address and psm */ |
521 | bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); | 538 | bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr); |
539 | sco_pi(sk)->pkt_type = sa.sco_pkt_type; | ||
522 | 540 | ||
523 | err = sco_connect(sk); | 541 | err = sco_connect(sk); |
524 | if (err) | 542 | if (err) |
@@ -564,30 +582,26 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag | |||
564 | 582 | ||
565 | lock_sock(sk); | 583 | lock_sock(sk); |
566 | 584 | ||
567 | if (sk->sk_state != BT_LISTEN) { | ||
568 | err = -EBADFD; | ||
569 | goto done; | ||
570 | } | ||
571 | |||
572 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); | 585 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); |
573 | 586 | ||
574 | BT_DBG("sk %p timeo %ld", sk, timeo); | 587 | BT_DBG("sk %p timeo %ld", sk, timeo); |
575 | 588 | ||
576 | /* Wait for an incoming connection. (wake-one). */ | 589 | /* Wait for an incoming connection. (wake-one). */ |
577 | add_wait_queue_exclusive(sk_sleep(sk), &wait); | 590 | add_wait_queue_exclusive(sk_sleep(sk), &wait); |
578 | while (!(ch = bt_accept_dequeue(sk, newsock))) { | 591 | while (1) { |
579 | set_current_state(TASK_INTERRUPTIBLE); | 592 | set_current_state(TASK_INTERRUPTIBLE); |
580 | if (!timeo) { | 593 | |
581 | err = -EAGAIN; | 594 | if (sk->sk_state != BT_LISTEN) { |
595 | err = -EBADFD; | ||
582 | break; | 596 | break; |
583 | } | 597 | } |
584 | 598 | ||
585 | release_sock(sk); | 599 | ch = bt_accept_dequeue(sk, newsock); |
586 | timeo = schedule_timeout(timeo); | 600 | if (ch) |
587 | lock_sock(sk); | 601 | break; |
588 | 602 | ||
589 | if (sk->sk_state != BT_LISTEN) { | 603 | if (!timeo) { |
590 | err = -EBADFD; | 604 | err = -EAGAIN; |
591 | break; | 605 | break; |
592 | } | 606 | } |
593 | 607 | ||
@@ -595,8 +609,12 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag | |||
595 | err = sock_intr_errno(timeo); | 609 | err = sock_intr_errno(timeo); |
596 | break; | 610 | break; |
597 | } | 611 | } |
612 | |||
613 | release_sock(sk); | ||
614 | timeo = schedule_timeout(timeo); | ||
615 | lock_sock(sk); | ||
598 | } | 616 | } |
599 | set_current_state(TASK_RUNNING); | 617 | __set_current_state(TASK_RUNNING); |
600 | remove_wait_queue(sk_sleep(sk), &wait); | 618 | remove_wait_queue(sk_sleep(sk), &wait); |
601 | 619 | ||
602 | if (err) | 620 | if (err) |
@@ -625,6 +643,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len | |||
625 | bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst); | 643 | bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst); |
626 | else | 644 | else |
627 | bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src); | 645 | bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src); |
646 | sa->sco_pkt_type = sco_pi(sk)->pkt_type; | ||
628 | 647 | ||
629 | return 0; | 648 | return 0; |
630 | } | 649 | } |
@@ -932,7 +951,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) | |||
932 | if (conn) | 951 | if (conn) |
933 | sco_conn_ready(conn); | 952 | sco_conn_ready(conn); |
934 | } else | 953 | } else |
935 | sco_conn_del(hcon, bt_err(status)); | 954 | sco_conn_del(hcon, bt_to_errno(status)); |
936 | 955 | ||
937 | return 0; | 956 | return 0; |
938 | } | 957 | } |
@@ -944,7 +963,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) | |||
944 | if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) | 963 | if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) |
945 | return -EINVAL; | 964 | return -EINVAL; |
946 | 965 | ||
947 | sco_conn_del(hcon, bt_err(reason)); | 966 | sco_conn_del(hcon, bt_to_errno(reason)); |
948 | 967 | ||
949 | return 0; | 968 | return 0; |
950 | } | 969 | } |