Blame view

net/ipv6/mip6.c 13 KB
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Copyright (C)2003-2006 Helsinki University of Technology
   * Copyright (C)2003-2006 USAGI/WIDE Project
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
a99421d9b   Jeff Kirsher   ipv4/ipv6: Fix FS...
16
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
17
18
19
20
21
22
   */
  /*
   * Authors:
   *	Noriaki TAKAMIYA @USAGI
   *	Masahide NAKAMURA @USAGI
   */
f32138319   Joe Perches   net: ipv6: Standa...
23
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
24
25
  #include <linux/module.h>
  #include <linux/skbuff.h>
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
26
  #include <linux/time.h>
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
27
  #include <linux/ipv6.h>
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
28
29
  #include <linux/icmpv6.h>
  #include <net/sock.h>
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
30
  #include <net/ipv6.h>
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
31
  #include <net/ip6_checksum.h>
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
32
  #include <net/rawv6.h>
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
33
34
  #include <net/xfrm.h>
  #include <net/mip6.h>
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
35
36
37
38
39
40
41
42
43
44
  static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
  {
  	return (n - len + 16) & 0x7;
  }
  
  static inline void *mip6_padn(__u8 *data, __u8 padlen)
  {
  	if (!data)
  		return NULL;
  	if (padlen == 1) {
1de5a71c3   Eldad Zack   ipv6: correct the...
45
  		data[0] = IPV6_TLV_PAD1;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
46
  	} else if (padlen > 1) {
7f1eced8b   YOSHIFUJI Hideaki   [IPV6] MIP6: Use ...
47
  		data[0] = IPV6_TLV_PADN;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
48
49
50
51
52
53
  		data[1] = padlen - 2;
  		if (padlen > 2)
  			memset(data+2, 0, data[1]);
  	}
  	return data + padlen;
  }
d5fdd6bab   Brian Haley   ipv6: Use correct...
54
  static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
55
  {
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
56
  	icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  }
  
  static int mip6_mh_len(int type)
  {
  	int len = 0;
  
  	switch (type) {
  	case IP6_MH_TYPE_BRR:
  		len = 0;
  		break;
  	case IP6_MH_TYPE_HOTI:
  	case IP6_MH_TYPE_COTI:
  	case IP6_MH_TYPE_BU:
  	case IP6_MH_TYPE_BACK:
  		len = 1;
  		break;
  	case IP6_MH_TYPE_HOT:
  	case IP6_MH_TYPE_COT:
  	case IP6_MH_TYPE_BERROR:
  		len = 2;
  		break;
  	}
  	return len;
  }
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
81
  static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
82
  {
96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
83
84
  	struct ip6_mh _hdr;
  	const struct ip6_mh *mh;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
85

96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
86
87
88
  	mh = skb_header_pointer(skb, skb_transport_offset(skb),
  				sizeof(_hdr), &_hdr);
  	if (!mh)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
89
  		return -1;
96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
90
91
  	if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len)
  		return -1;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
92
93
  
  	if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
ba7a46f16   Joe Perches   net: Convert LIMI...
94
95
96
97
  		net_dbg_ratelimited("mip6: MH message too short: %d vs >=%d
  ",
  				    mh->ip6mh_hdrlen,
  				    mip6_mh_len(mh->ip6mh_type));
96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
98
99
  		mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) +
  				skb_network_header_len(skb));
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
100
101
  		return -1;
  	}
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
102
103
  
  	if (mh->ip6mh_proto != IPPROTO_NONE) {
ba7a46f16   Joe Perches   net: Convert LIMI...
104
105
106
  		net_dbg_ratelimited("mip6: MH invalid payload proto = %d
  ",
  				    mh->ip6mh_proto);
96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
107
108
  		mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) +
  				skb_network_header_len(skb));
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
109
110
111
112
113
  		return -1;
  	}
  
  	return 0;
  }
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
114
115
  struct mip6_report_rate_limiter {
  	spinlock_t lock;
3dd7669f1   Arnd Bergmann   ipv6: use ktime_t...
116
  	ktime_t stamp;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
117
118
119
120
121
122
  	int iif;
  	struct in6_addr src;
  	struct in6_addr dst;
  };
  
  static struct mip6_report_rate_limiter mip6_report_rl = {
4ef8d0aea   Milind Arun Choudhary   [NET]: SPIN_LOCK_...
123
  	.lock = __SPIN_LOCK_UNLOCKED(mip6_report_rl.lock)
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
124
  };
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
125
126
  static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
