diff options
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
-rw-r--r-- | net/ipv4/ip_sockglue.c | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 43c05854d75..fc7993e9061 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -57,7 +57,7 @@ | |||
57 | static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) | 57 | static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) |
58 | { | 58 | { |
59 | struct in_pktinfo info; | 59 | struct in_pktinfo info; |
60 | struct rtable *rt = skb->rtable; | 60 | struct rtable *rt = skb_rtable(skb); |
61 | 61 | ||
62 | info.ipi_addr.s_addr = ip_hdr(skb)->daddr; | 62 | info.ipi_addr.s_addr = ip_hdr(skb)->daddr; |
63 | if (rt) { | 63 | if (rt) { |
@@ -157,38 +157,39 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | |||
157 | /* Ordered by supposed usage frequency */ | 157 | /* Ordered by supposed usage frequency */ |
158 | if (flags & 1) | 158 | if (flags & 1) |
159 | ip_cmsg_recv_pktinfo(msg, skb); | 159 | ip_cmsg_recv_pktinfo(msg, skb); |
160 | if ((flags>>=1) == 0) | 160 | if ((flags >>= 1) == 0) |
161 | return; | 161 | return; |
162 | 162 | ||
163 | if (flags & 1) | 163 | if (flags & 1) |
164 | ip_cmsg_recv_ttl(msg, skb); | 164 | ip_cmsg_recv_ttl(msg, skb); |
165 | if ((flags>>=1) == 0) | 165 | if ((flags >>= 1) == 0) |
166 | return; | 166 | return; |
167 | 167 | ||
168 | if (flags & 1) | 168 | if (flags & 1) |
169 | ip_cmsg_recv_tos(msg, skb); | 169 | ip_cmsg_recv_tos(msg, skb); |
170 | if ((flags>>=1) == 0) | 170 | if ((flags >>= 1) == 0) |
171 | return; | 171 | return; |
172 | 172 | ||
173 | if (flags & 1) | 173 | if (flags & 1) |
174 | ip_cmsg_recv_opts(msg, skb); | 174 | ip_cmsg_recv_opts(msg, skb); |
175 | if ((flags>>=1) == 0) | 175 | if ((flags >>= 1) == 0) |
176 | return; | 176 | return; |
177 | 177 | ||
178 | if (flags & 1) | 178 | if (flags & 1) |
179 | ip_cmsg_recv_retopts(msg, skb); | 179 | ip_cmsg_recv_retopts(msg, skb); |
180 | if ((flags>>=1) == 0) | 180 | if ((flags >>= 1) == 0) |
181 | return; | 181 | return; |
182 | 182 | ||
183 | if (flags & 1) | 183 | if (flags & 1) |
184 | ip_cmsg_recv_security(msg, skb); | 184 | ip_cmsg_recv_security(msg, skb); |
185 | 185 | ||
186 | if ((flags>>=1) == 0) | 186 | if ((flags >>= 1) == 0) |
187 | return; | 187 | return; |
188 | if (flags & 1) | 188 | if (flags & 1) |
189 | ip_cmsg_recv_dstaddr(msg, skb); | 189 | ip_cmsg_recv_dstaddr(msg, skb); |
190 | 190 | ||
191 | } | 191 | } |
192 | EXPORT_SYMBOL(ip_cmsg_recv); | ||
192 | 193 | ||
193 | int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) | 194 | int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) |
194 | { | 195 | { |
@@ -203,7 +204,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) | |||
203 | switch (cmsg->cmsg_type) { | 204 | switch (cmsg->cmsg_type) { |
204 | case IP_RETOPTS: | 205 | case IP_RETOPTS: |
205 | err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); | 206 | err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); |
206 | err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); | 207 | err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), |
208 | err < 40 ? err : 40); | ||
207 | if (err) | 209 | if (err) |
208 | return err; | 210 | return err; |
209 | break; | 211 | break; |
@@ -238,7 +240,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) | |||
238 | struct ip_ra_chain *ip_ra_chain; | 240 | struct ip_ra_chain *ip_ra_chain; |
239 | DEFINE_RWLOCK(ip_ra_lock); | 241 | DEFINE_RWLOCK(ip_ra_lock); |
240 | 242 | ||
241 | int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)) | 243 | int ip_ra_control(struct sock *sk, unsigned char on, |
244 | void (*destructor)(struct sock *)) | ||
242 | { | 245 | { |
243 | struct ip_ra_chain *ra, *new_ra, **rap; | 246 | struct ip_ra_chain *ra, *new_ra, **rap; |
244 | 247 | ||
@@ -248,7 +251,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s | |||
248 | new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; | 251 | new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; |
249 | 252 | ||
250 | write_lock_bh(&ip_ra_lock); | 253 | write_lock_bh(&ip_ra_lock); |
251 | for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { | 254 | for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { |
252 | if (ra->sk == sk) { | 255 | if (ra->sk == sk) { |
253 | if (on) { | 256 | if (on) { |
254 | write_unlock_bh(&ip_ra_lock); | 257 | write_unlock_bh(&ip_ra_lock); |
@@ -416,7 +419,8 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
416 | /* Reset and regenerate socket error */ | 419 | /* Reset and regenerate socket error */ |
417 | spin_lock_bh(&sk->sk_error_queue.lock); | 420 | spin_lock_bh(&sk->sk_error_queue.lock); |
418 | sk->sk_err = 0; | 421 | sk->sk_err = 0; |
419 | if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { | 422 | skb2 = skb_peek(&sk->sk_error_queue); |
423 | if (skb2 != NULL) { | ||
420 | sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; | 424 | sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; |
421 | spin_unlock_bh(&sk->sk_error_queue.lock); | 425 | spin_unlock_bh(&sk->sk_error_queue.lock); |
422 | sk->sk_error_report(sk); | 426 | sk->sk_error_report(sk); |
@@ -431,8 +435,8 @@ out: | |||
431 | 435 | ||
432 | 436 | ||
433 | /* | 437 | /* |
434 | * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on | 438 | * Socket option code for IP. This is the end of the line after any |
435 | * an IP socket. | 439 | * TCP,UDP etc options on an IP socket. |
436 | */ | 440 | */ |
437 | 441 | ||
438 | static int do_ip_setsockopt(struct sock *sk, int level, | 442 | static int do_ip_setsockopt(struct sock *sk, int level, |
@@ -449,6 +453,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
449 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | | 453 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | |
450 | (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) || | 454 | (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) || |
451 | optname == IP_MULTICAST_TTL || | 455 | optname == IP_MULTICAST_TTL || |
456 | optname == IP_MULTICAST_ALL || | ||
452 | optname == IP_MULTICAST_LOOP || | 457 | optname == IP_MULTICAST_LOOP || |
453 | optname == IP_RECVORIGDSTADDR) { | 458 | optname == IP_RECVORIGDSTADDR) { |
454 | if (optlen >= sizeof(int)) { | 459 | if (optlen >= sizeof(int)) { |
@@ -474,7 +479,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
474 | switch (optname) { | 479 | switch (optname) { |
475 | case IP_OPTIONS: | 480 | case IP_OPTIONS: |
476 | { | 481 | { |
477 | struct ip_options * opt = NULL; | 482 | struct ip_options *opt = NULL; |
478 | if (optlen > 40 || optlen < 0) | 483 | if (optlen > 40 || optlen < 0) |
479 | goto e_inval; | 484 | goto e_inval; |
480 | err = ip_options_get_from_user(sock_net(sk), &opt, | 485 | err = ip_options_get_from_user(sock_net(sk), &opt, |
@@ -556,9 +561,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
556 | } | 561 | } |
557 | break; | 562 | break; |
558 | case IP_TTL: | 563 | case IP_TTL: |
559 | if (optlen<1) | 564 | if (optlen < 1) |
560 | goto e_inval; | 565 | goto e_inval; |
561 | if (val != -1 && (val < 1 || val>255)) | 566 | if (val != -1 && (val < 0 || val > 255)) |
562 | goto e_inval; | 567 | goto e_inval; |
563 | inet->uc_ttl = val; | 568 | inet->uc_ttl = val; |
564 | break; | 569 | break; |
@@ -570,7 +575,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
570 | inet->hdrincl = val ? 1 : 0; | 575 | inet->hdrincl = val ? 1 : 0; |
571 | break; | 576 | break; |
572 | case IP_MTU_DISCOVER: | 577 | case IP_MTU_DISCOVER: |
573 | if (val<0 || val>3) | 578 | if (val < 0 || val > 3) |
574 | goto e_inval; | 579 | goto e_inval; |
575 | inet->pmtudisc = val; | 580 | inet->pmtudisc = val; |
576 | break; | 581 | break; |
@@ -582,7 +587,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
582 | case IP_MULTICAST_TTL: | 587 | case IP_MULTICAST_TTL: |
583 | if (sk->sk_type == SOCK_STREAM) | 588 | if (sk->sk_type == SOCK_STREAM) |
584 | goto e_inval; | 589 | goto e_inval; |
585 | if (optlen<1) | 590 | if (optlen < 1) |
586 | goto e_inval; | 591 | goto e_inval; |
587 | if (val == -1) | 592 | if (val == -1) |
588 | val = 1; | 593 | val = 1; |
@@ -591,7 +596,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
591 | inet->mc_ttl = val; | 596 | inet->mc_ttl = val; |
592 | break; | 597 | break; |
593 | case IP_MULTICAST_LOOP: | 598 | case IP_MULTICAST_LOOP: |
594 | if (optlen<1) | 599 | if (optlen < 1) |
595 | goto e_inval; | 600 | goto e_inval; |
596 | inet->mc_loop = !!val; | 601 | inet->mc_loop = !!val; |
597 | break; | 602 | break; |
@@ -613,7 +618,8 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
613 | } else { | 618 | } else { |
614 | memset(&mreq, 0, sizeof(mreq)); | 619 | memset(&mreq, 0, sizeof(mreq)); |
615 | if (optlen >= sizeof(struct in_addr) && | 620 | if (optlen >= sizeof(struct in_addr) && |
616 | copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr))) | 621 | copy_from_user(&mreq.imr_address, optval, |
622 | sizeof(struct in_addr))) | ||
617 | break; | 623 | break; |
618 | } | 624 | } |
619 | 625 | ||
@@ -677,7 +683,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
677 | } | 683 | } |
678 | case IP_MSFILTER: | 684 | case IP_MSFILTER: |
679 | { | 685 | { |
680 | extern int sysctl_igmp_max_msf; | ||
681 | struct ip_msfilter *msf; | 686 | struct ip_msfilter *msf; |
682 | 687 | ||
683 | if (optlen < IP_MSFILTER_SIZE(0)) | 688 | if (optlen < IP_MSFILTER_SIZE(0)) |
@@ -831,7 +836,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
831 | } | 836 | } |
832 | case MCAST_MSFILTER: | 837 | case MCAST_MSFILTER: |
833 | { | 838 | { |
834 | extern int sysctl_igmp_max_msf; | ||
835 | struct sockaddr_in *psin; | 839 | struct sockaddr_in *psin; |
836 | struct ip_msfilter *msf = NULL; | 840 | struct ip_msfilter *msf = NULL; |
837 | struct group_filter *gsf = NULL; | 841 | struct group_filter *gsf = NULL; |
@@ -849,9 +853,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
849 | break; | 853 | break; |
850 | } | 854 | } |
851 | err = -EFAULT; | 855 | err = -EFAULT; |
852 | if (copy_from_user(gsf, optval, optlen)) { | 856 | if (copy_from_user(gsf, optval, optlen)) |
853 | goto mc_msf_out; | 857 | goto mc_msf_out; |
854 | } | 858 | |
855 | /* numsrc >= (4G-140)/128 overflow in 32 bits */ | 859 | /* numsrc >= (4G-140)/128 overflow in 32 bits */ |
856 | if (gsf->gf_numsrc >= 0x1ffffff || | 860 | if (gsf->gf_numsrc >= 0x1ffffff || |
857 | gsf->gf_numsrc > sysctl_igmp_max_msf) { | 861 | gsf->gf_numsrc > sysctl_igmp_max_msf) { |
@@ -879,7 +883,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
879 | msf->imsf_fmode = gsf->gf_fmode; | 883 | msf->imsf_fmode = gsf->gf_fmode; |
880 | msf->imsf_numsrc = gsf->gf_numsrc; | 884 | msf->imsf_numsrc = gsf->gf_numsrc; |
881 | err = -EADDRNOTAVAIL; | 885 | err = -EADDRNOTAVAIL; |
882 | for (i=0; i<gsf->gf_numsrc; ++i) { | 886 | for (i = 0; i < gsf->gf_numsrc; ++i) { |
883 | psin = (struct sockaddr_in *)&gsf->gf_slist[i]; | 887 | psin = (struct sockaddr_in *)&gsf->gf_slist[i]; |
884 | 888 | ||
885 | if (psin->sin_family != AF_INET) | 889 | if (psin->sin_family != AF_INET) |
@@ -890,17 +894,24 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
890 | gsf = NULL; | 894 | gsf = NULL; |
891 | 895 | ||
892 | err = ip_mc_msfilter(sk, msf, ifindex); | 896 | err = ip_mc_msfilter(sk, msf, ifindex); |
893 | mc_msf_out: | 897 | mc_msf_out: |
894 | kfree(msf); | 898 | kfree(msf); |
895 | kfree(gsf); | 899 | kfree(gsf); |
896 | break; | 900 | break; |
897 | } | 901 | } |
902 | case IP_MULTICAST_ALL: | ||
903 | if (optlen < 1) | ||
904 | goto e_inval; | ||
905 | if (val != 0 && val != 1) | ||
906 | goto e_inval; | ||
907 | inet->mc_all = val; | ||
908 | break; | ||
898 | case IP_ROUTER_ALERT: | 909 | case IP_ROUTER_ALERT: |
899 | err = ip_ra_control(sk, val ? 1 : 0, NULL); | 910 | err = ip_ra_control(sk, val ? 1 : 0, NULL); |
900 | break; | 911 | break; |
901 | 912 | ||
902 | case IP_FREEBIND: | 913 | case IP_FREEBIND: |
903 | if (optlen<1) | 914 | if (optlen < 1) |
904 | goto e_inval; | 915 | goto e_inval; |
905 | inet->freebind = !!val; | 916 | inet->freebind = !!val; |
906 | break; | 917 | break; |
@@ -957,6 +968,7 @@ int ip_setsockopt(struct sock *sk, int level, | |||
957 | #endif | 968 | #endif |
958 | return err; | 969 | return err; |
959 | } | 970 | } |
971 | EXPORT_SYMBOL(ip_setsockopt); | ||
960 | 972 | ||
961 | #ifdef CONFIG_COMPAT | 973 | #ifdef CONFIG_COMPAT |
962 | int compat_ip_setsockopt(struct sock *sk, int level, int optname, | 974 | int compat_ip_setsockopt(struct sock *sk, int level, int optname, |
@@ -986,13 +998,12 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, | |||
986 | #endif | 998 | #endif |
987 | return err; | 999 | return err; |
988 | } | 1000 | } |
989 | |||
990 | EXPORT_SYMBOL(compat_ip_setsockopt); | 1001 | EXPORT_SYMBOL(compat_ip_setsockopt); |
991 | #endif | 1002 | #endif |
992 | 1003 | ||
993 | /* | 1004 | /* |
994 | * Get the options. Note for future reference. The GET of IP options gets the | 1005 | * Get the options. Note for future reference. The GET of IP options gets |
995 | * _received_ ones. The set sets the _sent_ ones. | 1006 | * the _received_ ones. The set sets the _sent_ ones. |
996 | */ | 1007 | */ |
997 | 1008 | ||
998 | static int do_ip_getsockopt(struct sock *sk, int level, int optname, | 1009 | static int do_ip_getsockopt(struct sock *sk, int level, int optname, |
@@ -1143,10 +1154,14 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, | |||
1143 | return -EFAULT; | 1154 | return -EFAULT; |
1144 | } | 1155 | } |
1145 | err = ip_mc_gsfget(sk, &gsf, | 1156 | err = ip_mc_gsfget(sk, &gsf, |
1146 | (struct group_filter __user *)optval, optlen); | 1157 | (struct group_filter __user *)optval, |
1158 | optlen); | ||
1147 | release_sock(sk); | 1159 | release_sock(sk); |
1148 | return err; | 1160 | return err; |
1149 | } | 1161 | } |
1162 | case IP_MULTICAST_ALL: | ||
1163 | val = inet->mc_all; | ||
1164 | break; | ||
1150 | case IP_PKTOPTIONS: | 1165 | case IP_PKTOPTIONS: |
1151 | { | 1166 | { |
1152 | struct msghdr msg; | 1167 | struct msghdr msg; |
@@ -1187,7 +1202,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, | |||
1187 | } | 1202 | } |
1188 | release_sock(sk); | 1203 | release_sock(sk); |
1189 | 1204 | ||
1190 | if (len < sizeof(int) && len > 0 && val>=0 && val<=255) { | 1205 | if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) { |
1191 | unsigned char ucval = (unsigned char)val; | 1206 | unsigned char ucval = (unsigned char)val; |
1192 | len = 1; | 1207 | len = 1; |
1193 | if (put_user(len, optlen)) | 1208 | if (put_user(len, optlen)) |
@@ -1230,6 +1245,7 @@ int ip_getsockopt(struct sock *sk, int level, | |||
1230 | #endif | 1245 | #endif |
1231 | return err; | 1246 | return err; |
1232 | } | 1247 | } |
1248 | EXPORT_SYMBOL(ip_getsockopt); | ||
1233 | 1249 | ||
1234 | #ifdef CONFIG_COMPAT | 1250 | #ifdef CONFIG_COMPAT |
1235 | int compat_ip_getsockopt(struct sock *sk, int level, int optname, | 1251 | int compat_ip_getsockopt(struct sock *sk, int level, int optname, |
@@ -1262,11 +1278,5 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname, | |||
1262 | #endif | 1278 | #endif |
1263 | return err; | 1279 | return err; |
1264 | } | 1280 | } |
1265 | |||
1266 | EXPORT_SYMBOL(compat_ip_getsockopt); | 1281 | EXPORT_SYMBOL(compat_ip_getsockopt); |
1267 | #endif | 1282 | #endif |
1268 | |||
1269 | EXPORT_SYMBOL(ip_cmsg_recv); | ||
1270 | |||
1271 | EXPORT_SYMBOL(ip_getsockopt); | ||
1272 | EXPORT_SYMBOL(ip_setsockopt); | ||