aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/udp.h5
-rw-r--r--net/ipv4/udp.c30
-rw-r--r--net/ipv6/udp.c118
3 files changed, 32 insertions, 121 deletions
diff --git a/include/net/udp.h b/include/net/udp.h
index eac69ff0582c..1548d68d45da 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -134,6 +134,11 @@ extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
134extern int udp_disconnect(struct sock *sk, int flags); 134extern int udp_disconnect(struct sock *sk, int flags);
135extern unsigned int udp_poll(struct file *file, struct socket *sock, 135extern unsigned int udp_poll(struct file *file, struct socket *sock,
136 poll_table *wait); 136 poll_table *wait);
137extern int udp_lib_getsockopt(struct sock *sk, int level, int optname,
138 char __user *optval, int __user *optlen);
139extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
140 char __user *optval, int optlen,
141 int (*push_pending_frames)(struct sock *));
137 142
138DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); 143DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
139/* 144/*
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1807a30694d9..035915fc9ed3 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -448,8 +448,9 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
448/* 448/*
449 * Push out all pending data as one UDP datagram. Socket is locked. 449 * Push out all pending data as one UDP datagram. Socket is locked.
450 */ 450 */
451static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) 451static int udp_push_pending_frames(struct sock *sk)
452{ 452{
453 struct udp_sock *up = udp_sk(sk);
453 struct inet_sock *inet = inet_sk(sk); 454 struct inet_sock *inet = inet_sk(sk);
454 struct flowi *fl = &inet->cork.fl; 455 struct flowi *fl = &inet->cork.fl;
455 struct sk_buff *skb; 456 struct sk_buff *skb;
@@ -673,7 +674,7 @@ do_append_data:
673 if (err) 674 if (err)
674 udp_flush_pending_frames(sk); 675 udp_flush_pending_frames(sk);
675 else if (!corkreq) 676 else if (!corkreq)
676 err = udp_push_pending_frames(sk, up); 677 err = udp_push_pending_frames(sk);
677 else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) 678 else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
678 up->pending = 0; 679 up->pending = 0;
679 release_sock(sk); 680 release_sock(sk);
@@ -746,7 +747,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
746 747
747 up->len += size; 748 up->len += size;
748 if (!(up->corkflag || (flags&MSG_MORE))) 749 if (!(up->corkflag || (flags&MSG_MORE)))
749 ret = udp_push_pending_frames(sk, up); 750 ret = udp_push_pending_frames(sk);
750 if (!ret) 751 if (!ret)
751 ret = size; 752 ret = size;
752out: 753out:
@@ -1299,8 +1300,9 @@ int udp_destroy_sock(struct sock *sk)
1299/* 1300/*
1300 * Socket option code for UDP 1301 * Socket option code for UDP
1301 */ 1302 */
1302static int do_udp_setsockopt(struct sock *sk, int level, int optname, 1303int udp_lib_setsockopt(struct sock *sk, int level, int optname,
1303 char __user *optval, int optlen) 1304 char __user *optval, int optlen,
1305 int (*push_pending_frames)(struct sock *))
1304{ 1306{
1305 struct udp_sock *up = udp_sk(sk); 1307 struct udp_sock *up = udp_sk(sk);
1306 int val; 1308 int val;
@@ -1319,7 +1321,7 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname,
1319 } else { 1321 } else {
1320 up->corkflag = 0; 1322 up->corkflag = 0;
1321 lock_sock(sk); 1323 lock_sock(sk);
1322 udp_push_pending_frames(sk, up); 1324 (*push_pending_frames)(sk);
1323 release_sock(sk); 1325 release_sock(sk);
1324 } 1326 }
1325 break; 1327 break;
@@ -1375,7 +1377,8 @@ int udp_setsockopt(struct sock *sk, int level, int optname,
1375 char __user *optval, int optlen) 1377 char __user *optval, int optlen)
1376{ 1378{
1377 if (level == SOL_UDP || level == SOL_UDPLITE) 1379 if (level == SOL_UDP || level == SOL_UDPLITE)
1378 return do_udp_setsockopt(sk, level, optname, optval, optlen); 1380 return udp_lib_setsockopt(sk, level, optname, optval, optlen,
1381 udp_push_pending_frames);
1379 return ip_setsockopt(sk, level, optname, optval, optlen); 1382 return ip_setsockopt(sk, level, optname, optval, optlen);
1380} 1383}
1381 1384
@@ -1384,13 +1387,14 @@ int compat_udp_setsockopt(struct sock *sk, int level, int optname,
1384 char __user *optval, int optlen) 1387 char __user *optval, int optlen)
1385{ 1388{
1386 if (level == SOL_UDP || level == SOL_UDPLITE) 1389 if (level == SOL_UDP || level == SOL_UDPLITE)
1387 return do_udp_setsockopt(sk, level, optname, optval, optlen); 1390 return udp_lib_setsockopt(sk, level, optname, optval, optlen,
1391 udp_push_pending_frames);
1388 return compat_ip_setsockopt(sk, level, optname, optval, optlen); 1392 return compat_ip_setsockopt(sk, level, optname, optval, optlen);
1389} 1393}
1390#endif 1394#endif
1391 1395
1392static int do_udp_getsockopt(struct sock *sk, int level, int optname, 1396int udp_lib_getsockopt(struct sock *sk, int level, int optname,
1393 char __user *optval, int __user *optlen) 1397 char __user *optval, int __user *optlen)
1394{ 1398{
1395 struct udp_sock *up = udp_sk(sk); 1399 struct udp_sock *up = udp_sk(sk);
1396 int val, len; 1400 int val, len;
@@ -1437,7 +1441,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname,
1437 char __user *optval, int __user *optlen) 1441 char __user *optval, int __user *optlen)
1438{ 1442{
1439 if (level == SOL_UDP || level == SOL_UDPLITE) 1443 if (level == SOL_UDP || level == SOL_UDPLITE)
1440 return do_udp_getsockopt(sk, level, optname, optval, optlen); 1444 return udp_lib_getsockopt(sk, level, optname, optval, optlen);
1441 return ip_getsockopt(sk, level, optname, optval, optlen); 1445 return ip_getsockopt(sk, level, optname, optval, optlen);
1442} 1446}
1443 1447
@@ -1446,7 +1450,7 @@ int compat_udp_getsockopt(struct sock *sk, int level, int optname,
1446 char __user *optval, int __user *optlen) 1450 char __user *optval, int __user *optlen)
1447{ 1451{
1448 if (level == SOL_UDP || level == SOL_UDPLITE) 1452 if (level == SOL_UDP || level == SOL_UDPLITE)
1449 return do_udp_getsockopt(sk, level, optname, optval, optlen); 1453 return udp_lib_getsockopt(sk, level, optname, optval, optlen);
1450 return compat_ip_getsockopt(sk, level, optname, optval, optlen); 1454 return compat_ip_getsockopt(sk, level, optname, optval, optlen);
1451} 1455}
1452#endif 1456#endif
@@ -1716,6 +1720,8 @@ EXPORT_SYMBOL(udp_ioctl);
1716EXPORT_SYMBOL(udp_get_port); 1720EXPORT_SYMBOL(udp_get_port);
1717EXPORT_SYMBOL(udp_prot); 1721EXPORT_SYMBOL(udp_prot);
1718EXPORT_SYMBOL(udp_sendmsg); 1722EXPORT_SYMBOL(udp_sendmsg);
1723EXPORT_SYMBOL(udp_lib_getsockopt);
1724EXPORT_SYMBOL(udp_lib_setsockopt);
1719EXPORT_SYMBOL(udp_poll); 1725EXPORT_SYMBOL(udp_poll);
1720 1726
1721#ifdef CONFIG_PROC_FS 1727#ifdef CONFIG_PROC_FS
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index b3ea8af50a9b..f52a5c3cc0a3 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -505,10 +505,11 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
505 * Sending 505 * Sending
506 */ 506 */
507 507
508static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) 508static int udp_v6_push_pending_frames(struct sock *sk)
509{ 509{
510 struct sk_buff *skb; 510 struct sk_buff *skb;
511 struct udphdr *uh; 511 struct udphdr *uh;
512 struct udp_sock *up = udp_sk(sk);
512 struct inet_sock *inet = inet_sk(sk); 513 struct inet_sock *inet = inet_sk(sk);
513 struct flowi *fl = &inet->cork.fl; 514 struct flowi *fl = &inet->cork.fl;
514 int err = 0; 515 int err = 0;
@@ -782,7 +783,7 @@ do_append_data:
782 if (err) 783 if (err)
783 udp_v6_flush_pending_frames(sk); 784 udp_v6_flush_pending_frames(sk);
784 else if (!corkreq) 785 else if (!corkreq)
785 err = udp_v6_push_pending_frames(sk, up); 786 err = udp_v6_push_pending_frames(sk);
786 else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) 787 else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
787 up->pending = 0; 788 up->pending = 0;
788 789
@@ -844,72 +845,12 @@ int udpv6_destroy_sock(struct sock *sk)
844/* 845/*
845 * Socket option code for UDP 846 * Socket option code for UDP
846 */ 847 */
847static int do_udpv6_setsockopt(struct sock *sk, int level, int optname,
848 char __user *optval, int optlen)
849{
850 struct udp_sock *up = udp_sk(sk);
851 int val;
852 int err = 0;
853
854 if(optlen<sizeof(int))
855 return -EINVAL;
856
857 if (get_user(val, (int __user *)optval))
858 return -EFAULT;
859
860 switch(optname) {
861 case UDP_CORK:
862 if (val != 0) {
863 up->corkflag = 1;
864 } else {
865 up->corkflag = 0;
866 lock_sock(sk);
867 udp_v6_push_pending_frames(sk, up);
868 release_sock(sk);
869 }
870 break;
871 case UDP_ENCAP:
872 switch (val) {
873 case 0:
874 up->encap_type = val;
875 break;
876 default:
877 err = -ENOPROTOOPT;
878 break;
879 }
880 break;
881
882 case UDPLITE_SEND_CSCOV:
883 if (!up->pcflag) /* Disable the option on UDP sockets */
884 return -ENOPROTOOPT;
885 if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
886 val = 8;
887 up->pcslen = val;
888 up->pcflag |= UDPLITE_SEND_CC;
889 break;
890
891 case UDPLITE_RECV_CSCOV:
892 if (!up->pcflag) /* Disable the option on UDP sockets */
893 return -ENOPROTOOPT;
894 if (val != 0 && val < 8) /* Avoid silly minimal values. */
895 val = 8;
896 up->pcrlen = val;
897 up->pcflag |= UDPLITE_RECV_CC;
898 break;
899
900 default:
901 err = -ENOPROTOOPT;
902 break;
903 };
904
905 return err;
906}
907
908int udpv6_setsockopt(struct sock *sk, int level, int optname, 848int udpv6_setsockopt(struct sock *sk, int level, int optname,
909 char __user *optval, int optlen) 849 char __user *optval, int optlen)
910{ 850{
911 if (level == SOL_UDP || level == SOL_UDPLITE) 851 if (level == SOL_UDP || level == SOL_UDPLITE)
912 return do_udpv6_setsockopt(sk, level, optname, optval, optlen); 852 return udp_lib_setsockopt(sk, level, optname, optval, optlen,
853 udp_v6_push_pending_frames);
913 return ipv6_setsockopt(sk, level, optname, optval, optlen); 854 return ipv6_setsockopt(sk, level, optname, optval, optlen);
914} 855}
915 856
@@ -918,58 +859,17 @@ int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
918 char __user *optval, int optlen) 859 char __user *optval, int optlen)
919{ 860{
920 if (level == SOL_UDP || level == SOL_UDPLITE) 861 if (level == SOL_UDP || level == SOL_UDPLITE)
921 return do_udpv6_setsockopt(sk, level, optname, optval, optlen); 862 return udp_lib_setsockopt(sk, level, optname, optval, optlen,
863 udp_v6_push_pending_frames);
922 return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); 864 return compat_ipv6_setsockopt(sk, level, optname, optval, optlen);
923} 865}
924#endif 866#endif
925 867
926static int do_udpv6_getsockopt(struct sock *sk, int level, int optname,
927 char __user *optval, int __user *optlen)
928{
929 struct udp_sock *up = udp_sk(sk);
930 int val, len;
931
932 if(get_user(len,optlen))
933 return -EFAULT;
934
935 len = min_t(unsigned int, len, sizeof(int));
936
937 if(len < 0)
938 return -EINVAL;
939
940 switch(optname) {
941 case UDP_CORK:
942 val = up->corkflag;
943 break;
944
945 case UDP_ENCAP:
946 val = up->encap_type;
947 break;
948
949 case UDPLITE_SEND_CSCOV:
950 val = up->pcslen;
951 break;
952
953 case UDPLITE_RECV_CSCOV:
954 val = up->pcrlen;
955 break;
956
957 default:
958 return -ENOPROTOOPT;
959 };
960
961 if(put_user(len, optlen))
962 return -EFAULT;
963 if(copy_to_user(optval, &val,len))
964 return -EFAULT;
965 return 0;
966}
967
968int udpv6_getsockopt(struct sock *sk, int level, int optname, 868int udpv6_getsockopt(struct sock *sk, int level, int optname,
969 char __user *optval, int __user *optlen) 869 char __user *optval, int __user *optlen)
970{ 870{
971 if (level == SOL_UDP || level == SOL_UDPLITE) 871 if (level == SOL_UDP || level == SOL_UDPLITE)
972 return do_udpv6_getsockopt(sk, level, optname, optval, optlen); 872 return udp_lib_getsockopt(sk, level, optname, optval, optlen);
973 return ipv6_getsockopt(sk, level, optname, optval, optlen); 873 return ipv6_getsockopt(sk, level, optname, optval, optlen);
974} 874}
975 875
@@ -978,7 +878,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
978 char __user *optval, int __user *optlen) 878 char __user *optval, int __user *optlen)
979{ 879{
980 if (level == SOL_UDP || level == SOL_UDPLITE) 880 if (level == SOL_UDP || level == SOL_UDPLITE)
981 return do_udpv6_getsockopt(sk, level, optname, optval, optlen); 881 return udp_lib_getsockopt(sk, level, optname, optval, optlen);
982 return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); 882 return compat_ipv6_getsockopt(sk, level, optname, optval, optlen);
983} 883}
984#endif 884#endif