127
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
128
  	struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
129
  	int err = destopt->nexthdr;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
130

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
131
  	spin_lock(&x->lock);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
132
133
  	if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
  	    !ipv6_addr_any((struct in6_addr *)x->coaddr))
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
134
135
  		err = -ENOENT;
  	spin_unlock(&x->lock);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
136

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
137
  	return err;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
138
139
140
141
142
143
144
145
146
147
148
149
150
  }
  
  /* Destination Option Header is inserted.
   * IP Header's src address is replaced with Home Address Option in
   * Destination Option Header.
   */
  static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct ipv6hdr *iph;
  	struct ipv6_destopt_hdr *dstopt;
  	struct ipv6_destopt_hao *hao;
  	u8 nexthdr;
  	int len;
7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
151
  	skb_push(skb, -skb_network_offset(skb));
007f0211a   Herbert Xu   [IPSEC]: Store IP...
152
  	iph = ipv6_hdr(skb);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
153

007f0211a   Herbert Xu   [IPSEC]: Store IP...
154
155
  	nexthdr = *skb_mac_header(skb);
  	*skb_mac_header(skb) = IPPROTO_DSTOPTS;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
156

9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
157
  	dstopt = (struct ipv6_destopt_hdr *)skb_transport_header(skb);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
158
159
160
161
162
163
  	dstopt->nexthdr = nexthdr;
  
  	hao = mip6_padn((char *)(dstopt + 1),
  			calc_padlen(sizeof(*dstopt), 6));
  
  	hao->type = IPV6_TLV_HAO;
547b792ca   Ilpo Järvinen   net: convert BUG_...
164
  	BUILD_BUG_ON(sizeof(*hao) != 18);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
165
  	hao->length = sizeof(*hao) - 2;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
166
167
168
169
  
  	len = ((char *)hao - (char *)dstopt) + sizeof(*hao);
  
  	memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
170
  	spin_lock_bh(&x->lock);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
171
  	memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
172
  	spin_unlock_bh(&x->lock);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
173

547b792ca   Ilpo Järvinen   net: convert BUG_...
174
  	WARN_ON(len != x->props.header_len);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
175
176
177
178
  	dstopt->hdrlen = (x->props.header_len >> 3) - 1;
  
  	return 0;
  }
3dd7669f1   Arnd Bergmann   ipv6: use ktime_t...
179
  static inline int mip6_report_rl_allow(ktime_t stamp,
b71d1d426   Eric Dumazet   inet: constify ip...
180
181
  				       const struct in6_addr *dst,
  				       const struct in6_addr *src, int iif)
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
182
183
184
185
  {
  	int allow = 0;
  
  	spin_lock_bh(&mip6_report_rl.lock);
1f3a8e49d   Thomas Gleixner   ktime: Get rid of...
186
  	if (mip6_report_rl.stamp != stamp ||
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
187
188
189
  	    mip6_report_rl.iif != iif ||
  	    !ipv6_addr_equal(&mip6_report_rl.src, src) ||
  	    !ipv6_addr_equal(&mip6_report_rl.dst, dst)) {
3dd7669f1   Arnd Bergmann   ipv6: use ktime_t...
190
  		mip6_report_rl.stamp = stamp;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
191
  		mip6_report_rl.iif = iif;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
192
193
  		mip6_report_rl.src = *src;
  		mip6_report_rl.dst = *dst;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
194
195
196
197
198
  		allow = 1;
  	}
  	spin_unlock_bh(&mip6_report_rl.lock);
  	return allow;
  }
