Blame view

net/ipv6/mip6.c 13.2 KB
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   * 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
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  /*
   * Authors:
   *	Noriaki TAKAMIYA @USAGI
   *	Masahide NAKAMURA @USAGI
   */
f32138319   Joe Perches   net: ipv6: Standa...
24
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
25
26
  #include <linux/module.h>
  #include <linux/skbuff.h>
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
27
  #include <linux/time.h>
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
28
  #include <linux/ipv6.h>
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
29
30
  #include <linux/icmpv6.h>
  #include <net/sock.h>
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
31
  #include <net/ipv6.h>
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
32
  #include <net/ip6_checksum.h>
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
33
  #include <net/rawv6.h>
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
34
35
  #include <net/xfrm.h>
  #include <net/mip6.h>
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
36
37
38
39
40
41
42
43
44
45
  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...
46
  		data[0] = IPV6_TLV_PAD1;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
47
  	} else if (padlen > 1) {
7f1eced8b   YOSHIFUJI Hideaki   [IPV6] MIP6: Use ...
48
  		data[0] = IPV6_TLV_PADN;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
49
50
51
52
53
54
  		data[1] = padlen - 2;
  		if (padlen > 2)
  			memset(data+2, 0, data[1]);
  	}
  	return data + padlen;
  }
d5fdd6bab   Brian Haley   ipv6: Use correct...
55
  static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
56
  {
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
57
  	icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  }
  
  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...
82
  static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
83
  {
96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
84
85
  	struct ip6_mh _hdr;
  	const struct ip6_mh *mh;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
86

96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
87
88
89
  	mh = skb_header_pointer(skb, skb_transport_offset(skb),
  				sizeof(_hdr), &_hdr);
  	if (!mh)
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
90
  		return -1;
96af69ea2   Eric Dumazet   ipv6: mip6: fix m...
91
92
  	if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len)
  		return -1;
