aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-08-23 23:35:31 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:07:01 -0400
commit7be96f7628469e56f91d51f13b03e9bcff113c7f (patch)
tree60db169f3fa51967dd916355face3f2b38d7cc5d
parent2b741653b6c824fe7520ee92b6795f11c5f24b24 (diff)
[IPV6] MIP6: Add receiving mobility header functions through raw socket.
Like ICMPv6, mobility header is handled through raw socket. In inbound case, check only whether ICMPv6 error should be sent as a reply or not by kernel. Based on MIPL2 kernel patch. This patch was also written by: Ville Nuorvala <vnuorval@tcs.hut.fi> This patch was also written by: Antti Tuominen <anttit@tcs.hut.fi> Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/mip6.h4
-rw-r--r--net/ipv6/mip6.c83
-rw-r--r--net/ipv6/raw.c29
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
54extern int mip6_init(void); 57extern int mip6_init(void);
55extern void mip6_fini(void); 58extern void mip6_fini(void);
59extern 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
61static 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
66static 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
89int 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
58static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) 141static 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! */