8f029de28   David S. Miller   xfrm: Mark flowi ...
199
200
  static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
  			       const struct flowi *fl)
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
201
  {
db983c114   Alexey Dobriyan   netns xfrm: KM re...
202
  	struct net *net = xs_net(x);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
203
  	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
4c9483b2f   David S. Miller   ipv6: Convert to ...
204
  	const struct flowi6 *fl6 = &fl->u.ip6;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
205
206
207
  	struct ipv6_destopt_hao *hao = NULL;
  	struct xfrm_selector sel;
  	int offset;
3dd7669f1   Arnd Bergmann   ipv6: use ktime_t...
208
  	ktime_t stamp;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
209
  	int err = 0;
4c9483b2f   David S. Miller   ipv6: Convert to ...
210
  	if (unlikely(fl6->flowi6_proto == IPPROTO_MH &&
1958b856c   David S. Miller   net: Put fl6_* ma...
211
  		     fl6->fl6_mh_type <= IP6_MH_TYPE_MAX))
01be8e5d5   Masahide NAKAMURA   [IPV6] MIP6: Igno...
212
  		goto out;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
213
214
215
  	if (likely(opt->dsthao)) {
  		offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
  		if (likely(offset >= 0))
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
216
217
  			hao = (struct ipv6_destopt_hao *)
  					(skb_network_header(skb) + offset);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
218
  	}
3dd7669f1   Arnd Bergmann   ipv6: use ktime_t...
219
  	stamp = skb_get_ktime(skb);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
220

3dd7669f1   Arnd Bergmann   ipv6: use ktime_t...
221
  	if (!mip6_report_rl_allow(stamp, &ipv6_hdr(skb)->daddr,
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
222
  				  hao ? &hao->addr : &ipv6_hdr(skb)->saddr,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
223
224
225
226
  				  opt->iif))
  		goto out;
  
  	memset(&sel, 0, sizeof(sel));
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
227
  	memcpy(&sel.daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
228
229
  	       sizeof(sel.daddr));
  	sel.prefixlen_d = 128;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
230
  	memcpy(&sel.saddr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
231
232
233
  	       sizeof(sel.saddr));
  	sel.prefixlen_s = 128;
  	sel.family = AF_INET6;
4c9483b2f   David S. Miller   ipv6: Convert to ...
234
235
  	sel.proto = fl6->flowi6_proto;
  	sel.dport = xfrm_flowi_dport(fl, &fl6->uli);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
236
  	if (sel.dport)
e69a4adc6   Al Viro   [IPV6]: Misc endi...
237
  		sel.dport_mask = htons(~0);
4c9483b2f   David S. Miller   ipv6: Convert to ...
238
  	sel.sport = xfrm_flowi_sport(fl, &fl6->uli);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
239
  	if (sel.sport)
e69a4adc6   Al Viro   [IPV6]: Misc endi...
240
  		sel.sport_mask = htons(~0);
4c9483b2f   David S. Miller   ipv6: Convert to ...
241
  	sel.ifindex = fl6->flowi6_oif;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
242

db983c114   Alexey Dobriyan   netns xfrm: KM re...
243
  	err = km_report(net, IPPROTO_DSTOPTS, &sel,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
244
245
246
247
248
  			(hao ? (xfrm_address_t *)&hao->addr : NULL));
  
   out:
  	return err;
  }
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
249
250
251
252
  static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
  			       u8 **nexthdr)
  {
  	u16 offset = sizeof(struct ipv6hdr);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
253
254
  	struct ipv6_opt_hdr *exthdr =
  				   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
255
  	const unsigned char *nh = skb_network_header(skb);
29a3cad5c   Simon Horman   ipv6: Correct com...
256
257
  	unsigned int packet_len = skb_tail_pointer(skb) -
  		skb_network_header(skb);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
258
  	int found_rhdr = 0;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
259
  	*nexthdr = &ipv6_hdr(skb)->nexthdr;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  
  	while (offset + 1 <= packet_len) {
  
  		switch (**nexthdr) {
  		case NEXTHDR_HOP:
  			break;
  		case NEXTHDR_ROUTING:
  			found_rhdr = 1;
  			break;
  		case NEXTHDR_DEST:
  			/*
  			 * HAO MUST NOT appear more than once.
  			 * XXX: It is better to try to find by the end of
  			 * XXX: packet if HAO exists.
  			 */
  			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
ba7a46f16   Joe Perches   net: Convert LIMI...
276
277
  				net_dbg_ratelimited("mip6: hao exists already, override
  ");
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
278
279
280
281
282
283
284
285
286
287
288
289
290
  				return offset;
  			}
  
  			if (found_rhdr)
  				return offset;
  
  			break;
  		default:
  			return offset;
  		}
  
  		offset += ipv6_optlen(exthdr);
  		*nexthdr = &exthdr->nexthdr;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
291
  		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
292
293
294
295
296
297
298
299
  	}
  
  	return offset;
  }
  
  static int mip6_destopt_init_state(struct xfrm_state *x)
  {
  	if (x->id.spi) {
f32138319   Joe Perches   net: ipv6: Standa...
300
301
  		pr_info("%s: spi is not 0: %u
  ", __func__, x->id.spi);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
302
303
304
  		return -EINVAL;
  	}
  	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
f32138319   Joe Perches   net: ipv6: Standa...
305
306
307
  		pr_info("%s: state's mode is not %u: %u
  ",
  			__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
308
309
310
311
312
313
  		return -EINVAL;
  	}
  
  	x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
  		calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
  		sizeof(struct ipv6_destopt_hao);
547b792ca   Ilpo Järvinen   net: convert BUG_...
314
  	WARN_ON(x->props.header_len != 24);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
315
316
317
318
319
320
321
322
323
324
325
  
  	return 0;
  }
  
  /*
   * Do nothing about destroying since it has no specific operation for
   * destination options header unlike IPsec protocols.
   */
  static void mip6_destopt_destroy(struct xfrm_state *x)
  {
  }
cc24becae   Ian Morris   ipv6: White-space...
326
  static const struct xfrm_type mip6_destopt_type = {
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
327
328
  	.description	= "MIP6DESTOPT",
  	.owner		= THIS_MODULE,
cc24becae   Ian Morris   ipv6: White-space...
329
  	.proto		= IPPROTO_DSTOPTS,
f04e7e8d7   Herbert Xu   [IPSEC]: Replace ...
330
  	.flags		= XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
331
332
333
334
  	.init_state	= mip6_destopt_init_state,
  	.destructor	= mip6_destopt_destroy,
  	.input		= mip6_destopt_input,
  	.output		= mip6_destopt_output,
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
335
  	.reject		= mip6_destopt_reject,
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
336
  	.hdr_offset	= mip6_destopt_offset,
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
337
  };
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
338
339
  static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
340
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
341
  	struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
342
  	int err = rt2->rt_hdr.nexthdr;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
343

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
344
  	spin_lock(&x->lock);
d9a9dc66e   Arnaud Ebalard   IPv6: fix CoA che...
345
  	if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
346
  	    !ipv6_addr_any((struct in6_addr *)x->coaddr))
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
347
348
  		err = -ENOENT;
  	spin_unlock(&x->lock);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
