diff options
Diffstat (limited to 'net/caif/caif_socket.c')
-rw-r--r-- | net/caif/caif_socket.c | 152 |
1 files changed, 72 insertions, 80 deletions
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index c3a70c5c893a..8ce904786116 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c | |||
@@ -28,8 +28,8 @@ | |||
28 | MODULE_LICENSE("GPL"); | 28 | MODULE_LICENSE("GPL"); |
29 | MODULE_ALIAS_NETPROTO(AF_CAIF); | 29 | MODULE_ALIAS_NETPROTO(AF_CAIF); |
30 | 30 | ||
31 | #define CAIF_DEF_SNDBUF (CAIF_MAX_PAYLOAD_SIZE*10) | 31 | #define CAIF_DEF_SNDBUF (4096*10) |
32 | #define CAIF_DEF_RCVBUF (CAIF_MAX_PAYLOAD_SIZE*100) | 32 | #define CAIF_DEF_RCVBUF (4096*100) |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * CAIF state is re-using the TCP socket states. | 35 | * CAIF state is re-using the TCP socket states. |
@@ -60,7 +60,7 @@ struct debug_fs_counter { | |||
60 | atomic_t num_rx_flow_off; | 60 | atomic_t num_rx_flow_off; |
61 | atomic_t num_rx_flow_on; | 61 | atomic_t num_rx_flow_on; |
62 | }; | 62 | }; |
63 | struct debug_fs_counter cnt; | 63 | static struct debug_fs_counter cnt; |
64 | #define dbfs_atomic_inc(v) atomic_inc(v) | 64 | #define dbfs_atomic_inc(v) atomic_inc(v) |
65 | #define dbfs_atomic_dec(v) atomic_dec(v) | 65 | #define dbfs_atomic_dec(v) atomic_dec(v) |
66 | #else | 66 | #else |
@@ -76,6 +76,7 @@ struct caifsock { | |||
76 | struct caif_connect_request conn_req; | 76 | struct caif_connect_request conn_req; |
77 | struct mutex readlock; | 77 | struct mutex readlock; |
78 | struct dentry *debugfs_socket_dir; | 78 | struct dentry *debugfs_socket_dir; |
79 | int headroom, tailroom, maxframe; | ||
79 | }; | 80 | }; |
80 | 81 | ||
81 | static int rx_flow_is_on(struct caifsock *cf_sk) | 82 | static int rx_flow_is_on(struct caifsock *cf_sk) |
@@ -128,17 +129,17 @@ static void caif_read_unlock(struct sock *sk) | |||
128 | mutex_unlock(&cf_sk->readlock); | 129 | mutex_unlock(&cf_sk->readlock); |
129 | } | 130 | } |
130 | 131 | ||
131 | int sk_rcvbuf_lowwater(struct caifsock *cf_sk) | 132 | static int sk_rcvbuf_lowwater(struct caifsock *cf_sk) |
132 | { | 133 | { |
133 | /* A quarter of full buffer is used a low water mark */ | 134 | /* A quarter of full buffer is used a low water mark */ |
134 | return cf_sk->sk.sk_rcvbuf / 4; | 135 | return cf_sk->sk.sk_rcvbuf / 4; |
135 | } | 136 | } |
136 | 137 | ||
137 | void caif_flow_ctrl(struct sock *sk, int mode) | 138 | static void caif_flow_ctrl(struct sock *sk, int mode) |
138 | { | 139 | { |
139 | struct caifsock *cf_sk; | 140 | struct caifsock *cf_sk; |
140 | cf_sk = container_of(sk, struct caifsock, sk); | 141 | cf_sk = container_of(sk, struct caifsock, sk); |
141 | if (cf_sk->layer.dn) | 142 | if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd) |
142 | cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode); | 143 | cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode); |
143 | } | 144 | } |
144 | 145 | ||
@@ -146,7 +147,7 @@ void caif_flow_ctrl(struct sock *sk, int mode) | |||
146 | * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are | 147 | * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are |
147 | * not dropped, but CAIF is sending flow off instead. | 148 | * not dropped, but CAIF is sending flow off instead. |
148 | */ | 149 | */ |
149 | int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | 150 | static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) |
150 | { | 151 | { |
151 | int err; | 152 | int err; |
152 | int skb_len; | 153 | int skb_len; |
@@ -162,9 +163,8 @@ int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
162 | atomic_read(&cf_sk->sk.sk_rmem_alloc), | 163 | atomic_read(&cf_sk->sk.sk_rmem_alloc), |
163 | sk_rcvbuf_lowwater(cf_sk)); | 164 | sk_rcvbuf_lowwater(cf_sk)); |
164 | set_rx_flow_off(cf_sk); | 165 | set_rx_flow_off(cf_sk); |
165 | if (cf_sk->layer.dn) | 166 | dbfs_atomic_inc(&cnt.num_rx_flow_off); |
166 | cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, | 167 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); |
167 | CAIF_MODEMCMD_FLOW_OFF_REQ); | ||
168 | } | 168 | } |
169 | 169 | ||
170 | err = sk_filter(sk, skb); | 170 | err = sk_filter(sk, skb); |
@@ -175,9 +175,8 @@ int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
175 | trace_printk("CAIF: %s():" | 175 | trace_printk("CAIF: %s():" |
176 | " sending flow OFF due to rmem_schedule\n", | 176 | " sending flow OFF due to rmem_schedule\n", |
177 | __func__); | 177 | __func__); |
178 | if (cf_sk->layer.dn) | 178 | dbfs_atomic_inc(&cnt.num_rx_flow_off); |
179 | cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, | 179 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); |
180 | CAIF_MODEMCMD_FLOW_OFF_REQ); | ||
181 | } | 180 | } |
182 | skb->dev = NULL; | 181 | skb->dev = NULL; |
183 | skb_set_owner_r(skb, sk); | 182 | skb_set_owner_r(skb, sk); |
@@ -285,65 +284,51 @@ static void caif_check_flow_release(struct sock *sk) | |||
285 | { | 284 | { |
286 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); | 285 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); |
287 | 286 | ||
288 | if (cf_sk->layer.dn == NULL || cf_sk->layer.dn->modemcmd == NULL) | ||
289 | return; | ||
290 | if (rx_flow_is_on(cf_sk)) | 287 | if (rx_flow_is_on(cf_sk)) |
291 | return; | 288 | return; |
292 | 289 | ||
293 | if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) { | 290 | if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) { |
294 | dbfs_atomic_inc(&cnt.num_rx_flow_on); | 291 | dbfs_atomic_inc(&cnt.num_rx_flow_on); |
295 | set_rx_flow_on(cf_sk); | 292 | set_rx_flow_on(cf_sk); |
296 | cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, | 293 | caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ); |
297 | CAIF_MODEMCMD_FLOW_ON_REQ); | ||
298 | } | 294 | } |
299 | } | 295 | } |
296 | |||
300 | /* | 297 | /* |
301 | * Copied from sock.c:sock_queue_rcv_skb(), and added check that user buffer | 298 | * Copied from unix_dgram_recvmsg, but removed credit checks, |
302 | * has sufficient size. | 299 | * changed locking, address handling and added MSG_TRUNC. |
303 | */ | 300 | */ |
304 | |||
305 | static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock, | 301 | static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock, |
306 | struct msghdr *m, size_t buf_len, int flags) | 302 | struct msghdr *m, size_t len, int flags) |
307 | 303 | ||
308 | { | 304 | { |
309 | struct sock *sk = sock->sk; | 305 | struct sock *sk = sock->sk; |
310 | struct sk_buff *skb; | 306 | struct sk_buff *skb; |
311 | int ret = 0; | 307 | int ret; |
312 | int len; | 308 | int copylen; |
313 | 309 | ||
314 | if (unlikely(!buf_len)) | 310 | ret = -EOPNOTSUPP; |
315 | return -EINVAL; | 311 | if (m->msg_flags&MSG_OOB) |
312 | goto read_error; | ||
316 | 313 | ||
317 | skb = skb_recv_datagram(sk, flags, 0 , &ret); | 314 | skb = skb_recv_datagram(sk, flags, 0 , &ret); |
318 | if (!skb) | 315 | if (!skb) |
319 | goto read_error; | 316 | goto read_error; |
320 | 317 | copylen = skb->len; | |
321 | len = skb->len; | 318 | if (len < copylen) { |
322 | 319 | m->msg_flags |= MSG_TRUNC; | |
323 | if (skb && skb->len > buf_len && !(flags & MSG_PEEK)) { | 320 | copylen = len; |
324 | len = buf_len; | ||
325 | /* | ||
326 | * Push skb back on receive queue if buffer too small. | ||
327 | * This has a built-in race where multi-threaded receive | ||
328 | * may get packet in wrong order, but multiple read does | ||
329 | * not really guarantee ordered delivery anyway. | ||
330 | * Let's optimize for speed without taking locks. | ||
331 | */ | ||
332 | |||
333 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
334 | ret = -EMSGSIZE; | ||
335 | goto read_error; | ||
336 | } | 321 | } |
337 | 322 | ||
338 | ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, len); | 323 | ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, copylen); |
339 | if (ret) | 324 | if (ret) |
340 | goto read_error; | 325 | goto out_free; |
341 | 326 | ||
327 | ret = (flags & MSG_TRUNC) ? skb->len : copylen; | ||
328 | out_free: | ||
342 | skb_free_datagram(sk, skb); | 329 | skb_free_datagram(sk, skb); |
343 | |||
344 | caif_check_flow_release(sk); | 330 | caif_check_flow_release(sk); |
345 | 331 | return ret; | |
346 | return len; | ||
347 | 332 | ||
348 | read_error: | 333 | read_error: |
349 | return ret; | 334 | return ret; |
@@ -610,27 +595,32 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
610 | goto err; | 595 | goto err; |
611 | noblock = msg->msg_flags & MSG_DONTWAIT; | 596 | noblock = msg->msg_flags & MSG_DONTWAIT; |
612 | 597 | ||
613 | buffer_size = len + CAIF_NEEDED_HEADROOM + CAIF_NEEDED_TAILROOM; | ||
614 | |||
615 | ret = -EMSGSIZE; | ||
616 | if (buffer_size > CAIF_MAX_PAYLOAD_SIZE) | ||
617 | goto err; | ||
618 | |||
619 | timeo = sock_sndtimeo(sk, noblock); | 598 | timeo = sock_sndtimeo(sk, noblock); |
620 | timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk), | 599 | timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk), |
621 | 1, timeo, &ret); | 600 | 1, timeo, &ret); |
622 | 601 | ||
602 | if (ret) | ||
603 | goto err; | ||
623 | ret = -EPIPE; | 604 | ret = -EPIPE; |
624 | if (cf_sk->sk.sk_state != CAIF_CONNECTED || | 605 | if (cf_sk->sk.sk_state != CAIF_CONNECTED || |
625 | sock_flag(sk, SOCK_DEAD) || | 606 | sock_flag(sk, SOCK_DEAD) || |
626 | (sk->sk_shutdown & RCV_SHUTDOWN)) | 607 | (sk->sk_shutdown & RCV_SHUTDOWN)) |
627 | goto err; | 608 | goto err; |
628 | 609 | ||
610 | /* Error if trying to write more than maximum frame size. */ | ||
611 | ret = -EMSGSIZE; | ||
612 | if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM) | ||
613 | goto err; | ||
614 | |||
615 | buffer_size = len + cf_sk->headroom + cf_sk->tailroom; | ||
616 | |||
629 | ret = -ENOMEM; | 617 | ret = -ENOMEM; |
630 | skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret); | 618 | skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret); |
631 | if (!skb) | 619 | |
620 | if (!skb || skb_tailroom(skb) < buffer_size) | ||
632 | goto err; | 621 | goto err; |
633 | skb_reserve(skb, CAIF_NEEDED_HEADROOM); | 622 | |
623 | skb_reserve(skb, cf_sk->headroom); | ||
634 | 624 | ||
635 | ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); | 625 | ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); |
636 | 626 | ||
@@ -661,7 +651,6 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
661 | long timeo; | 651 | long timeo; |
662 | 652 | ||
663 | err = -EOPNOTSUPP; | 653 | err = -EOPNOTSUPP; |
664 | |||
665 | if (unlikely(msg->msg_flags&MSG_OOB)) | 654 | if (unlikely(msg->msg_flags&MSG_OOB)) |
666 | goto out_err; | 655 | goto out_err; |
667 | 656 | ||
@@ -678,8 +667,8 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
678 | 667 | ||
679 | size = len-sent; | 668 | size = len-sent; |
680 | 669 | ||
681 | if (size > CAIF_MAX_PAYLOAD_SIZE) | 670 | if (size > cf_sk->maxframe) |
682 | size = CAIF_MAX_PAYLOAD_SIZE; | 671 | size = cf_sk->maxframe; |
683 | 672 | ||
684 | /* If size is more than half of sndbuf, chop up message */ | 673 | /* If size is more than half of sndbuf, chop up message */ |
685 | if (size > ((sk->sk_sndbuf >> 1) - 64)) | 674 | if (size > ((sk->sk_sndbuf >> 1) - 64)) |
@@ -689,14 +678,14 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
689 | size = SKB_MAX_ALLOC; | 678 | size = SKB_MAX_ALLOC; |
690 | 679 | ||
691 | skb = sock_alloc_send_skb(sk, | 680 | skb = sock_alloc_send_skb(sk, |
692 | size + CAIF_NEEDED_HEADROOM | 681 | size + cf_sk->headroom + |
693 | + CAIF_NEEDED_TAILROOM, | 682 | cf_sk->tailroom, |
694 | msg->msg_flags&MSG_DONTWAIT, | 683 | msg->msg_flags&MSG_DONTWAIT, |
695 | &err); | 684 | &err); |
696 | if (skb == NULL) | 685 | if (skb == NULL) |
697 | goto out_err; | 686 | goto out_err; |
698 | 687 | ||
699 | skb_reserve(skb, CAIF_NEEDED_HEADROOM); | 688 | skb_reserve(skb, cf_sk->headroom); |
700 | /* | 689 | /* |
701 | * If you pass two values to the sock_alloc_send_skb | 690 | * If you pass two values to the sock_alloc_send_skb |
702 | * it tries to grab the large buffer with GFP_NOFS | 691 | * it tries to grab the large buffer with GFP_NOFS |
@@ -837,17 +826,15 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
837 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); | 826 | struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); |
838 | long timeo; | 827 | long timeo; |
839 | int err; | 828 | int err; |
829 | int ifindex, headroom, tailroom; | ||
830 | struct net_device *dev; | ||
831 | |||
840 | lock_sock(sk); | 832 | lock_sock(sk); |
841 | 833 | ||
842 | err = -EAFNOSUPPORT; | 834 | err = -EAFNOSUPPORT; |
843 | if (uaddr->sa_family != AF_CAIF) | 835 | if (uaddr->sa_family != AF_CAIF) |
844 | goto out; | 836 | goto out; |
845 | 837 | ||
846 | err = -ESOCKTNOSUPPORT; | ||
847 | if (unlikely(!(sk->sk_type == SOCK_STREAM && | ||
848 | cf_sk->sk.sk_protocol == CAIFPROTO_AT) && | ||
849 | sk->sk_type != SOCK_SEQPACKET)) | ||
850 | goto out; | ||
851 | switch (sock->state) { | 838 | switch (sock->state) { |
852 | case SS_UNCONNECTED: | 839 | case SS_UNCONNECTED: |
853 | /* Normal case, a fresh connect */ | 840 | /* Normal case, a fresh connect */ |
@@ -890,8 +877,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
890 | sk_stream_kill_queues(&cf_sk->sk); | 877 | sk_stream_kill_queues(&cf_sk->sk); |
891 | 878 | ||
892 | err = -EINVAL; | 879 | err = -EINVAL; |
893 | if (addr_len != sizeof(struct sockaddr_caif) || | 880 | if (addr_len != sizeof(struct sockaddr_caif)) |
894 | !uaddr) | ||
895 | goto out; | 881 | goto out; |
896 | 882 | ||
897 | memcpy(&cf_sk->conn_req.sockaddr, uaddr, | 883 | memcpy(&cf_sk->conn_req.sockaddr, uaddr, |
@@ -904,12 +890,23 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, | |||
904 | dbfs_atomic_inc(&cnt.num_connect_req); | 890 | dbfs_atomic_inc(&cnt.num_connect_req); |
905 | cf_sk->layer.receive = caif_sktrecv_cb; | 891 | cf_sk->layer.receive = caif_sktrecv_cb; |
906 | err = caif_connect_client(&cf_sk->conn_req, | 892 | err = caif_connect_client(&cf_sk->conn_req, |
907 | &cf_sk->layer); | 893 | &cf_sk->layer, &ifindex, &headroom, &tailroom); |
908 | if (err < 0) { | 894 | if (err < 0) { |
909 | cf_sk->sk.sk_socket->state = SS_UNCONNECTED; | 895 | cf_sk->sk.sk_socket->state = SS_UNCONNECTED; |
910 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; | 896 | cf_sk->sk.sk_state = CAIF_DISCONNECTED; |
911 | goto out; | 897 | goto out; |
912 | } | 898 | } |
899 | dev = dev_get_by_index(sock_net(sk), ifindex); | ||
900 | cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom); | ||
901 | cf_sk->tailroom = tailroom; | ||
902 | cf_sk->maxframe = dev->mtu - (headroom + tailroom); | ||
903 | dev_put(dev); | ||
904 | if (cf_sk->maxframe < 1) { | ||
905 | pr_warning("CAIF: %s(): CAIF Interface MTU too small (%d)\n", | ||
906 | __func__, dev->mtu); | ||
907 | err = -ENODEV; | ||
908 | goto out; | ||
909 | } | ||
913 | 910 | ||
914 | err = -EINPROGRESS; | 911 | err = -EINPROGRESS; |
915 | wait_connect: | 912 | wait_connect: |
@@ -920,17 +917,17 @@ wait_connect: | |||
920 | timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); | 917 | timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); |
921 | 918 | ||
922 | release_sock(sk); | 919 | release_sock(sk); |
923 | err = wait_event_interruptible_timeout(*sk_sleep(sk), | 920 | err = -ERESTARTSYS; |
921 | timeo = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
924 | sk->sk_state != CAIF_CONNECTING, | 922 | sk->sk_state != CAIF_CONNECTING, |
925 | timeo); | 923 | timeo); |
926 | lock_sock(sk); | 924 | lock_sock(sk); |
927 | if (err < 0) | 925 | if (timeo < 0) |
928 | goto out; /* -ERESTARTSYS */ | 926 | goto out; /* -ERESTARTSYS */ |
929 | if (err == 0 && sk->sk_state != CAIF_CONNECTED) { | ||
930 | err = -ETIMEDOUT; | ||
931 | goto out; | ||
932 | } | ||
933 | 927 | ||
928 | err = -ETIMEDOUT; | ||
929 | if (timeo == 0 && sk->sk_state != CAIF_CONNECTED) | ||
930 | goto out; | ||
934 | if (sk->sk_state != CAIF_CONNECTED) { | 931 | if (sk->sk_state != CAIF_CONNECTED) { |
935 | sock->state = SS_UNCONNECTED; | 932 | sock->state = SS_UNCONNECTED; |
936 | err = sock_error(sk); | 933 | err = sock_error(sk); |
@@ -945,7 +942,6 @@ out: | |||
945 | return err; | 942 | return err; |
946 | } | 943 | } |
947 | 944 | ||
948 | |||
949 | /* | 945 | /* |
950 | * caif_release() - Disconnect a CAIF Socket | 946 | * caif_release() - Disconnect a CAIF Socket |
951 | * Copied and modified af_irda.c:irda_release(). | 947 | * Copied and modified af_irda.c:irda_release(). |
@@ -1019,10 +1015,6 @@ static unsigned int caif_poll(struct file *file, | |||
1019 | (sk->sk_shutdown & RCV_SHUTDOWN)) | 1015 | (sk->sk_shutdown & RCV_SHUTDOWN)) |
1020 | mask |= POLLIN | POLLRDNORM; | 1016 | mask |= POLLIN | POLLRDNORM; |
1021 | 1017 | ||
1022 | /* Connection-based need to check for termination and startup */ | ||
1023 | if (sk->sk_state == CAIF_DISCONNECTED) | ||
1024 | mask |= POLLHUP; | ||
1025 | |||
1026 | /* | 1018 | /* |
1027 | * we set writable also when the other side has shut down the | 1019 | * we set writable also when the other side has shut down the |
1028 | * connection. This prevents stuck sockets. | 1020 | * connection. This prevents stuck sockets. |
@@ -1194,7 +1186,7 @@ static struct net_proto_family caif_family_ops = { | |||
1194 | .owner = THIS_MODULE, | 1186 | .owner = THIS_MODULE, |
1195 | }; | 1187 | }; |
1196 | 1188 | ||
1197 | int af_caif_init(void) | 1189 | static int af_caif_init(void) |
1198 | { | 1190 | { |
1199 | int err = sock_register(&caif_family_ops); | 1191 | int err = sock_register(&caif_family_ops); |
1200 | if (!err) | 1192 | if (!err) |