diff options
Diffstat (limited to 'drivers/net/pppol2tp.c')
-rw-r--r-- | drivers/net/pppol2tp.c | 157 |
1 files changed, 118 insertions, 39 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 244d7830c92a..f9298827a76c 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
@@ -240,12 +240,15 @@ static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk) | |||
240 | if (sk == NULL) | 240 | if (sk == NULL) |
241 | return NULL; | 241 | return NULL; |
242 | 242 | ||
243 | sock_hold(sk); | ||
243 | session = (struct pppol2tp_session *)(sk->sk_user_data); | 244 | session = (struct pppol2tp_session *)(sk->sk_user_data); |
244 | if (session == NULL) | 245 | if (session == NULL) { |
245 | return NULL; | 246 | sock_put(sk); |
247 | goto out; | ||
248 | } | ||
246 | 249 | ||
247 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); | 250 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); |
248 | 251 | out: | |
249 | return session; | 252 | return session; |
250 | } | 253 | } |
251 | 254 | ||
@@ -256,12 +259,15 @@ static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk) | |||
256 | if (sk == NULL) | 259 | if (sk == NULL) |
257 | return NULL; | 260 | return NULL; |
258 | 261 | ||
262 | sock_hold(sk); | ||
259 | tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data); | 263 | tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data); |
260 | if (tunnel == NULL) | 264 | if (tunnel == NULL) { |
261 | return NULL; | 265 | sock_put(sk); |
266 | goto out; | ||
267 | } | ||
262 | 268 | ||
263 | BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); | 269 | BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); |
264 | 270 | out: | |
265 | return tunnel; | 271 | return tunnel; |
266 | } | 272 | } |
267 | 273 | ||
@@ -716,12 +722,14 @@ discard: | |||
716 | session->stats.rx_errors++; | 722 | session->stats.rx_errors++; |
717 | kfree_skb(skb); | 723 | kfree_skb(skb); |
718 | sock_put(session->sock); | 724 | sock_put(session->sock); |
725 | sock_put(sock); | ||
719 | 726 | ||
720 | return 0; | 727 | return 0; |
721 | 728 | ||
722 | error: | 729 | error: |
723 | /* Put UDP header back */ | 730 | /* Put UDP header back */ |
724 | __skb_push(skb, sizeof(struct udphdr)); | 731 | __skb_push(skb, sizeof(struct udphdr)); |
732 | sock_put(sock); | ||
725 | 733 | ||
726 | no_tunnel: | 734 | no_tunnel: |
727 | return 1; | 735 | return 1; |
@@ -745,10 +753,13 @@ static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) | |||
745 | "%s: received %d bytes\n", tunnel->name, skb->len); | 753 | "%s: received %d bytes\n", tunnel->name, skb->len); |
746 | 754 | ||
747 | if (pppol2tp_recv_core(sk, skb)) | 755 | if (pppol2tp_recv_core(sk, skb)) |
748 | goto pass_up; | 756 | goto pass_up_put; |
749 | 757 | ||
758 | sock_put(sk); | ||
750 | return 0; | 759 | return 0; |
751 | 760 | ||
761 | pass_up_put: | ||
762 | sock_put(sk); | ||
752 | pass_up: | 763 | pass_up: |
753 | return 1; | 764 | return 1; |
754 | } | 765 | } |
@@ -772,14 +783,18 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
772 | err = 0; | 783 | err = 0; |
773 | skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, | 784 | skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, |
774 | flags & MSG_DONTWAIT, &err); | 785 | flags & MSG_DONTWAIT, &err); |
775 | if (skb) { | 786 | if (!skb) |
776 | err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data, | 787 | goto end; |
777 | skb->len); | 788 | |
778 | if (err < 0) | 789 | if (len > skb->len) |
779 | goto do_skb_free; | 790 | len = skb->len; |
780 | err = skb->len; | 791 | else if (len < skb->len) |
781 | } | 792 | msg->msg_flags |= MSG_TRUNC; |
782 | do_skb_free: | 793 | |
794 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); | ||
795 | if (likely(err == 0)) | ||
796 | err = len; | ||
797 | |||
783 | kfree_skb(skb); | 798 | kfree_skb(skb); |
784 | end: | 799 | end: |
785 | return err; | 800 | return err; |
@@ -858,7 +873,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
858 | 873 | ||
859 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); | 874 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); |
860 | if (tunnel == NULL) | 875 | if (tunnel == NULL) |
861 | goto error; | 876 | goto error_put_sess; |
862 | 877 | ||
863 | /* What header length is configured for this session? */ | 878 | /* What header length is configured for this session? */ |
864 | hdr_len = pppol2tp_l2tp_header_len(session); | 879 | hdr_len = pppol2tp_l2tp_header_len(session); |
@@ -870,7 +885,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
870 | sizeof(ppph) + total_len, | 885 | sizeof(ppph) + total_len, |
871 | 0, GFP_KERNEL); | 886 | 0, GFP_KERNEL); |
872 | if (!skb) | 887 | if (!skb) |
873 | goto error; | 888 | goto error_put_sess_tun; |
874 | 889 | ||
875 | /* Reserve space for headers. */ | 890 | /* Reserve space for headers. */ |
876 | skb_reserve(skb, NET_SKB_PAD); | 891 | skb_reserve(skb, NET_SKB_PAD); |
@@ -900,7 +915,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
900 | error = memcpy_fromiovec(skb->data, m->msg_iov, total_len); | 915 | error = memcpy_fromiovec(skb->data, m->msg_iov, total_len); |
901 | if (error < 0) { | 916 | if (error < 0) { |
902 | kfree_skb(skb); | 917 | kfree_skb(skb); |
903 | goto error; | 918 | goto error_put_sess_tun; |
904 | } | 919 | } |
905 | skb_put(skb, total_len); | 920 | skb_put(skb, total_len); |
906 | 921 | ||
@@ -947,10 +962,33 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh | |||
947 | session->stats.tx_errors++; | 962 | session->stats.tx_errors++; |
948 | } | 963 | } |
949 | 964 | ||
965 | return error; | ||
966 | |||
967 | error_put_sess_tun: | ||
968 | sock_put(session->tunnel_sock); | ||
969 | error_put_sess: | ||
970 | sock_put(sk); | ||
950 | error: | 971 | error: |
951 | return error; | 972 | return error; |
952 | } | 973 | } |
953 | 974 | ||
975 | /* Automatically called when the skb is freed. | ||
976 | */ | ||
977 | static void pppol2tp_sock_wfree(struct sk_buff *skb) | ||
978 | { | ||
979 | sock_put(skb->sk); | ||
980 | } | ||
981 | |||
982 | /* For data skbs that we transmit, we associate with the tunnel socket | ||
983 | * but don't do accounting. | ||
984 | */ | ||
985 | static inline void pppol2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk) | ||
986 | { | ||
987 | sock_hold(sk); | ||
988 | skb->sk = sk; | ||
989 | skb->destructor = pppol2tp_sock_wfree; | ||
990 | } | ||
991 | |||
954 | /* Transmit function called by generic PPP driver. Sends PPP frame | 992 | /* Transmit function called by generic PPP driver. Sends PPP frame |
955 | * over PPPoL2TP socket. | 993 | * over PPPoL2TP socket. |
956 | * | 994 | * |
@@ -980,6 +1018,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
980 | __wsum csum = 0; | 1018 | __wsum csum = 0; |
981 | struct udphdr *uh; | 1019 | struct udphdr *uh; |
982 | unsigned int len; | 1020 | unsigned int len; |
1021 | int old_headroom; | ||
1022 | int new_headroom; | ||
983 | 1023 | ||
984 | if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) | 1024 | if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) |
985 | goto abort; | 1025 | goto abort; |
@@ -991,25 +1031,27 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
991 | 1031 | ||
992 | sk_tun = session->tunnel_sock; | 1032 | sk_tun = session->tunnel_sock; |
993 | if (sk_tun == NULL) | 1033 | if (sk_tun == NULL) |
994 | goto abort; | 1034 | goto abort_put_sess; |
995 | tunnel = pppol2tp_sock_to_tunnel(sk_tun); | 1035 | tunnel = pppol2tp_sock_to_tunnel(sk_tun); |
996 | if (tunnel == NULL) | 1036 | if (tunnel == NULL) |
997 | goto abort; | 1037 | goto abort_put_sess; |
998 | 1038 | ||
999 | /* What header length is configured for this session? */ | 1039 | /* What header length is configured for this session? */ |
1000 | hdr_len = pppol2tp_l2tp_header_len(session); | 1040 | hdr_len = pppol2tp_l2tp_header_len(session); |
1001 | 1041 | ||
1002 | /* Check that there's enough headroom in the skb to insert IP, | 1042 | /* Check that there's enough headroom in the skb to insert IP, |
1003 | * UDP and L2TP and PPP headers. If not enough, expand it to | 1043 | * UDP and L2TP and PPP headers. If not enough, expand it to |
1004 | * make room. Note that a new skb (or a clone) is | 1044 | * make room. Adjust truesize. |
1005 | * allocated. If we return an error from this point on, make | ||
1006 | * sure we free the new skb but do not free the original skb | ||
1007 | * since that is done by the caller for the error case. | ||
1008 | */ | 1045 | */ |
1009 | headroom = NET_SKB_PAD + sizeof(struct iphdr) + | 1046 | headroom = NET_SKB_PAD + sizeof(struct iphdr) + |
1010 | sizeof(struct udphdr) + hdr_len + sizeof(ppph); | 1047 | sizeof(struct udphdr) + hdr_len + sizeof(ppph); |
1048 | old_headroom = skb_headroom(skb); | ||
1011 | if (skb_cow_head(skb, headroom)) | 1049 | if (skb_cow_head(skb, headroom)) |
1012 | goto abort; | 1050 | goto abort_put_sess_tun; |
1051 | |||
1052 | new_headroom = skb_headroom(skb); | ||
1053 | skb_orphan(skb); | ||
1054 | skb->truesize += new_headroom - old_headroom; | ||
1013 | 1055 | ||
1014 | /* Setup PPP header */ | 1056 | /* Setup PPP header */ |
1015 | __skb_push(skb, sizeof(ppph)); | 1057 | __skb_push(skb, sizeof(ppph)); |
@@ -1065,8 +1107,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1065 | /* Get routing info from the tunnel socket */ | 1107 | /* Get routing info from the tunnel socket */ |
1066 | dst_release(skb->dst); | 1108 | dst_release(skb->dst); |
1067 | skb->dst = dst_clone(__sk_dst_get(sk_tun)); | 1109 | skb->dst = dst_clone(__sk_dst_get(sk_tun)); |
1068 | skb_orphan(skb); | 1110 | pppol2tp_skb_set_owner_w(skb, sk_tun); |
1069 | skb->sk = sk_tun; | ||
1070 | 1111 | ||
1071 | /* Queue the packet to IP for output */ | 1112 | /* Queue the packet to IP for output */ |
1072 | len = skb->len; | 1113 | len = skb->len; |
@@ -1083,8 +1124,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
1083 | session->stats.tx_errors++; | 1124 | session->stats.tx_errors++; |
1084 | } | 1125 | } |
1085 | 1126 | ||
1127 | sock_put(sk_tun); | ||
1128 | sock_put(sk); | ||
1086 | return 1; | 1129 | return 1; |
1087 | 1130 | ||
1131 | abort_put_sess_tun: | ||
1132 | sock_put(sk_tun); | ||
1133 | abort_put_sess: | ||
1134 | sock_put(sk); | ||
1088 | abort: | 1135 | abort: |
1089 | /* Free the original skb */ | 1136 | /* Free the original skb */ |
1090 | kfree_skb(skb); | 1137 | kfree_skb(skb); |
@@ -1188,7 +1235,7 @@ static void pppol2tp_tunnel_destruct(struct sock *sk) | |||
1188 | { | 1235 | { |
1189 | struct pppol2tp_tunnel *tunnel; | 1236 | struct pppol2tp_tunnel *tunnel; |
1190 | 1237 | ||
1191 | tunnel = pppol2tp_sock_to_tunnel(sk); | 1238 | tunnel = sk->sk_user_data; |
1192 | if (tunnel == NULL) | 1239 | if (tunnel == NULL) |
1193 | goto end; | 1240 | goto end; |
1194 | 1241 | ||
@@ -1227,10 +1274,12 @@ static void pppol2tp_session_destruct(struct sock *sk) | |||
1227 | if (sk->sk_user_data != NULL) { | 1274 | if (sk->sk_user_data != NULL) { |
1228 | struct pppol2tp_tunnel *tunnel; | 1275 | struct pppol2tp_tunnel *tunnel; |
1229 | 1276 | ||
1230 | session = pppol2tp_sock_to_session(sk); | 1277 | session = sk->sk_user_data; |
1231 | if (session == NULL) | 1278 | if (session == NULL) |
1232 | goto out; | 1279 | goto out; |
1233 | 1280 | ||
1281 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); | ||
1282 | |||
1234 | /* Don't use pppol2tp_sock_to_tunnel() here to | 1283 | /* Don't use pppol2tp_sock_to_tunnel() here to |
1235 | * get the tunnel context because the tunnel | 1284 | * get the tunnel context because the tunnel |
1236 | * socket might have already been closed (its | 1285 | * socket might have already been closed (its |
@@ -1276,6 +1325,7 @@ out: | |||
1276 | static int pppol2tp_release(struct socket *sock) | 1325 | static int pppol2tp_release(struct socket *sock) |
1277 | { | 1326 | { |
1278 | struct sock *sk = sock->sk; | 1327 | struct sock *sk = sock->sk; |
1328 | struct pppol2tp_session *session; | ||
1279 | int error; | 1329 | int error; |
1280 | 1330 | ||
1281 | if (!sk) | 1331 | if (!sk) |
@@ -1293,9 +1343,18 @@ static int pppol2tp_release(struct socket *sock) | |||
1293 | sock_orphan(sk); | 1343 | sock_orphan(sk); |
1294 | sock->sk = NULL; | 1344 | sock->sk = NULL; |
1295 | 1345 | ||
1346 | session = pppol2tp_sock_to_session(sk); | ||
1347 | |||
1296 | /* Purge any queued data */ | 1348 | /* Purge any queued data */ |
1297 | skb_queue_purge(&sk->sk_receive_queue); | 1349 | skb_queue_purge(&sk->sk_receive_queue); |
1298 | skb_queue_purge(&sk->sk_write_queue); | 1350 | skb_queue_purge(&sk->sk_write_queue); |
1351 | if (session != NULL) { | ||
1352 | struct sk_buff *skb; | ||
1353 | while ((skb = skb_dequeue(&session->reorder_q))) { | ||
1354 | kfree_skb(skb); | ||
1355 | sock_put(sk); | ||
1356 | } | ||
1357 | } | ||
1299 | 1358 | ||
1300 | release_sock(sk); | 1359 | release_sock(sk); |
1301 | 1360 | ||
@@ -1598,7 +1657,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
1598 | 1657 | ||
1599 | error = ppp_register_channel(&po->chan); | 1658 | error = ppp_register_channel(&po->chan); |
1600 | if (error) | 1659 | if (error) |
1601 | goto end; | 1660 | goto end_put_tun; |
1602 | 1661 | ||
1603 | /* This is how we get the session context from the socket. */ | 1662 | /* This is how we get the session context from the socket. */ |
1604 | sk->sk_user_data = session; | 1663 | sk->sk_user_data = session; |
@@ -1618,12 +1677,21 @@ out_no_ppp: | |||
1618 | PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, | 1677 | PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, |
1619 | "%s: created\n", session->name); | 1678 | "%s: created\n", session->name); |
1620 | 1679 | ||
1680 | end_put_tun: | ||
1681 | sock_put(tunnel_sock); | ||
1621 | end: | 1682 | end: |
1622 | release_sock(sk); | 1683 | release_sock(sk); |
1623 | 1684 | ||
1624 | if (error != 0) | 1685 | if (error != 0) { |
1625 | PRINTK(session ? session->debug : -1, PPPOL2TP_MSG_CONTROL, KERN_WARNING, | 1686 | if (session) |
1626 | "%s: connect failed: %d\n", session->name, error); | 1687 | PRINTK(session->debug, |
1688 | PPPOL2TP_MSG_CONTROL, KERN_WARNING, | ||
1689 | "%s: connect failed: %d\n", | ||
1690 | session->name, error); | ||
1691 | else | ||
1692 | PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_WARNING, | ||
1693 | "connect failed: %d\n", error); | ||
1694 | } | ||
1627 | 1695 | ||
1628 | return error; | 1696 | return error; |
1629 | } | 1697 | } |
@@ -1658,6 +1726,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, | |||
1658 | *usockaddr_len = len; | 1726 | *usockaddr_len = len; |
1659 | 1727 | ||
1660 | error = 0; | 1728 | error = 0; |
1729 | sock_put(sock->sk); | ||
1661 | 1730 | ||
1662 | end: | 1731 | end: |
1663 | return error; | 1732 | return error; |
@@ -1896,14 +1965,17 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, | |||
1896 | err = -EBADF; | 1965 | err = -EBADF; |
1897 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); | 1966 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); |
1898 | if (tunnel == NULL) | 1967 | if (tunnel == NULL) |
1899 | goto end; | 1968 | goto end_put_sess; |
1900 | 1969 | ||
1901 | err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg); | 1970 | err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg); |
1902 | goto end; | 1971 | sock_put(session->tunnel_sock); |
1972 | goto end_put_sess; | ||
1903 | } | 1973 | } |
1904 | 1974 | ||
1905 | err = pppol2tp_session_ioctl(session, cmd, arg); | 1975 | err = pppol2tp_session_ioctl(session, cmd, arg); |
1906 | 1976 | ||
1977 | end_put_sess: | ||
1978 | sock_put(sk); | ||
1907 | end: | 1979 | end: |
1908 | return err; | 1980 | return err; |
1909 | } | 1981 | } |
@@ -2049,14 +2121,17 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname, | |||
2049 | err = -EBADF; | 2121 | err = -EBADF; |
2050 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); | 2122 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); |
2051 | if (tunnel == NULL) | 2123 | if (tunnel == NULL) |
2052 | goto end; | 2124 | goto end_put_sess; |
2053 | 2125 | ||
2054 | err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val); | 2126 | err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val); |
2127 | sock_put(session->tunnel_sock); | ||
2055 | } else | 2128 | } else |
2056 | err = pppol2tp_session_setsockopt(sk, session, optname, val); | 2129 | err = pppol2tp_session_setsockopt(sk, session, optname, val); |
2057 | 2130 | ||
2058 | err = 0; | 2131 | err = 0; |
2059 | 2132 | ||
2133 | end_put_sess: | ||
2134 | sock_put(sk); | ||
2060 | end: | 2135 | end: |
2061 | return err; | 2136 | return err; |
2062 | } | 2137 | } |
@@ -2171,20 +2246,24 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, | |||
2171 | err = -EBADF; | 2246 | err = -EBADF; |
2172 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); | 2247 | tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); |
2173 | if (tunnel == NULL) | 2248 | if (tunnel == NULL) |
2174 | goto end; | 2249 | goto end_put_sess; |
2175 | 2250 | ||
2176 | err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val); | 2251 | err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val); |
2252 | sock_put(session->tunnel_sock); | ||
2177 | } else | 2253 | } else |
2178 | err = pppol2tp_session_getsockopt(sk, session, optname, &val); | 2254 | err = pppol2tp_session_getsockopt(sk, session, optname, &val); |
2179 | 2255 | ||
2180 | err = -EFAULT; | 2256 | err = -EFAULT; |
2181 | if (put_user(len, (int __user *) optlen)) | 2257 | if (put_user(len, (int __user *) optlen)) |
2182 | goto end; | 2258 | goto end_put_sess; |
2183 | 2259 | ||
2184 | if (copy_to_user((void __user *) optval, &val, len)) | 2260 | if (copy_to_user((void __user *) optval, &val, len)) |
2185 | goto end; | 2261 | goto end_put_sess; |
2186 | 2262 | ||
2187 | err = 0; | 2263 | err = 0; |
2264 | |||
2265 | end_put_sess: | ||
2266 | sock_put(sk); | ||
2188 | end: | 2267 | end: |
2189 | return err; | 2268 | return err; |
2190 | } | 2269 | } |