349

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
350
  	return err;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
351
352
353
354
355
356
357
358
359
360
  }
  
  /* Routing Header type 2 is inserted.
   * IP Header's dst address is replaced with Routing Header's Home Address.
   */
  static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct ipv6hdr *iph;
  	struct rt2_hdr *rt2;
  	u8 nexthdr;
7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
361
  	skb_push(skb, -skb_network_offset(skb));
007f0211a   Herbert Xu   [IPSEC]: Store IP...
362
  	iph = ipv6_hdr(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
363

007f0211a   Herbert Xu   [IPSEC]: Store IP...
364
365
  	nexthdr = *skb_mac_header(skb);
  	*skb_mac_header(skb) = IPPROTO_ROUTING;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
366

9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
367
  	rt2 = (struct rt2_hdr *)skb_transport_header(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
368
369
370
371
372
  	rt2->rt_hdr.nexthdr = nexthdr;
  	rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
  	rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
  	rt2->rt_hdr.segments_left = 1;
  	memset(&rt2->reserved, 0, sizeof(rt2->reserved));
547b792ca   Ilpo Järvinen   net: convert BUG_...
373
  	WARN_ON(rt2->rt_hdr.hdrlen != 2);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
374
375
  
  	memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
376
  	spin_lock_bh(&x->lock);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
377
  	memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
378
  	spin_unlock_bh(&x->lock);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
379
380
381
382
383
384
385
386
  
  	return 0;
  }
  
  static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
  			     u8 **nexthdr)
  {
  	u16 offset = sizeof(struct ipv6hdr);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
387
388
  	struct ipv6_opt_hdr *exthdr =
  				   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
389
  	const unsigned char *nh = skb_network_header(skb);
29a3cad5c   Simon Horman   ipv6: Correct com...
390
391
  	unsigned int packet_len = skb_tail_pointer(skb) -
  		skb_network_header(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
392
  	int found_rhdr = 0;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
393
  	*nexthdr = &ipv6_hdr(skb)->nexthdr;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
394
395
396
397
398
399
400
401
402
  
  	while (offset + 1 <= packet_len) {
  
  		switch (**nexthdr) {
  		case NEXTHDR_HOP:
  			break;
  		case NEXTHDR_ROUTING:
  			if (offset + 3 <= packet_len) {
  				struct ipv6_rt_hdr *rt;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
403
  				rt = (struct ipv6_rt_hdr *)(nh + offset);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  				if (rt->type != 0)
  					return offset;
  			}
  			found_rhdr = 1;
  			break;
  		case NEXTHDR_DEST:
  			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
  				return offset;
  
  			if (found_rhdr)
  				return offset;
  
  			break;
  		default:
  			return offset;
  		}
  
  		offset += ipv6_optlen(exthdr);
  		*nexthdr = &exthdr->nexthdr;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
423
  		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
424
425
426
427
428
429
430
431
  	}
  
  	return offset;
  }
  
  static int mip6_rthdr_init_state(struct xfrm_state *x)
  {
  	if (x->id.spi) {
f32138319   Joe Perches   net: ipv6: Standa...
432
433
  		pr_info("%s: spi is not 0: %u
  ", __func__, x->id.spi);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
434
435
436
  		return -EINVAL;
  	}
  	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
f32138319   Joe Perches   net: ipv6: Standa...
437
438
439
  		pr_info("%s: state's mode is not %u: %u
  ",
  			__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  		return -EINVAL;
  	}
  
  	x->props.header_len = sizeof(struct rt2_hdr);
  
  	return 0;
  }
  
  /*
   * Do nothing about destroying since it has no specific operation for routing
   * header type 2 unlike IPsec protocols.
   */
  static void mip6_rthdr_destroy(struct xfrm_state *x)
  {
  }
cc24becae   Ian Morris   ipv6: White-space...
455
  static const struct xfrm_type mip6_rthdr_type = {
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
456
457
  	.description	= "MIP6RT",
  	.owner		= THIS_MODULE,
cc24becae   Ian Morris   ipv6: White-space...
458
  	.proto		= IPPROTO_ROUTING,
f04e7e8d7   Herbert Xu   [IPSEC]: Replace ...
459
  	.flags		= XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
460
461
462
463
464
  	.init_state	= mip6_rthdr_init_state,
  	.destructor	= mip6_rthdr_destroy,
  	.input		= mip6_rthdr_input,
  	.output		= mip6_rthdr_output,
  	.hdr_offset	= mip6_rthdr_offset,
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
465
  };
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
466
  static int __init mip6_init(void)
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
467
  {
f32138319   Joe Perches   net: ipv6: Standa...
468
469
  	pr_info("Mobile IPv6
  ");
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
470

3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
471
  	if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
472
473
  		pr_info("%s: can't add xfrm type(destopt)
  ", __func__);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
474
475
  		goto mip6_destopt_xfrm_fail;
  	}
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
476
  	if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
477
478
  		pr_info("%s: can't add xfrm type(rthdr)
  ", __func__);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
479
480
  		goto mip6_rthdr_xfrm_fail;
  	}
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
481
  	if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
482
483
  		pr_info("%s: can't add rawv6 mh filter
  ", __func__);
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
484
485
  		goto mip6_rawv6_mh_fail;
  	}
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
486
  	return 0;
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
487
488
   mip6_rawv6_mh_fail:
  	xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
489
   mip6_rthdr_xfrm_fail:
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
490
491
  	xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
   mip6_destopt_xfrm_fail:
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
492
493
  	return -EAGAIN;
  }
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
494
  static void __exit mip6_fini(void)
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
495
  {
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
496
  	if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
f32138319   Joe Perches   net: ipv6: Standa...
497
498
  		pr_info("%s: can't remove rawv6 mh filter
  ", __func__);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
499
  	if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
f32138319   Joe Perches   net: ipv6: Standa...
500
501
  		pr_info("%s: can't remove xfrm type(rthdr)
  ", __func__);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
502
  	if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
f32138319   Joe Perches   net: ipv6: Standa...
503
504
  		pr_info("%s: can't remove xfrm type(destopt)
  ", __func__);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
505
  }
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
506
507
508
509
510
  
  module_init(mip6_init);
  module_exit(mip6_fini);
  
  MODULE_LICENSE("GPL");
d3d6dd3ad   Masahide NAKAMURA   [XFRM]: Add modul...
511
512
  MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
  MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);