diff options
-rw-r--r-- | include/net/mip6.h | 4 | ||||
-rw-r--r-- | net/ipv6/mip6.c | 83 | ||||
-rw-r--r-- | net/ipv6/raw.c | 29 |
3 files changed, 115 insertions, 1 deletions
diff --git a/include/net/mip6.h b/include/net/mip6.h index fd43178faace..68263c6d9996 100644 --- a/include/net/mip6.h +++ b/include/net/mip6.h | |||
@@ -25,6 +25,9 @@ | |||
25 | #ifndef _NET_MIP6_H | 25 | #ifndef _NET_MIP6_H |
26 | #define _NET_MIP6_H | 26 | #define _NET_MIP6_H |
27 | 27 | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <net/sock.h> | ||
30 | |||
28 | #define MIP6_OPT_PAD_1 0 | 31 | #define MIP6_OPT_PAD_1 0 |
29 | #define MIP6_OPT_PAD_N 1 | 32 | #define MIP6_OPT_PAD_N 1 |
30 | 33 | ||
@@ -53,5 +56,6 @@ struct ip6_mh { | |||
53 | 56 | ||
54 | extern int mip6_init(void); | 57 | extern int mip6_init(void); |
55 | extern void mip6_fini(void); | 58 | extern void mip6_fini(void); |
59 | extern int mip6_mh_filter(struct sock *sk, struct sk_buff *skb); | ||
56 | 60 | ||
57 | #endif | 61 | #endif |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index a8adf891fe0e..7b5f89321482 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
@@ -26,7 +26,10 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | #include <linux/ipv6.h> | 28 | #include <linux/ipv6.h> |
29 | #include <linux/icmpv6.h> | ||
30 | #include <net/sock.h> | ||
29 | #include <net/ipv6.h> | 31 | #include <net/ipv6.h> |
32 | #include <net/ip6_checksum.h> | ||
30 | #include <net/xfrm.h> | 33 | #include <net/xfrm.h> |
31 | #include <net/mip6.h> | 34 | #include <net/mip6.h> |
32 | 35 | ||
@@ -55,6 +58,86 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen) | |||
55 | return data + padlen; | 58 | return data + padlen; |
56 | } | 59 | } |
57 | 60 | ||
61 | static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos) | ||
62 | { | ||
63 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | ||
64 | } | ||
65 | |||
66 | static int mip6_mh_len(int type) | ||
67 | { | ||
68 | int len = 0; | ||
69 | |||
70 | switch (type) { | ||
71 | case IP6_MH_TYPE_BRR: | ||
72 | len = 0; | ||
73 | break; | ||
74 | case IP6_MH_TYPE_HOTI: | ||
75 | case IP6_MH_TYPE_COTI: | ||
76 | case IP6_MH_TYPE_BU: | ||
77 | case IP6_MH_TYPE_BACK: | ||
78 | len = 1; | ||
79 | break; | ||
80 | case IP6_MH_TYPE_HOT: | ||
81 | case IP6_MH_TYPE_COT: | ||
82 | case IP6_MH_TYPE_BERROR: | ||
83 | len = 2; | ||
84 | break; | ||
85 | } | ||
86 | return len; | ||
87 | } | ||
88 | |||
89 | int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) | ||
90 | { | ||
91 | struct ip6_mh *mh; | ||
92 | int mhlen; | ||
93 | |||
94 | if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) || | ||
95 | !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3))) | ||
96 | return -1; | ||
97 | |||
98 | mh = (struct ip6_mh *)skb->h.raw; | ||
99 | |||
100 | if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { | ||
101 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n", | ||
102 | mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); | ||
103 | mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw); | ||
104 | return -1; | ||
105 | } | ||
106 | mhlen = (mh->ip6mh_hdrlen + 1) << 3; | ||
107 | |||
108 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | ||
109 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
110 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
111 | &skb->nh.ipv6h->daddr, | ||
112 | mhlen, IPPROTO_MH, | ||
113 | skb->csum)) { | ||
114 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n"); | ||
115 | skb->ip_summed = CHECKSUM_NONE; | ||
116 | } | ||
117 | } | ||
118 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
119 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
120 | &skb->nh.ipv6h->daddr, | ||
121 | mhlen, IPPROTO_MH, | ||
122 | skb_checksum(skb, 0, mhlen, 0))) { | ||
123 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", | ||
124 | NIP6(skb->nh.ipv6h->saddr), | ||
125 | NIP6(skb->nh.ipv6h->daddr)); | ||
126 | return -1; | ||
127 | } | ||
128 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
129 | } | ||
130 | |||
131 | if (mh->ip6mh_proto != IPPROTO_NONE) { | ||
132 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n", | ||
133 | mh->ip6mh_proto); | ||
134 | mip6_param_prob(skb, 0, (&mh->ip6mh_proto) - skb->nh.raw); | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
58 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) | 141 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) |
59 | { | 142 | { |
60 | struct ipv6hdr *iph = skb->nh.ipv6h; | 143 | struct ipv6hdr *iph = skb->nh.ipv6h; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d4af1cb5e19f..ecca8aae3c4b 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -50,6 +50,9 @@ | |||
50 | #include <net/udp.h> | 50 | #include <net/udp.h> |
51 | #include <net/inet_common.h> | 51 | #include <net/inet_common.h> |
52 | #include <net/tcp_states.h> | 52 | #include <net/tcp_states.h> |
53 | #ifdef CONFIG_IPV6_MIP6 | ||
54 | #include <net/mip6.h> | ||
55 | #endif | ||
53 | 56 | ||
54 | #include <net/rawv6.h> | 57 | #include <net/rawv6.h> |
55 | #include <net/xfrm.h> | 58 | #include <net/xfrm.h> |
@@ -169,8 +172,32 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
169 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); | 172 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); |
170 | 173 | ||
171 | while (sk) { | 174 | while (sk) { |
175 | int filtered; | ||
176 | |||
172 | delivered = 1; | 177 | delivered = 1; |
173 | if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) { | 178 | switch (nexthdr) { |
179 | case IPPROTO_ICMPV6: | ||
180 | filtered = icmpv6_filter(sk, skb); | ||
181 | break; | ||
182 | #ifdef CONFIG_IPV6_MIP6 | ||
183 | case IPPROTO_MH: | ||
184 | /* XXX: To validate MH only once for each packet, | ||
185 | * this is placed here. It should be after checking | ||
186 | * xfrm policy, however it doesn't. The checking xfrm | ||
187 | * policy is placed in rawv6_rcv() because it is | ||
188 | * required for each socket. | ||
189 | */ | ||
190 | filtered = mip6_mh_filter(sk, skb); | ||
191 | break; | ||
192 | #endif | ||
193 | default: | ||
194 | filtered = 0; | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | if (filtered < 0) | ||
199 | break; | ||
200 | if (filtered == 0) { | ||
174 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 201 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
175 | 202 | ||
176 | /* Not releasing hash table! */ | 203 | /* Not releasing hash table! */ |