diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 103 |
1 files changed, 57 insertions, 46 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 2b02a3a80313..338837396642 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * net/tipc/socket.c: TIPC socket API | 2 | * net/tipc/socket.c: TIPC socket API |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2007, Ericsson AB | 4 | * Copyright (c) 2001-2007, Ericsson AB |
5 | * Copyright (c) 2004-2008, Wind River Systems | 5 | * Copyright (c) 2004-2008, 2010-2011, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
@@ -58,6 +58,9 @@ struct tipc_sock { | |||
58 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) | 58 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) |
59 | #define tipc_sk_port(sk) ((struct tipc_port *)(tipc_sk(sk)->p)) | 59 | #define tipc_sk_port(sk) ((struct tipc_port *)(tipc_sk(sk)->p)) |
60 | 60 | ||
61 | #define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \ | ||
62 | (sock->state == SS_DISCONNECTING)) | ||
63 | |||
61 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); | 64 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); |
62 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); | 65 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); |
63 | static void wakeupdispatch(struct tipc_port *tport); | 66 | static void wakeupdispatch(struct tipc_port *tport); |
@@ -241,7 +244,6 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, | |||
241 | tipc_set_portunreliable(tp_ptr->ref, 1); | 244 | tipc_set_portunreliable(tp_ptr->ref, 1); |
242 | } | 245 | } |
243 | 246 | ||
244 | atomic_inc(&tipc_user_count); | ||
245 | return 0; | 247 | return 0; |
246 | } | 248 | } |
247 | 249 | ||
@@ -290,7 +292,7 @@ static int release(struct socket *sock) | |||
290 | if (buf == NULL) | 292 | if (buf == NULL) |
291 | break; | 293 | break; |
292 | atomic_dec(&tipc_queue_size); | 294 | atomic_dec(&tipc_queue_size); |
293 | if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) | 295 | if (TIPC_SKB_CB(buf)->handle != 0) |
294 | buf_discard(buf); | 296 | buf_discard(buf); |
295 | else { | 297 | else { |
296 | if ((sock->state == SS_CONNECTING) || | 298 | if ((sock->state == SS_CONNECTING) || |
@@ -321,7 +323,6 @@ static int release(struct socket *sock) | |||
321 | sock_put(sk); | 323 | sock_put(sk); |
322 | sock->sk = NULL; | 324 | sock->sk = NULL; |
323 | 325 | ||
324 | atomic_dec(&tipc_user_count); | ||
325 | return res; | 326 | return res; |
326 | } | 327 | } |
327 | 328 | ||
@@ -495,6 +496,8 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
495 | if (likely(dest->addr.name.name.type != TIPC_CFG_SRV)) | 496 | if (likely(dest->addr.name.name.type != TIPC_CFG_SRV)) |
496 | return -EACCES; | 497 | return -EACCES; |
497 | 498 | ||
499 | if (!m->msg_iovlen || (m->msg_iov[0].iov_len < sizeof(hdr))) | ||
500 | return -EMSGSIZE; | ||
498 | if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr))) | 501 | if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr))) |
499 | return -EFAULT; | 502 | return -EFAULT; |
500 | if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN))) | 503 | if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN))) |
@@ -532,6 +535,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
532 | if (unlikely((m->msg_namelen < sizeof(*dest)) || | 535 | if (unlikely((m->msg_namelen < sizeof(*dest)) || |
533 | (dest->family != AF_TIPC))) | 536 | (dest->family != AF_TIPC))) |
534 | return -EINVAL; | 537 | return -EINVAL; |
538 | if ((total_len > TIPC_MAX_USER_MSG_SIZE) || | ||
539 | (m->msg_iovlen > (unsigned)INT_MAX)) | ||
540 | return -EMSGSIZE; | ||
535 | 541 | ||
536 | if (iocb) | 542 | if (iocb) |
537 | lock_sock(sk); | 543 | lock_sock(sk); |
@@ -570,12 +576,14 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
570 | &dest->addr.name.name, | 576 | &dest->addr.name.name, |
571 | dest->addr.name.domain, | 577 | dest->addr.name.domain, |
572 | m->msg_iovlen, | 578 | m->msg_iovlen, |
573 | m->msg_iov); | 579 | m->msg_iov, |
580 | total_len); | ||
574 | } else if (dest->addrtype == TIPC_ADDR_ID) { | 581 | } else if (dest->addrtype == TIPC_ADDR_ID) { |
575 | res = tipc_send2port(tport->ref, | 582 | res = tipc_send2port(tport->ref, |
576 | &dest->addr.id, | 583 | &dest->addr.id, |
577 | m->msg_iovlen, | 584 | m->msg_iovlen, |
578 | m->msg_iov); | 585 | m->msg_iov, |
586 | total_len); | ||
579 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { | 587 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { |
580 | if (needs_conn) { | 588 | if (needs_conn) { |
581 | res = -EOPNOTSUPP; | 589 | res = -EOPNOTSUPP; |
@@ -587,7 +595,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
587 | res = tipc_multicast(tport->ref, | 595 | res = tipc_multicast(tport->ref, |
588 | &dest->addr.nameseq, | 596 | &dest->addr.nameseq, |
589 | m->msg_iovlen, | 597 | m->msg_iovlen, |
590 | m->msg_iov); | 598 | m->msg_iov, |
599 | total_len); | ||
591 | } | 600 | } |
592 | if (likely(res != -ELINKCONG)) { | 601 | if (likely(res != -ELINKCONG)) { |
593 | if (needs_conn && (res >= 0)) | 602 | if (needs_conn && (res >= 0)) |
@@ -637,6 +646,10 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
637 | if (unlikely(dest)) | 646 | if (unlikely(dest)) |
638 | return send_msg(iocb, sock, m, total_len); | 647 | return send_msg(iocb, sock, m, total_len); |
639 | 648 | ||
649 | if ((total_len > TIPC_MAX_USER_MSG_SIZE) || | ||
650 | (m->msg_iovlen > (unsigned)INT_MAX)) | ||
651 | return -EMSGSIZE; | ||
652 | |||
640 | if (iocb) | 653 | if (iocb) |
641 | lock_sock(sk); | 654 | lock_sock(sk); |
642 | 655 | ||
@@ -649,7 +662,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
649 | break; | 662 | break; |
650 | } | 663 | } |
651 | 664 | ||
652 | res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov); | 665 | res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov, |
666 | total_len); | ||
653 | if (likely(res != -ELINKCONG)) | 667 | if (likely(res != -ELINKCONG)) |
654 | break; | 668 | break; |
655 | if (m->msg_flags & MSG_DONTWAIT) { | 669 | if (m->msg_flags & MSG_DONTWAIT) { |
@@ -720,6 +734,12 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
720 | goto exit; | 734 | goto exit; |
721 | } | 735 | } |
722 | 736 | ||
737 | if ((total_len > (unsigned)INT_MAX) || | ||
738 | (m->msg_iovlen > (unsigned)INT_MAX)) { | ||
739 | res = -EMSGSIZE; | ||
740 | goto exit; | ||
741 | } | ||
742 | |||
723 | /* | 743 | /* |
724 | * Send each iovec entry using one or more messages | 744 | * Send each iovec entry using one or more messages |
725 | * | 745 | * |
@@ -750,7 +770,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
750 | bytes_to_send = curr_left; | 770 | bytes_to_send = curr_left; |
751 | my_iov.iov_base = curr_start; | 771 | my_iov.iov_base = curr_start; |
752 | my_iov.iov_len = bytes_to_send; | 772 | my_iov.iov_len = bytes_to_send; |
753 | res = send_packet(NULL, sock, &my_msg, 0); | 773 | res = send_packet(NULL, sock, &my_msg, bytes_to_send); |
754 | if (res < 0) { | 774 | if (res < 0) { |
755 | if (bytes_sent) | 775 | if (bytes_sent) |
756 | res = bytes_sent; | 776 | res = bytes_sent; |
@@ -911,15 +931,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
911 | struct tipc_port *tport = tipc_sk_port(sk); | 931 | struct tipc_port *tport = tipc_sk_port(sk); |
912 | struct sk_buff *buf; | 932 | struct sk_buff *buf; |
913 | struct tipc_msg *msg; | 933 | struct tipc_msg *msg; |
934 | long timeout; | ||
914 | unsigned int sz; | 935 | unsigned int sz; |
915 | u32 err; | 936 | u32 err; |
916 | int res; | 937 | int res; |
917 | 938 | ||
918 | /* Catch invalid receive requests */ | 939 | /* Catch invalid receive requests */ |
919 | 940 | ||
920 | if (m->msg_iovlen != 1) | ||
921 | return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */ | ||
922 | |||
923 | if (unlikely(!buf_len)) | 941 | if (unlikely(!buf_len)) |
924 | return -EINVAL; | 942 | return -EINVAL; |
925 | 943 | ||
@@ -930,6 +948,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
930 | goto exit; | 948 | goto exit; |
931 | } | 949 | } |
932 | 950 | ||
951 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | ||
933 | restart: | 952 | restart: |
934 | 953 | ||
935 | /* Look for a message in receive queue; wait if necessary */ | 954 | /* Look for a message in receive queue; wait if necessary */ |
@@ -939,17 +958,15 @@ restart: | |||
939 | res = -ENOTCONN; | 958 | res = -ENOTCONN; |
940 | goto exit; | 959 | goto exit; |
941 | } | 960 | } |
942 | if (flags & MSG_DONTWAIT) { | 961 | if (timeout <= 0L) { |
943 | res = -EWOULDBLOCK; | 962 | res = timeout ? timeout : -EWOULDBLOCK; |
944 | goto exit; | 963 | goto exit; |
945 | } | 964 | } |
946 | release_sock(sk); | 965 | release_sock(sk); |
947 | res = wait_event_interruptible(*sk_sleep(sk), | 966 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), |
948 | (!skb_queue_empty(&sk->sk_receive_queue) || | 967 | tipc_rx_ready(sock), |
949 | (sock->state == SS_DISCONNECTING))); | 968 | timeout); |
950 | lock_sock(sk); | 969 | lock_sock(sk); |
951 | if (res) | ||
952 | goto exit; | ||
953 | } | 970 | } |
954 | 971 | ||
955 | /* Look at first message in receive queue */ | 972 | /* Look at first message in receive queue */ |
@@ -991,11 +1008,10 @@ restart: | |||
991 | sz = buf_len; | 1008 | sz = buf_len; |
992 | m->msg_flags |= MSG_TRUNC; | 1009 | m->msg_flags |= MSG_TRUNC; |
993 | } | 1010 | } |
994 | if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg), | 1011 | res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg), |
995 | sz))) { | 1012 | m->msg_iov, sz); |
996 | res = -EFAULT; | 1013 | if (res) |
997 | goto exit; | 1014 | goto exit; |
998 | } | ||
999 | res = sz; | 1015 | res = sz; |
1000 | } else { | 1016 | } else { |
1001 | if ((sock->state == SS_READY) || | 1017 | if ((sock->state == SS_READY) || |
@@ -1038,19 +1054,15 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
1038 | struct tipc_port *tport = tipc_sk_port(sk); | 1054 | struct tipc_port *tport = tipc_sk_port(sk); |
1039 | struct sk_buff *buf; | 1055 | struct sk_buff *buf; |
1040 | struct tipc_msg *msg; | 1056 | struct tipc_msg *msg; |
1057 | long timeout; | ||
1041 | unsigned int sz; | 1058 | unsigned int sz; |
1042 | int sz_to_copy, target, needed; | 1059 | int sz_to_copy, target, needed; |
1043 | int sz_copied = 0; | 1060 | int sz_copied = 0; |
1044 | char __user *crs = m->msg_iov->iov_base; | ||
1045 | unsigned char *buf_crs; | ||
1046 | u32 err; | 1061 | u32 err; |
1047 | int res = 0; | 1062 | int res = 0; |
1048 | 1063 | ||
1049 | /* Catch invalid receive attempts */ | 1064 | /* Catch invalid receive attempts */ |
1050 | 1065 | ||
1051 | if (m->msg_iovlen != 1) | ||
1052 | return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */ | ||
1053 | |||
1054 | if (unlikely(!buf_len)) | 1066 | if (unlikely(!buf_len)) |
1055 | return -EINVAL; | 1067 | return -EINVAL; |
1056 | 1068 | ||
@@ -1063,7 +1075,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
1063 | } | 1075 | } |
1064 | 1076 | ||
1065 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); | 1077 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); |
1066 | 1078 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | |
1067 | restart: | 1079 | restart: |
1068 | 1080 | ||
1069 | /* Look for a message in receive queue; wait if necessary */ | 1081 | /* Look for a message in receive queue; wait if necessary */ |
@@ -1073,17 +1085,15 @@ restart: | |||
1073 | res = -ENOTCONN; | 1085 | res = -ENOTCONN; |
1074 | goto exit; | 1086 | goto exit; |
1075 | } | 1087 | } |
1076 | if (flags & MSG_DONTWAIT) { | 1088 | if (timeout <= 0L) { |
1077 | res = -EWOULDBLOCK; | 1089 | res = timeout ? timeout : -EWOULDBLOCK; |
1078 | goto exit; | 1090 | goto exit; |
1079 | } | 1091 | } |
1080 | release_sock(sk); | 1092 | release_sock(sk); |
1081 | res = wait_event_interruptible(*sk_sleep(sk), | 1093 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), |
1082 | (!skb_queue_empty(&sk->sk_receive_queue) || | 1094 | tipc_rx_ready(sock), |
1083 | (sock->state == SS_DISCONNECTING))); | 1095 | timeout); |
1084 | lock_sock(sk); | 1096 | lock_sock(sk); |
1085 | if (res) | ||
1086 | goto exit; | ||
1087 | } | 1097 | } |
1088 | 1098 | ||
1089 | /* Look at first message in receive queue */ | 1099 | /* Look at first message in receive queue */ |
@@ -1112,24 +1122,25 @@ restart: | |||
1112 | /* Capture message data (if valid) & compute return value (always) */ | 1122 | /* Capture message data (if valid) & compute return value (always) */ |
1113 | 1123 | ||
1114 | if (!err) { | 1124 | if (!err) { |
1115 | buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle); | 1125 | u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); |
1116 | sz = (unsigned char *)msg + msg_size(msg) - buf_crs; | ||
1117 | 1126 | ||
1127 | sz -= offset; | ||
1118 | needed = (buf_len - sz_copied); | 1128 | needed = (buf_len - sz_copied); |
1119 | sz_to_copy = (sz <= needed) ? sz : needed; | 1129 | sz_to_copy = (sz <= needed) ? sz : needed; |
1120 | if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) { | 1130 | |
1121 | res = -EFAULT; | 1131 | res = skb_copy_datagram_iovec(buf, msg_hdr_sz(msg) + offset, |
1132 | m->msg_iov, sz_to_copy); | ||
1133 | if (res) | ||
1122 | goto exit; | 1134 | goto exit; |
1123 | } | 1135 | |
1124 | sz_copied += sz_to_copy; | 1136 | sz_copied += sz_to_copy; |
1125 | 1137 | ||
1126 | if (sz_to_copy < sz) { | 1138 | if (sz_to_copy < sz) { |
1127 | if (!(flags & MSG_PEEK)) | 1139 | if (!(flags & MSG_PEEK)) |
1128 | TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy; | 1140 | TIPC_SKB_CB(buf)->handle = |
1141 | (void *)(unsigned long)(offset + sz_to_copy); | ||
1129 | goto exit; | 1142 | goto exit; |
1130 | } | 1143 | } |
1131 | |||
1132 | crs += sz_to_copy; | ||
1133 | } else { | 1144 | } else { |
1134 | if (sz_copied != 0) | 1145 | if (sz_copied != 0) |
1135 | goto exit; /* can't add error msg to valid data */ | 1146 | goto exit; /* can't add error msg to valid data */ |
@@ -1256,7 +1267,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
1256 | 1267 | ||
1257 | /* Enqueue message (finally!) */ | 1268 | /* Enqueue message (finally!) */ |
1258 | 1269 | ||
1259 | TIPC_SKB_CB(buf)->handle = msg_data(msg); | 1270 | TIPC_SKB_CB(buf)->handle = 0; |
1260 | atomic_inc(&tipc_queue_size); | 1271 | atomic_inc(&tipc_queue_size); |
1261 | __skb_queue_tail(&sk->sk_receive_queue, buf); | 1272 | __skb_queue_tail(&sk->sk_receive_queue, buf); |
1262 | 1273 | ||
@@ -1608,7 +1619,7 @@ restart: | |||
1608 | buf = __skb_dequeue(&sk->sk_receive_queue); | 1619 | buf = __skb_dequeue(&sk->sk_receive_queue); |
1609 | if (buf) { | 1620 | if (buf) { |
1610 | atomic_dec(&tipc_queue_size); | 1621 | atomic_dec(&tipc_queue_size); |
1611 | if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) { | 1622 | if (TIPC_SKB_CB(buf)->handle != 0) { |
1612 | buf_discard(buf); | 1623 | buf_discard(buf); |
1613 | goto restart; | 1624 | goto restart; |
1614 | } | 1625 | } |