diff options
Diffstat (limited to 'net/nfc/llcp/sock.c')
-rw-r--r-- | net/nfc/llcp/sock.c | 101 |
1 files changed, 88 insertions, 13 deletions
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index ddeb9aa398f..63e4cdc9237 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -142,6 +142,60 @@ error: | |||
142 | return ret; | 142 | return ret; |
143 | } | 143 | } |
144 | 144 | ||
145 | static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr, | ||
146 | int alen) | ||
147 | { | ||
148 | struct sock *sk = sock->sk; | ||
149 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
150 | struct nfc_llcp_local *local; | ||
151 | struct nfc_dev *dev; | ||
152 | struct sockaddr_nfc_llcp llcp_addr; | ||
153 | int len, ret = 0; | ||
154 | |||
155 | if (!addr || addr->sa_family != AF_NFC) | ||
156 | return -EINVAL; | ||
157 | |||
158 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
159 | |||
160 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | ||
161 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | ||
162 | memcpy(&llcp_addr, addr, len); | ||
163 | |||
164 | lock_sock(sk); | ||
165 | |||
166 | if (sk->sk_state != LLCP_CLOSED) { | ||
167 | ret = -EBADFD; | ||
168 | goto error; | ||
169 | } | ||
170 | |||
171 | dev = nfc_get_device(llcp_addr.dev_idx); | ||
172 | if (dev == NULL) { | ||
173 | ret = -ENODEV; | ||
174 | goto error; | ||
175 | } | ||
176 | |||
177 | local = nfc_llcp_find_local(dev); | ||
178 | if (local == NULL) { | ||
179 | ret = -ENODEV; | ||
180 | goto put_dev; | ||
181 | } | ||
182 | |||
183 | llcp_sock->dev = dev; | ||
184 | llcp_sock->local = nfc_llcp_local_get(local); | ||
185 | llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; | ||
186 | |||
187 | nfc_llcp_sock_link(&local->raw_sockets, sk); | ||
188 | |||
189 | sk->sk_state = LLCP_BOUND; | ||
190 | |||
191 | put_dev: | ||
192 | nfc_put_device(dev); | ||
193 | |||
194 | error: | ||
195 | release_sock(sk); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
145 | static int llcp_sock_listen(struct socket *sock, int backlog) | 199 | static int llcp_sock_listen(struct socket *sock, int backlog) |
146 | { | 200 | { |
147 | struct sock *sk = sock->sk; | 201 | struct sock *sk = sock->sk; |
@@ -300,9 +354,6 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, | |||
300 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, | 354 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, |
301 | llcp_sock->dsap, llcp_sock->ssap); | 355 | llcp_sock->dsap, llcp_sock->ssap); |
302 | 356 | ||
303 | if (llcp_sock == NULL || llcp_sock->dev == NULL) | ||
304 | return -EBADFD; | ||
305 | |||
306 | uaddr->sa_family = AF_NFC; | 357 | uaddr->sa_family = AF_NFC; |
307 | 358 | ||
308 | *len = sizeof(struct sockaddr_nfc_llcp); | 359 | *len = sizeof(struct sockaddr_nfc_llcp); |
@@ -421,7 +472,10 @@ static int llcp_sock_release(struct socket *sock) | |||
421 | 472 | ||
422 | release_sock(sk); | 473 | release_sock(sk); |
423 | 474 | ||
424 | nfc_llcp_sock_unlink(&local->sockets, sk); | 475 | if (sock->type == SOCK_RAW) |
476 | nfc_llcp_sock_unlink(&local->raw_sockets, sk); | ||
477 | else | ||
478 | nfc_llcp_sock_unlink(&local->sockets, sk); | ||
425 | 479 | ||
426 | out: | 480 | out: |
427 | sock_orphan(sk); | 481 | sock_orphan(sk); |
@@ -443,15 +497,11 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, | |||
443 | pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags); | 497 | pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags); |
444 | 498 | ||
445 | if (!addr || len < sizeof(struct sockaddr_nfc) || | 499 | if (!addr || len < sizeof(struct sockaddr_nfc) || |
446 | addr->sa_family != AF_NFC) { | 500 | addr->sa_family != AF_NFC) |
447 | pr_err("Invalid socket\n"); | ||
448 | return -EINVAL; | 501 | return -EINVAL; |
449 | } | ||
450 | 502 | ||
451 | if (addr->service_name_len == 0 && addr->dsap == 0) { | 503 | if (addr->service_name_len == 0 && addr->dsap == 0) |
452 | pr_err("Missing service name or dsap\n"); | ||
453 | return -EINVAL; | 504 | return -EINVAL; |
454 | } | ||
455 | 505 | ||
456 | pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx, | 506 | pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx, |
457 | addr->target_idx, addr->nfc_protocol); | 507 | addr->target_idx, addr->nfc_protocol); |
@@ -617,7 +667,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
617 | if (!(flags & MSG_PEEK)) { | 667 | if (!(flags & MSG_PEEK)) { |
618 | 668 | ||
619 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ | 669 | /* SOCK_STREAM: re-queue skb if it contains unreceived data */ |
620 | if (sk->sk_type == SOCK_STREAM) { | 670 | if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_RAW) { |
621 | skb_pull(skb, copied); | 671 | skb_pull(skb, copied); |
622 | if (skb->len) { | 672 | if (skb->len) { |
623 | skb_queue_head(&sk->sk_receive_queue, skb); | 673 | skb_queue_head(&sk->sk_receive_queue, skb); |
@@ -658,6 +708,26 @@ static const struct proto_ops llcp_sock_ops = { | |||
658 | .mmap = sock_no_mmap, | 708 | .mmap = sock_no_mmap, |
659 | }; | 709 | }; |
660 | 710 | ||
711 | static const struct proto_ops llcp_rawsock_ops = { | ||
712 | .family = PF_NFC, | ||
713 | .owner = THIS_MODULE, | ||
714 | .bind = llcp_raw_sock_bind, | ||
715 | .connect = sock_no_connect, | ||
716 | .release = llcp_sock_release, | ||
717 | .socketpair = sock_no_socketpair, | ||
718 | .accept = sock_no_accept, | ||
719 | .getname = llcp_sock_getname, | ||
720 | .poll = llcp_sock_poll, | ||
721 | .ioctl = sock_no_ioctl, | ||
722 | .listen = sock_no_listen, | ||
723 | .shutdown = sock_no_shutdown, | ||
724 | .setsockopt = sock_no_setsockopt, | ||
725 | .getsockopt = sock_no_getsockopt, | ||
726 | .sendmsg = sock_no_sendmsg, | ||
727 | .recvmsg = llcp_sock_recvmsg, | ||
728 | .mmap = sock_no_mmap, | ||
729 | }; | ||
730 | |||
661 | static void llcp_sock_destruct(struct sock *sk) | 731 | static void llcp_sock_destruct(struct sock *sk) |
662 | { | 732 | { |
663 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 733 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -735,10 +805,15 @@ static int llcp_sock_create(struct net *net, struct socket *sock, | |||
735 | 805 | ||
736 | pr_debug("%p\n", sock); | 806 | pr_debug("%p\n", sock); |
737 | 807 | ||
738 | if (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM) | 808 | if (sock->type != SOCK_STREAM && |
809 | sock->type != SOCK_DGRAM && | ||
810 | sock->type != SOCK_RAW) | ||
739 | return -ESOCKTNOSUPPORT; | 811 | return -ESOCKTNOSUPPORT; |
740 | 812 | ||
741 | sock->ops = &llcp_sock_ops; | 813 | if (sock->type == SOCK_RAW) |
814 | sock->ops = &llcp_rawsock_ops; | ||
815 | else | ||
816 | sock->ops = &llcp_sock_ops; | ||
742 | 817 | ||
743 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); | 818 | sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); |
744 | if (sk == NULL) | 819 | if (sk == NULL) |