diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/in.h | 1 | ||||
-rw-r--r-- | include/linux/socket.h | 1 | ||||
-rw-r--r-- | include/linux/udp.h | 12 | ||||
-rw-r--r-- | include/net/ipv6.h | 12 | ||||
-rw-r--r-- | include/net/transp_v6.h | 2 | ||||
-rw-r--r-- | include/net/udp.h | 91 | ||||
-rw-r--r-- | include/net/udplite.h | 149 | ||||
-rw-r--r-- | include/net/xfrm.h | 2 |
8 files changed, 263 insertions, 7 deletions
diff --git a/include/linux/in.h b/include/linux/in.h index 2619859f6e1b..1912e7c0bc26 100644 --- a/include/linux/in.h +++ b/include/linux/in.h | |||
@@ -45,6 +45,7 @@ enum { | |||
45 | 45 | ||
46 | IPPROTO_COMP = 108, /* Compression Header protocol */ | 46 | IPPROTO_COMP = 108, /* Compression Header protocol */ |
47 | IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ | 47 | IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ |
48 | IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ | ||
48 | 49 | ||
49 | IPPROTO_RAW = 255, /* Raw IP packets */ | 50 | IPPROTO_RAW = 255, /* Raw IP packets */ |
50 | IPPROTO_MAX | 51 | IPPROTO_MAX |
diff --git a/include/linux/socket.h b/include/linux/socket.h index 361409094649..592b66679823 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
@@ -264,6 +264,7 @@ struct ucred { | |||
264 | #define SOL_IPV6 41 | 264 | #define SOL_IPV6 41 |
265 | #define SOL_ICMPV6 58 | 265 | #define SOL_ICMPV6 58 |
266 | #define SOL_SCTP 132 | 266 | #define SOL_SCTP 132 |
267 | #define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ | ||
267 | #define SOL_RAW 255 | 268 | #define SOL_RAW 255 |
268 | #define SOL_IPX 256 | 269 | #define SOL_IPX 256 |
269 | #define SOL_AX25 257 | 270 | #define SOL_AX25 257 |
diff --git a/include/linux/udp.h b/include/linux/udp.h index 014b41d1e308..564f3b050105 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h | |||
@@ -38,6 +38,7 @@ struct udphdr { | |||
38 | #include <linux/types.h> | 38 | #include <linux/types.h> |
39 | 39 | ||
40 | #include <net/inet_sock.h> | 40 | #include <net/inet_sock.h> |
41 | #define UDP_HTABLE_SIZE 128 | ||
41 | 42 | ||
42 | struct udp_sock { | 43 | struct udp_sock { |
43 | /* inet_sock has to be the first member */ | 44 | /* inet_sock has to be the first member */ |
@@ -50,12 +51,23 @@ struct udp_sock { | |||
50 | * when the socket is uncorked. | 51 | * when the socket is uncorked. |
51 | */ | 52 | */ |
52 | __u16 len; /* total length of pending frames */ | 53 | __u16 len; /* total length of pending frames */ |
54 | /* | ||
55 | * Fields specific to UDP-Lite. | ||
56 | */ | ||
57 | __u16 pcslen; | ||
58 | __u16 pcrlen; | ||
59 | /* indicator bits used by pcflag: */ | ||
60 | #define UDPLITE_BIT 0x1 /* set by udplite proto init function */ | ||
61 | #define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ | ||
62 | #define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ | ||
63 | __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ | ||
53 | }; | 64 | }; |
54 | 65 | ||
55 | static inline struct udp_sock *udp_sk(const struct sock *sk) | 66 | static inline struct udp_sock *udp_sk(const struct sock *sk) |
56 | { | 67 | { |
57 | return (struct udp_sock *)sk; | 68 | return (struct udp_sock *)sk; |
58 | } | 69 | } |
70 | #define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) | ||
59 | 71 | ||
60 | #endif | 72 | #endif |
61 | 73 | ||
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 3c266ad99a02..9390649bbfec 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -158,9 +158,13 @@ DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); | |||
158 | SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \ | 158 | SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \ |
159 | }) | 159 | }) |
160 | DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); | 160 | DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); |
161 | #define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field) | 161 | DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); |
162 | #define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field) | 162 | #define UDP6_INC_STATS_BH(field, is_udplite) do { \ |
163 | #define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field) | 163 | if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field); \ |
164 | else SNMP_INC_STATS_BH(udp_stats_in6, field); } while(0) | ||
165 | #define UDP6_INC_STATS_USER(field, is_udplite) do { \ | ||
166 | if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field); \ | ||
167 | else SNMP_INC_STATS_USER(udp_stats_in6, field); } while(0) | ||
164 | 168 | ||
165 | int snmp6_register_dev(struct inet6_dev *idev); | 169 | int snmp6_register_dev(struct inet6_dev *idev); |
166 | int snmp6_unregister_dev(struct inet6_dev *idev); | 170 | int snmp6_unregister_dev(struct inet6_dev *idev); |
@@ -604,6 +608,8 @@ extern int tcp6_proc_init(void); | |||
604 | extern void tcp6_proc_exit(void); | 608 | extern void tcp6_proc_exit(void); |
605 | extern int udp6_proc_init(void); | 609 | extern int udp6_proc_init(void); |
606 | extern void udp6_proc_exit(void); | 610 | extern void udp6_proc_exit(void); |
611 | extern int udplite6_proc_init(void); | ||
612 | extern void udplite6_proc_exit(void); | ||
607 | extern int ipv6_misc_proc_init(void); | 613 | extern int ipv6_misc_proc_init(void); |
608 | extern void ipv6_misc_proc_exit(void); | 614 | extern void ipv6_misc_proc_exit(void); |
609 | 615 | ||
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 61f724c1036f..409da3a9a455 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | extern struct proto rawv6_prot; | 12 | extern struct proto rawv6_prot; |
13 | extern struct proto udpv6_prot; | 13 | extern struct proto udpv6_prot; |
14 | extern struct proto udplitev6_prot; | ||
14 | extern struct proto tcpv6_prot; | 15 | extern struct proto tcpv6_prot; |
15 | 16 | ||
16 | struct flowi; | 17 | struct flowi; |
@@ -24,6 +25,7 @@ extern void ipv6_destopt_init(void); | |||
24 | /* transport protocols */ | 25 | /* transport protocols */ |
25 | extern void rawv6_init(void); | 26 | extern void rawv6_init(void); |
26 | extern void udpv6_init(void); | 27 | extern void udpv6_init(void); |
28 | extern void udplitev6_init(void); | ||
27 | extern void tcpv6_init(void); | 29 | extern void tcpv6_init(void); |
28 | 30 | ||
29 | extern int udpv6_connect(struct sock *sk, | 31 | extern int udpv6_connect(struct sock *sk, |
diff --git a/include/net/udp.h b/include/net/udp.h index db0c05f67546..4f0626735ed3 100644 --- a/include/net/udp.h +++ b/include/net/udp.h | |||
@@ -26,9 +26,28 @@ | |||
26 | #include <net/inet_sock.h> | 26 | #include <net/inet_sock.h> |
27 | #include <net/sock.h> | 27 | #include <net/sock.h> |
28 | #include <net/snmp.h> | 28 | #include <net/snmp.h> |
29 | #include <net/ip.h> | ||
30 | #include <linux/ipv6.h> | ||
29 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
30 | 32 | ||
31 | #define UDP_HTABLE_SIZE 128 | 33 | /** |
34 | * struct udp_skb_cb - UDP(-Lite) private variables | ||
35 | * | ||
36 | * @header: private variables used by IPv4/IPv6 | ||
37 | * @cscov: checksum coverage length (UDP-Lite only) | ||
38 | * @partial_cov: if set indicates partial csum coverage | ||
39 | */ | ||
40 | struct udp_skb_cb { | ||
41 | union { | ||
42 | struct inet_skb_parm h4; | ||
43 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
44 | struct inet6_skb_parm h6; | ||
45 | #endif | ||
46 | } header; | ||
47 | __u16 cscov; | ||
48 | __u8 partial_cov; | ||
49 | }; | ||
50 | #define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) | ||
32 | 51 | ||
33 | extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; | 52 | extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; |
34 | extern rwlock_t udp_hash_lock; | 53 | extern rwlock_t udp_hash_lock; |
@@ -47,6 +66,62 @@ extern struct proto udp_prot; | |||
47 | 66 | ||
48 | struct sk_buff; | 67 | struct sk_buff; |
49 | 68 | ||
69 | /* | ||
70 | * Generic checksumming routines for UDP(-Lite) v4 and v6 | ||
71 | */ | ||
72 | static inline u16 __udp_lib_checksum_complete(struct sk_buff *skb) | ||
73 | { | ||
74 | if (! UDP_SKB_CB(skb)->partial_cov) | ||
75 | return __skb_checksum_complete(skb); | ||
76 | return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov, | ||
77 | skb->csum)); | ||
78 | } | ||
79 | |||
80 | static __inline__ int udp_lib_checksum_complete(struct sk_buff *skb) | ||
81 | { | ||
82 | return skb->ip_summed != CHECKSUM_UNNECESSARY && | ||
83 | __udp_lib_checksum_complete(skb); | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * udp_csum_outgoing - compute UDPv4/v6 checksum over fragments | ||
88 | * @sk: socket we are writing to | ||
89 | * @skb: sk_buff containing the filled-in UDP header | ||
90 | * (checksum field must be zeroed out) | ||
91 | */ | ||
92 | static inline u32 udp_csum_outgoing(struct sock *sk, struct sk_buff *skb) | ||
93 | { | ||
94 | u32 csum = csum_partial(skb->h.raw, sizeof(struct udphdr), 0); | ||
95 | |||
96 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
97 | csum = csum_add(csum, skb->csum); | ||
98 | } | ||
99 | return csum; | ||
100 | } | ||
101 | |||
102 | /* hash routines shared between UDPv4/6 and UDP-Litev4/6 */ | ||
103 | static inline void udp_lib_hash(struct sock *sk) | ||
104 | { | ||
105 | BUG(); | ||
106 | } | ||
107 | |||
108 | static inline void udp_lib_unhash(struct sock *sk) | ||
109 | { | ||
110 | write_lock_bh(&udp_hash_lock); | ||
111 | if (sk_del_node_init(sk)) { | ||
112 | inet_sk(sk)->num = 0; | ||
113 | sock_prot_dec_use(sk->sk_prot); | ||
114 | } | ||
115 | write_unlock_bh(&udp_hash_lock); | ||
116 | } | ||
117 | |||
118 | static inline void udp_lib_close(struct sock *sk, long timeout) | ||
119 | { | ||
120 | sk_common_release(sk); | ||
121 | } | ||
122 | |||
123 | |||
124 | /* net/ipv4/udp.c */ | ||
50 | extern int udp_get_port(struct sock *sk, unsigned short snum, | 125 | extern int udp_get_port(struct sock *sk, unsigned short snum, |
51 | int (*saddr_cmp)(const struct sock *, const struct sock *)); | 126 | int (*saddr_cmp)(const struct sock *, const struct sock *)); |
52 | extern void udp_err(struct sk_buff *, u32); | 127 | extern void udp_err(struct sk_buff *, u32); |
@@ -61,21 +136,29 @@ extern unsigned int udp_poll(struct file *file, struct socket *sock, | |||
61 | poll_table *wait); | 136 | poll_table *wait); |
62 | 137 | ||
63 | DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); | 138 | DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); |
64 | #define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field) | 139 | /* |
65 | #define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field) | 140 | * SNMP statistics for UDP and UDP-Lite |
66 | #define UDP_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_statistics, field) | 141 | */ |
142 | #define UDP_INC_STATS_USER(field, is_udplite) do { \ | ||
143 | if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field); \ | ||
144 | else SNMP_INC_STATS_USER(udp_statistics, field); } while(0) | ||
145 | #define UDP_INC_STATS_BH(field, is_udplite) do { \ | ||
146 | if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field); \ | ||
147 | else SNMP_INC_STATS_BH(udp_statistics, field); } while(0) | ||
67 | 148 | ||
68 | /* /proc */ | 149 | /* /proc */ |
69 | struct udp_seq_afinfo { | 150 | struct udp_seq_afinfo { |
70 | struct module *owner; | 151 | struct module *owner; |
71 | char *name; | 152 | char *name; |
72 | sa_family_t family; | 153 | sa_family_t family; |
154 | struct hlist_head *hashtable; | ||
73 | int (*seq_show) (struct seq_file *m, void *v); | 155 | int (*seq_show) (struct seq_file *m, void *v); |
74 | struct file_operations *seq_fops; | 156 | struct file_operations *seq_fops; |
75 | }; | 157 | }; |
76 | 158 | ||
77 | struct udp_iter_state { | 159 | struct udp_iter_state { |
78 | sa_family_t family; | 160 | sa_family_t family; |
161 | struct hlist_head *hashtable; | ||
79 | int bucket; | 162 | int bucket; |
80 | struct seq_operations seq_ops; | 163 | struct seq_operations seq_ops; |
81 | }; | 164 | }; |
diff --git a/include/net/udplite.h b/include/net/udplite.h new file mode 100644 index 000000000000..1473b3e49044 --- /dev/null +++ b/include/net/udplite.h | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Definitions for the UDP-Lite (RFC 3828) code. | ||
3 | */ | ||
4 | #ifndef _UDPLITE_H | ||
5 | #define _UDPLITE_H | ||
6 | |||
7 | /* UDP-Lite socket options */ | ||
8 | #define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ | ||
9 | #define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ | ||
10 | |||
11 | extern struct proto udplite_prot; | ||
12 | extern struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; | ||
13 | |||
14 | /* UDP-Lite does not have a standardized MIB yet, so we inherit from UDP */ | ||
15 | DECLARE_SNMP_STAT(struct udp_mib, udplite_statistics); | ||
16 | |||
17 | /* | ||
18 | * Checksum computation is all in software, hence simpler getfrag. | ||
19 | */ | ||
20 | static __inline__ int udplite_getfrag(void *from, char *to, int offset, | ||
21 | int len, int odd, struct sk_buff *skb) | ||
22 | { | ||
23 | return memcpy_fromiovecend(to, (struct iovec *) from, offset, len); | ||
24 | } | ||
25 | |||
26 | /* Designate sk as UDP-Lite socket */ | ||
27 | static inline int udplite_sk_init(struct sock *sk) | ||
28 | { | ||
29 | udp_sk(sk)->pcflag = UDPLITE_BIT; | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Checksumming routines | ||
35 | */ | ||
36 | static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) | ||
37 | { | ||
38 | u16 cscov; | ||
39 | |||
40 | /* In UDPv4 a zero checksum means that the transmitter generated no | ||
41 | * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets | ||
42 | * with a zero checksum field are illegal. */ | ||
43 | if (uh->check == 0) { | ||
44 | LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: zeroed checksum field\n"); | ||
45 | return 1; | ||
46 | } | ||
47 | |||
48 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
49 | cscov = ntohs(uh->len); | ||
50 | |||
51 | if (cscov == 0) /* Indicates that full coverage is required. */ | ||
52 | cscov = skb->len; | ||
53 | else if (cscov < 8 || cscov > skb->len) { | ||
54 | /* | ||
55 | * Coverage length violates RFC 3828: log and discard silently. | ||
56 | */ | ||
57 | LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad csum coverage %d/%d\n", | ||
58 | cscov, skb->len); | ||
59 | return 1; | ||
60 | |||
61 | } else if (cscov < skb->len) | ||
62 | UDP_SKB_CB(skb)->partial_cov = 1; | ||
63 | |||
64 | UDP_SKB_CB(skb)->cscov = cscov; | ||
65 | |||
66 | /* | ||
67 | * There is no known NIC manufacturer supporting UDP-Lite yet, | ||
68 | * hence ip_summed is always (re-)set to CHECKSUM_NONE. | ||
69 | */ | ||
70 | skb->ip_summed = CHECKSUM_NONE; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static __inline__ int udplite4_csum_init(struct sk_buff *skb, struct udphdr *uh) | ||
76 | { | ||
77 | int rc = udplite_checksum_init(skb, uh); | ||
78 | |||
79 | if (!rc) | ||
80 | skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, | ||
81 | skb->nh.iph->daddr, | ||
82 | skb->len, IPPROTO_UDPLITE, 0); | ||
83 | return rc; | ||
84 | } | ||
85 | |||
86 | static __inline__ int udplite6_csum_init(struct sk_buff *skb, struct udphdr *uh) | ||
87 | { | ||
88 | int rc = udplite_checksum_init(skb, uh); | ||
89 | |||
90 | if (!rc) | ||
91 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
92 | &skb->nh.ipv6h->daddr, | ||
93 | skb->len, IPPROTO_UDPLITE, 0); | ||
94 | return rc; | ||
95 | } | ||
96 | |||
97 | static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) | ||
98 | { | ||
99 | int cscov = up->len; | ||
100 | |||
101 | /* | ||
102 | * Sender has set `partial coverage' option on UDP-Lite socket | ||
103 | */ | ||
104 | if (up->pcflag & UDPLITE_SEND_CC) { | ||
105 | if (up->pcslen < up->len) { | ||
106 | /* up->pcslen == 0 means that full coverage is required, | ||
107 | * partial coverage only if 0 < up->pcslen < up->len */ | ||
108 | if (0 < up->pcslen) { | ||
109 | cscov = up->pcslen; | ||
110 | } | ||
111 | uh->len = htons(up->pcslen); | ||
112 | } | ||
113 | /* | ||
114 | * NOTE: Causes for the error case `up->pcslen > up->len': | ||
115 | * (i) Application error (will not be penalized). | ||
116 | * (ii) Payload too big for send buffer: data is split | ||
117 | * into several packets, each with its own header. | ||
118 | * In this case (e.g. last segment), coverage may | ||
119 | * exceed packet length. | ||
120 | * Since packets with coverage length > packet length are | ||
121 | * illegal, we fall back to the defaults here. | ||
122 | */ | ||
123 | } | ||
124 | return cscov; | ||
125 | } | ||
126 | |||
127 | static inline u32 udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) | ||
128 | { | ||
129 | u32 csum = 0; | ||
130 | int off, len, cscov = udplite_sender_cscov(udp_sk(sk), skb->h.uh); | ||
131 | |||
132 | skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ | ||
133 | |||
134 | skb_queue_walk(&sk->sk_write_queue, skb) { | ||
135 | off = skb->h.raw - skb->data; | ||
136 | len = skb->len - off; | ||
137 | |||
138 | csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum); | ||
139 | |||
140 | if ((cscov -= len) <= 0) | ||
141 | break; | ||
142 | } | ||
143 | return csum; | ||
144 | } | ||
145 | |||
146 | extern void udplite4_register(void); | ||
147 | extern int udplite_get_port(struct sock *sk, unsigned short snum, | ||
148 | int (*scmp)(const struct sock *, const struct sock *)); | ||
149 | #endif /* _UDPLITE_H */ | ||
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 81c91e8a328f..3878a88ff618 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -468,6 +468,7 @@ __be16 xfrm_flowi_sport(struct flowi *fl) | |||
468 | switch(fl->proto) { | 468 | switch(fl->proto) { |
469 | case IPPROTO_TCP: | 469 | case IPPROTO_TCP: |
470 | case IPPROTO_UDP: | 470 | case IPPROTO_UDP: |
471 | case IPPROTO_UDPLITE: | ||
471 | case IPPROTO_SCTP: | 472 | case IPPROTO_SCTP: |
472 | port = fl->fl_ip_sport; | 473 | port = fl->fl_ip_sport; |
473 | break; | 474 | break; |
@@ -493,6 +494,7 @@ __be16 xfrm_flowi_dport(struct flowi *fl) | |||
493 | switch(fl->proto) { | 494 | switch(fl->proto) { |
494 | case IPPROTO_TCP: | 495 | case IPPROTO_TCP: |
495 | case IPPROTO_UDP: | 496 | case IPPROTO_UDP: |
497 | case IPPROTO_UDPLITE: | ||
496 | case IPPROTO_SCTP: | 498 | case IPPROTO_SCTP: |
497 | port = fl->fl_ip_dport; | 499 | port = fl->fl_ip_dport; |
498 | break; | 500 | break; |