7be96f762   Masahide NAKAMURA   [IPV6] MIP6: Add ...
93
94
95
96
97
  
  	if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
  		LIMIT_NETDEBUG(KERN_DEBUG "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
104
105
106
  
  	if (mh->ip6mh_proto != IPPROTO_NONE) {
  		LIMIT_NETDEBUG(KERN_DEBUG "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
116
117
118
119
120
121
122
  struct mip6_report_rate_limiter {
  	spinlock_t lock;
  	struct timeval stamp;
  	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;
  }
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
179
  static inline int mip6_report_rl_allow(struct timeval *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
186
187
188
189
190
191
192
193
  {
  	int allow = 0;
  
  	spin_lock_bh(&mip6_report_rl.lock);
  	if (mip6_report_rl.stamp.tv_sec != stamp->tv_sec ||
  	    mip6_report_rl.stamp.tv_usec != stamp->tv_usec ||
  	    mip6_report_rl.iif != iif ||
  	    !ipv6_addr_equal(&mip6_report_rl.src, src) ||
  	    !ipv6_addr_equal(&mip6_report_rl.dst, dst)) {
  		mip6_report_rl.stamp.tv_sec = stamp->tv_sec;
  		mip6_report_rl.stamp.tv_usec = stamp->tv_usec;
  		mip6_report_rl.iif = iif;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
194
195
  		mip6_report_rl.src = *src;
  		mip6_report_rl.dst = *dst;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
196
197
198
199
200
  		allow = 1;
  	}
  	spin_unlock_bh(&mip6_report_rl.lock);
  	return allow;
  }
8f029de28   David S. Miller   xfrm: Mark flowi ...
201
202
  static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
  			       const struct flowi *fl)
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
203
  {
db983c114   Alexey Dobriyan   netns xfrm: KM re...
204
  	struct net *net = xs_net(x);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
205
  	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
4c9483b2f   David S. Miller   ipv6: Convert to ...
206
  	const struct flowi6 *fl6 = &fl->u.ip6;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
207
208
209
210
211
  	struct ipv6_destopt_hao *hao = NULL;
  	struct xfrm_selector sel;
  	int offset;
  	struct timeval stamp;
  	int err = 0;
4c9483b2f   David S. Miller   ipv6: Convert to ...
212
  	if (unlikely(fl6->flowi6_proto == IPPROTO_MH &&
1958b856c   David S. Miller   net: Put fl6_* ma...
213
  		     fl6->fl6_mh_type <= IP6_MH_TYPE_MAX))
01be8e5d5   Masahide NAKAMURA   [IPV6] MIP6: Igno...
214
  		goto out;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
215
216
217
  	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...
218
219
  			hao = (struct ipv6_destopt_hao *)
  					(skb_network_header(skb) + offset);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
220
221
222
  	}
  
  	skb_get_timestamp(skb, &stamp);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
223
224
  	if (!mip6_report_rl_allow(&stamp, &ipv6_hdr(skb)->daddr,
  				  hao ? &hao->addr : &ipv6_hdr(skb)->saddr,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
225
226
227
228
  				  opt->iif))
  		goto out;
  
  	memset(&sel, 0, sizeof(sel));
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
229
  	memcpy(&sel.daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
230
231
  	       sizeof(sel.daddr));
  	sel.prefixlen_d = 128;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
232
  	memcpy(&sel.saddr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
233
234
235
  	       sizeof(sel.saddr));
  	sel.prefixlen_s = 128;
  	sel.family = AF_INET6;
4c9483b2f   David S. Miller   ipv6: Convert to ...
236
237
  	sel.proto = fl6->flowi6_proto;
  	sel.dport = xfrm_flowi_dport(fl, &fl6->uli);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
238
  	if (sel.dport)
e69a4adc6   Al Viro   [IPV6]: Misc endi...
239
  		sel.dport_mask = htons(~0);
4c9483b2f   David S. Miller   ipv6: Convert to ...
240
  	sel.sport = xfrm_flowi_sport(fl, &fl6->uli);
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
241
  	if (sel.sport)
e69a4adc6   Al Viro   [IPV6]: Misc endi...
242
  		sel.sport_mask = htons(~0);
4c9483b2f   David S. Miller   ipv6: Convert to ...
243
  	sel.ifindex = fl6->flowi6_oif;
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
244

db983c114   Alexey Dobriyan   netns xfrm: KM re...
245
  	err = km_report(net, IPPROTO_DSTOPTS, &sel,
70182ed23   Masahide NAKAMURA   [IPV6] MIP6: Repo...
246
247
248
249
250
  			(hao ? (xfrm_address_t *)&hao->addr : NULL));
  
   out:
  	return err;
  }
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
251
252
253
254
  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...
255
256
  	struct ipv6_opt_hdr *exthdr =
  				   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
257
  	const unsigned char *nh = skb_network_header(skb);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
258
  	unsigned int packet_len = skb->tail - skb->network_header;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
259
  	int found_rhdr = 0;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
260
  	*nexthdr = &ipv6_hdr(skb)->nexthdr;
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  
  	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) {
  				LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override
  ");
  				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...
292
  		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
293
294
295
296
297
298
299
300
  	}
  
  	return offset;
  }
  
  static int mip6_destopt_init_state(struct xfrm_state *x)
  {
  	if (x->id.spi) {
f32138319   Joe Perches   net: ipv6: Standa...
301
302
  		pr_info("%s: spi is not 0: %u
  ", __func__, x->id.spi);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
303
304
305
  		return -EINVAL;
  	}
  	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
f32138319   Joe Perches   net: ipv6: Standa...
306
307
308
  		pr_info("%s: state's mode is not %u: %u
  ",
  			__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
309
310
311
312
313
314
  		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_...
315
  	WARN_ON(x->props.header_len != 24);
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
316
317
318
319
320
321
322
323
324
325
326
  
  	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)
  {
  }
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
327
  static const struct xfrm_type mip6_destopt_type =
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
328
329
330
331
  {
  	.description	= "MIP6DESTOPT",
  	.owner		= THIS_MODULE,
  	.proto	     	= IPPROTO_DSTOPTS,
f04e7e8d7   Herbert Xu   [IPSEC]: Replace ...
332
  	.flags		= XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
333
334
335
336
  	.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...
337
  	.reject		= mip6_destopt_reject,
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
338
  	.hdr_offset	= mip6_destopt_offset,
3d126890d   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
339
  };
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
340
341
  static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
342
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
343
  	struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
344
  	int err = rt2->rt_hdr.nexthdr;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
345

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

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
352
  	return err;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
353
354
355
356
357
358
359
360
361
362
  }
  
  /* 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-...
363
  	skb_push(skb, -skb_network_offset(skb));
007f0211a   Herbert Xu   [IPSEC]: Store IP...
364
  	iph = ipv6_hdr(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
365

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

9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
369
  	rt2 = (struct rt2_hdr *)skb_transport_header(skb);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
370
371
372
373
374
  	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_...
375
  	WARN_ON(rt2->rt_hdr.hdrlen != 2);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
376
377
  
  	memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
378
  	spin_lock_bh(&x->lock);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
379
  	memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
380
  	spin_unlock_bh(&x->lock);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
381
382
383
384
385
386
387
388
  
  	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...
389
390
  	struct ipv6_opt_hdr *exthdr =
  				   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
391
  	const unsigned char *nh = skb_network_header(skb);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
392
  	unsigned int packet_len = skb->tail - skb->network_header;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
393
  	int found_rhdr = 0;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
394
  	*nexthdr = &ipv6_hdr(skb)->nexthdr;
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
395
396
397
398
399
400
401
402
403
  
  	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...
404
  				rt = (struct ipv6_rt_hdr *)(nh + offset);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  				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...
424
  		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
425
426
427
428
429
430
431
432
  	}
  
  	return offset;
  }
  
  static int mip6_rthdr_init_state(struct xfrm_state *x)
  {
  	if (x->id.spi) {
f32138319   Joe Perches   net: ipv6: Standa...
433
434
  		pr_info("%s: spi is not 0: %u
  ", __func__, x->id.spi);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
435
436
437
  		return -EINVAL;
  	}
  	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
f32138319   Joe Perches   net: ipv6: Standa...
438
439
440
  		pr_info("%s: state's mode is not %u: %u
  ",
  			__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  		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)
  {
  }
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
456
  static const struct xfrm_type mip6_rthdr_type =
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
457
458
459
460
  {
  	.description	= "MIP6RT",
  	.owner		= THIS_MODULE,
  	.proto	     	= IPPROTO_ROUTING,
f04e7e8d7   Herbert Xu   [IPSEC]: Replace ...
461
  	.flags		= XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
462
463
464
465
466
  	.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 ...
467
  };
59fbb3a61   Masahide NAKAMURA   [IPV6] MIP6: Load...
468
  static int __init mip6_init(void)
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
469
  {
f32138319   Joe Perches   net: ipv6: Standa...
470
471
  	pr_info("Mobile IPv6
  ");
2c8d7ca0f   Noriaki TAKAMIYA   [IPV6] MIP6: Add ...
472

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