1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C)2003-2006 Helsinki University of Technology
4*4882a593Smuzhiyun * Copyright (C)2003-2006 USAGI/WIDE Project
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun /*
7*4882a593Smuzhiyun * Authors:
8*4882a593Smuzhiyun * Noriaki TAKAMIYA @USAGI
9*4882a593Smuzhiyun * Masahide NAKAMURA @USAGI
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/skbuff.h>
16*4882a593Smuzhiyun #include <linux/time.h>
17*4882a593Smuzhiyun #include <linux/ipv6.h>
18*4882a593Smuzhiyun #include <linux/icmpv6.h>
19*4882a593Smuzhiyun #include <net/sock.h>
20*4882a593Smuzhiyun #include <net/ipv6.h>
21*4882a593Smuzhiyun #include <net/ip6_checksum.h>
22*4882a593Smuzhiyun #include <net/rawv6.h>
23*4882a593Smuzhiyun #include <net/xfrm.h>
24*4882a593Smuzhiyun #include <net/mip6.h>
25*4882a593Smuzhiyun
calc_padlen(unsigned int len,unsigned int n)26*4882a593Smuzhiyun static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun return (n - len + 16) & 0x7;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun
mip6_padn(__u8 * data,__u8 padlen)31*4882a593Smuzhiyun static inline void *mip6_padn(__u8 *data, __u8 padlen)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun if (!data)
34*4882a593Smuzhiyun return NULL;
35*4882a593Smuzhiyun if (padlen == 1) {
36*4882a593Smuzhiyun data[0] = IPV6_TLV_PAD1;
37*4882a593Smuzhiyun } else if (padlen > 1) {
38*4882a593Smuzhiyun data[0] = IPV6_TLV_PADN;
39*4882a593Smuzhiyun data[1] = padlen - 2;
40*4882a593Smuzhiyun if (padlen > 2)
41*4882a593Smuzhiyun memset(data+2, 0, data[1]);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun return data + padlen;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
mip6_param_prob(struct sk_buff * skb,u8 code,int pos)46*4882a593Smuzhiyun static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
mip6_mh_len(int type)51*4882a593Smuzhiyun static int mip6_mh_len(int type)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun int len = 0;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun switch (type) {
56*4882a593Smuzhiyun case IP6_MH_TYPE_BRR:
57*4882a593Smuzhiyun len = 0;
58*4882a593Smuzhiyun break;
59*4882a593Smuzhiyun case IP6_MH_TYPE_HOTI:
60*4882a593Smuzhiyun case IP6_MH_TYPE_COTI:
61*4882a593Smuzhiyun case IP6_MH_TYPE_BU:
62*4882a593Smuzhiyun case IP6_MH_TYPE_BACK:
63*4882a593Smuzhiyun len = 1;
64*4882a593Smuzhiyun break;
65*4882a593Smuzhiyun case IP6_MH_TYPE_HOT:
66*4882a593Smuzhiyun case IP6_MH_TYPE_COT:
67*4882a593Smuzhiyun case IP6_MH_TYPE_BERROR:
68*4882a593Smuzhiyun len = 2;
69*4882a593Smuzhiyun break;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun return len;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
mip6_mh_filter(struct sock * sk,struct sk_buff * skb)74*4882a593Smuzhiyun static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun struct ip6_mh _hdr;
77*4882a593Smuzhiyun const struct ip6_mh *mh;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun mh = skb_header_pointer(skb, skb_transport_offset(skb),
80*4882a593Smuzhiyun sizeof(_hdr), &_hdr);
81*4882a593Smuzhiyun if (!mh)
82*4882a593Smuzhiyun return -1;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (((mh->ip6mh_hdrlen + 1) << 3) > skb->len)
85*4882a593Smuzhiyun return -1;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
88*4882a593Smuzhiyun net_dbg_ratelimited("mip6: MH message too short: %d vs >=%d\n",
89*4882a593Smuzhiyun mh->ip6mh_hdrlen,
90*4882a593Smuzhiyun mip6_mh_len(mh->ip6mh_type));
91*4882a593Smuzhiyun mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_hdrlen) +
92*4882a593Smuzhiyun skb_network_header_len(skb));
93*4882a593Smuzhiyun return -1;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun if (mh->ip6mh_proto != IPPROTO_NONE) {
97*4882a593Smuzhiyun net_dbg_ratelimited("mip6: MH invalid payload proto = %d\n",
98*4882a593Smuzhiyun mh->ip6mh_proto);
99*4882a593Smuzhiyun mip6_param_prob(skb, 0, offsetof(struct ip6_mh, ip6mh_proto) +
100*4882a593Smuzhiyun skb_network_header_len(skb));
101*4882a593Smuzhiyun return -1;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun return 0;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun struct mip6_report_rate_limiter {
108*4882a593Smuzhiyun spinlock_t lock;
109*4882a593Smuzhiyun ktime_t stamp;
110*4882a593Smuzhiyun int iif;
111*4882a593Smuzhiyun struct in6_addr src;
112*4882a593Smuzhiyun struct in6_addr dst;
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun static struct mip6_report_rate_limiter mip6_report_rl = {
116*4882a593Smuzhiyun .lock = __SPIN_LOCK_UNLOCKED(mip6_report_rl.lock)
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun
mip6_destopt_input(struct xfrm_state * x,struct sk_buff * skb)119*4882a593Smuzhiyun static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun const struct ipv6hdr *iph = ipv6_hdr(skb);
122*4882a593Smuzhiyun struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
123*4882a593Smuzhiyun int err = destopt->nexthdr;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun spin_lock(&x->lock);
126*4882a593Smuzhiyun if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
127*4882a593Smuzhiyun !ipv6_addr_any((struct in6_addr *)x->coaddr))
128*4882a593Smuzhiyun err = -ENOENT;
129*4882a593Smuzhiyun spin_unlock(&x->lock);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return err;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Destination Option Header is inserted.
135*4882a593Smuzhiyun * IP Header's src address is replaced with Home Address Option in
136*4882a593Smuzhiyun * Destination Option Header.
137*4882a593Smuzhiyun */
mip6_destopt_output(struct xfrm_state * x,struct sk_buff * skb)138*4882a593Smuzhiyun static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct ipv6hdr *iph;
141*4882a593Smuzhiyun struct ipv6_destopt_hdr *dstopt;
142*4882a593Smuzhiyun struct ipv6_destopt_hao *hao;
143*4882a593Smuzhiyun u8 nexthdr;
144*4882a593Smuzhiyun int len;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun skb_push(skb, -skb_network_offset(skb));
147*4882a593Smuzhiyun iph = ipv6_hdr(skb);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun nexthdr = *skb_mac_header(skb);
150*4882a593Smuzhiyun *skb_mac_header(skb) = IPPROTO_DSTOPTS;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun dstopt = (struct ipv6_destopt_hdr *)skb_transport_header(skb);
153*4882a593Smuzhiyun dstopt->nexthdr = nexthdr;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun hao = mip6_padn((char *)(dstopt + 1),
156*4882a593Smuzhiyun calc_padlen(sizeof(*dstopt), 6));
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun hao->type = IPV6_TLV_HAO;
159*4882a593Smuzhiyun BUILD_BUG_ON(sizeof(*hao) != 18);
160*4882a593Smuzhiyun hao->length = sizeof(*hao) - 2;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun len = ((char *)hao - (char *)dstopt) + sizeof(*hao);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr));
165*4882a593Smuzhiyun spin_lock_bh(&x->lock);
166*4882a593Smuzhiyun memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
167*4882a593Smuzhiyun spin_unlock_bh(&x->lock);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun WARN_ON(len != x->props.header_len);
170*4882a593Smuzhiyun dstopt->hdrlen = (x->props.header_len >> 3) - 1;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
mip6_report_rl_allow(ktime_t stamp,const struct in6_addr * dst,const struct in6_addr * src,int iif)175*4882a593Smuzhiyun static inline int mip6_report_rl_allow(ktime_t stamp,
176*4882a593Smuzhiyun const struct in6_addr *dst,
177*4882a593Smuzhiyun const struct in6_addr *src, int iif)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun int allow = 0;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun spin_lock_bh(&mip6_report_rl.lock);
182*4882a593Smuzhiyun if (mip6_report_rl.stamp != stamp ||
183*4882a593Smuzhiyun mip6_report_rl.iif != iif ||
184*4882a593Smuzhiyun !ipv6_addr_equal(&mip6_report_rl.src, src) ||
185*4882a593Smuzhiyun !ipv6_addr_equal(&mip6_report_rl.dst, dst)) {
186*4882a593Smuzhiyun mip6_report_rl.stamp = stamp;
187*4882a593Smuzhiyun mip6_report_rl.iif = iif;
188*4882a593Smuzhiyun mip6_report_rl.src = *src;
189*4882a593Smuzhiyun mip6_report_rl.dst = *dst;
190*4882a593Smuzhiyun allow = 1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun spin_unlock_bh(&mip6_report_rl.lock);
193*4882a593Smuzhiyun return allow;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
mip6_destopt_reject(struct xfrm_state * x,struct sk_buff * skb,const struct flowi * fl)196*4882a593Smuzhiyun static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
197*4882a593Smuzhiyun const struct flowi *fl)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun struct net *net = xs_net(x);
200*4882a593Smuzhiyun struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
201*4882a593Smuzhiyun const struct flowi6 *fl6 = &fl->u.ip6;
202*4882a593Smuzhiyun struct ipv6_destopt_hao *hao = NULL;
203*4882a593Smuzhiyun struct xfrm_selector sel;
204*4882a593Smuzhiyun int offset;
205*4882a593Smuzhiyun ktime_t stamp;
206*4882a593Smuzhiyun int err = 0;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (unlikely(fl6->flowi6_proto == IPPROTO_MH &&
209*4882a593Smuzhiyun fl6->fl6_mh_type <= IP6_MH_TYPE_MAX))
210*4882a593Smuzhiyun goto out;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (likely(opt->dsthao)) {
213*4882a593Smuzhiyun offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
214*4882a593Smuzhiyun if (likely(offset >= 0))
215*4882a593Smuzhiyun hao = (struct ipv6_destopt_hao *)
216*4882a593Smuzhiyun (skb_network_header(skb) + offset);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun stamp = skb_get_ktime(skb);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (!mip6_report_rl_allow(stamp, &ipv6_hdr(skb)->daddr,
222*4882a593Smuzhiyun hao ? &hao->addr : &ipv6_hdr(skb)->saddr,
223*4882a593Smuzhiyun opt->iif))
224*4882a593Smuzhiyun goto out;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun memset(&sel, 0, sizeof(sel));
227*4882a593Smuzhiyun memcpy(&sel.daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
228*4882a593Smuzhiyun sizeof(sel.daddr));
229*4882a593Smuzhiyun sel.prefixlen_d = 128;
230*4882a593Smuzhiyun memcpy(&sel.saddr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
231*4882a593Smuzhiyun sizeof(sel.saddr));
232*4882a593Smuzhiyun sel.prefixlen_s = 128;
233*4882a593Smuzhiyun sel.family = AF_INET6;
234*4882a593Smuzhiyun sel.proto = fl6->flowi6_proto;
235*4882a593Smuzhiyun sel.dport = xfrm_flowi_dport(fl, &fl6->uli);
236*4882a593Smuzhiyun if (sel.dport)
237*4882a593Smuzhiyun sel.dport_mask = htons(~0);
238*4882a593Smuzhiyun sel.sport = xfrm_flowi_sport(fl, &fl6->uli);
239*4882a593Smuzhiyun if (sel.sport)
240*4882a593Smuzhiyun sel.sport_mask = htons(~0);
241*4882a593Smuzhiyun sel.ifindex = fl6->flowi6_oif;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun err = km_report(net, IPPROTO_DSTOPTS, &sel,
244*4882a593Smuzhiyun (hao ? (xfrm_address_t *)&hao->addr : NULL));
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun out:
247*4882a593Smuzhiyun return err;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
mip6_destopt_offset(struct xfrm_state * x,struct sk_buff * skb,u8 ** nexthdr)250*4882a593Smuzhiyun static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
251*4882a593Smuzhiyun u8 **nexthdr)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun u16 offset = sizeof(struct ipv6hdr);
254*4882a593Smuzhiyun struct ipv6_opt_hdr *exthdr =
255*4882a593Smuzhiyun (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
256*4882a593Smuzhiyun const unsigned char *nh = skb_network_header(skb);
257*4882a593Smuzhiyun unsigned int packet_len = skb_tail_pointer(skb) -
258*4882a593Smuzhiyun skb_network_header(skb);
259*4882a593Smuzhiyun int found_rhdr = 0;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun *nexthdr = &ipv6_hdr(skb)->nexthdr;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun while (offset + 1 <= packet_len) {
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun switch (**nexthdr) {
266*4882a593Smuzhiyun case NEXTHDR_HOP:
267*4882a593Smuzhiyun break;
268*4882a593Smuzhiyun case NEXTHDR_ROUTING:
269*4882a593Smuzhiyun found_rhdr = 1;
270*4882a593Smuzhiyun break;
271*4882a593Smuzhiyun case NEXTHDR_DEST:
272*4882a593Smuzhiyun /*
273*4882a593Smuzhiyun * HAO MUST NOT appear more than once.
274*4882a593Smuzhiyun * XXX: It is better to try to find by the end of
275*4882a593Smuzhiyun * XXX: packet if HAO exists.
276*4882a593Smuzhiyun */
277*4882a593Smuzhiyun if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
278*4882a593Smuzhiyun net_dbg_ratelimited("mip6: hao exists already, override\n");
279*4882a593Smuzhiyun return offset;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (found_rhdr)
283*4882a593Smuzhiyun return offset;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun break;
286*4882a593Smuzhiyun default:
287*4882a593Smuzhiyun return offset;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun offset += ipv6_optlen(exthdr);
291*4882a593Smuzhiyun *nexthdr = &exthdr->nexthdr;
292*4882a593Smuzhiyun exthdr = (struct ipv6_opt_hdr *)(nh + offset);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun return offset;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
mip6_destopt_init_state(struct xfrm_state * x)298*4882a593Smuzhiyun static int mip6_destopt_init_state(struct xfrm_state *x)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun if (x->id.spi) {
301*4882a593Smuzhiyun pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
302*4882a593Smuzhiyun return -EINVAL;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
305*4882a593Smuzhiyun pr_info("%s: state's mode is not %u: %u\n",
306*4882a593Smuzhiyun __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
307*4882a593Smuzhiyun return -EINVAL;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
311*4882a593Smuzhiyun calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
312*4882a593Smuzhiyun sizeof(struct ipv6_destopt_hao);
313*4882a593Smuzhiyun WARN_ON(x->props.header_len != 24);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return 0;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /*
319*4882a593Smuzhiyun * Do nothing about destroying since it has no specific operation for
320*4882a593Smuzhiyun * destination options header unlike IPsec protocols.
321*4882a593Smuzhiyun */
mip6_destopt_destroy(struct xfrm_state * x)322*4882a593Smuzhiyun static void mip6_destopt_destroy(struct xfrm_state *x)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun static const struct xfrm_type mip6_destopt_type = {
327*4882a593Smuzhiyun .description = "MIP6DESTOPT",
328*4882a593Smuzhiyun .owner = THIS_MODULE,
329*4882a593Smuzhiyun .proto = IPPROTO_DSTOPTS,
330*4882a593Smuzhiyun .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
331*4882a593Smuzhiyun .init_state = mip6_destopt_init_state,
332*4882a593Smuzhiyun .destructor = mip6_destopt_destroy,
333*4882a593Smuzhiyun .input = mip6_destopt_input,
334*4882a593Smuzhiyun .output = mip6_destopt_output,
335*4882a593Smuzhiyun .reject = mip6_destopt_reject,
336*4882a593Smuzhiyun .hdr_offset = mip6_destopt_offset,
337*4882a593Smuzhiyun };
338*4882a593Smuzhiyun
mip6_rthdr_input(struct xfrm_state * x,struct sk_buff * skb)339*4882a593Smuzhiyun static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun const struct ipv6hdr *iph = ipv6_hdr(skb);
342*4882a593Smuzhiyun struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
343*4882a593Smuzhiyun int err = rt2->rt_hdr.nexthdr;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun spin_lock(&x->lock);
346*4882a593Smuzhiyun if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
347*4882a593Smuzhiyun !ipv6_addr_any((struct in6_addr *)x->coaddr))
348*4882a593Smuzhiyun err = -ENOENT;
349*4882a593Smuzhiyun spin_unlock(&x->lock);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun return err;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /* Routing Header type 2 is inserted.
355*4882a593Smuzhiyun * IP Header's dst address is replaced with Routing Header's Home Address.
356*4882a593Smuzhiyun */
mip6_rthdr_output(struct xfrm_state * x,struct sk_buff * skb)357*4882a593Smuzhiyun static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun struct ipv6hdr *iph;
360*4882a593Smuzhiyun struct rt2_hdr *rt2;
361*4882a593Smuzhiyun u8 nexthdr;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun skb_push(skb, -skb_network_offset(skb));
364*4882a593Smuzhiyun iph = ipv6_hdr(skb);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun nexthdr = *skb_mac_header(skb);
367*4882a593Smuzhiyun *skb_mac_header(skb) = IPPROTO_ROUTING;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun rt2 = (struct rt2_hdr *)skb_transport_header(skb);
370*4882a593Smuzhiyun rt2->rt_hdr.nexthdr = nexthdr;
371*4882a593Smuzhiyun rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
372*4882a593Smuzhiyun rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
373*4882a593Smuzhiyun rt2->rt_hdr.segments_left = 1;
374*4882a593Smuzhiyun memset(&rt2->reserved, 0, sizeof(rt2->reserved));
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun WARN_ON(rt2->rt_hdr.hdrlen != 2);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
379*4882a593Smuzhiyun spin_lock_bh(&x->lock);
380*4882a593Smuzhiyun memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
381*4882a593Smuzhiyun spin_unlock_bh(&x->lock);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun return 0;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
mip6_rthdr_offset(struct xfrm_state * x,struct sk_buff * skb,u8 ** nexthdr)386*4882a593Smuzhiyun static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
387*4882a593Smuzhiyun u8 **nexthdr)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun u16 offset = sizeof(struct ipv6hdr);
390*4882a593Smuzhiyun struct ipv6_opt_hdr *exthdr =
391*4882a593Smuzhiyun (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
392*4882a593Smuzhiyun const unsigned char *nh = skb_network_header(skb);
393*4882a593Smuzhiyun unsigned int packet_len = skb_tail_pointer(skb) -
394*4882a593Smuzhiyun skb_network_header(skb);
395*4882a593Smuzhiyun int found_rhdr = 0;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun *nexthdr = &ipv6_hdr(skb)->nexthdr;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun while (offset + 1 <= packet_len) {
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun switch (**nexthdr) {
402*4882a593Smuzhiyun case NEXTHDR_HOP:
403*4882a593Smuzhiyun break;
404*4882a593Smuzhiyun case NEXTHDR_ROUTING:
405*4882a593Smuzhiyun if (offset + 3 <= packet_len) {
406*4882a593Smuzhiyun struct ipv6_rt_hdr *rt;
407*4882a593Smuzhiyun rt = (struct ipv6_rt_hdr *)(nh + offset);
408*4882a593Smuzhiyun if (rt->type != 0)
409*4882a593Smuzhiyun return offset;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun found_rhdr = 1;
412*4882a593Smuzhiyun break;
413*4882a593Smuzhiyun case NEXTHDR_DEST:
414*4882a593Smuzhiyun if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
415*4882a593Smuzhiyun return offset;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (found_rhdr)
418*4882a593Smuzhiyun return offset;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun break;
421*4882a593Smuzhiyun default:
422*4882a593Smuzhiyun return offset;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun offset += ipv6_optlen(exthdr);
426*4882a593Smuzhiyun *nexthdr = &exthdr->nexthdr;
427*4882a593Smuzhiyun exthdr = (struct ipv6_opt_hdr *)(nh + offset);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun return offset;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
mip6_rthdr_init_state(struct xfrm_state * x)433*4882a593Smuzhiyun static int mip6_rthdr_init_state(struct xfrm_state *x)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun if (x->id.spi) {
436*4882a593Smuzhiyun pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
437*4882a593Smuzhiyun return -EINVAL;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
440*4882a593Smuzhiyun pr_info("%s: state's mode is not %u: %u\n",
441*4882a593Smuzhiyun __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
442*4882a593Smuzhiyun return -EINVAL;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun x->props.header_len = sizeof(struct rt2_hdr);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun return 0;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun /*
451*4882a593Smuzhiyun * Do nothing about destroying since it has no specific operation for routing
452*4882a593Smuzhiyun * header type 2 unlike IPsec protocols.
453*4882a593Smuzhiyun */
mip6_rthdr_destroy(struct xfrm_state * x)454*4882a593Smuzhiyun static void mip6_rthdr_destroy(struct xfrm_state *x)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun static const struct xfrm_type mip6_rthdr_type = {
459*4882a593Smuzhiyun .description = "MIP6RT",
460*4882a593Smuzhiyun .owner = THIS_MODULE,
461*4882a593Smuzhiyun .proto = IPPROTO_ROUTING,
462*4882a593Smuzhiyun .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
463*4882a593Smuzhiyun .init_state = mip6_rthdr_init_state,
464*4882a593Smuzhiyun .destructor = mip6_rthdr_destroy,
465*4882a593Smuzhiyun .input = mip6_rthdr_input,
466*4882a593Smuzhiyun .output = mip6_rthdr_output,
467*4882a593Smuzhiyun .hdr_offset = mip6_rthdr_offset,
468*4882a593Smuzhiyun };
469*4882a593Smuzhiyun
mip6_init(void)470*4882a593Smuzhiyun static int __init mip6_init(void)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun pr_info("Mobile IPv6\n");
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
475*4882a593Smuzhiyun pr_info("%s: can't add xfrm type(destopt)\n", __func__);
476*4882a593Smuzhiyun goto mip6_destopt_xfrm_fail;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
479*4882a593Smuzhiyun pr_info("%s: can't add xfrm type(rthdr)\n", __func__);
480*4882a593Smuzhiyun goto mip6_rthdr_xfrm_fail;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
483*4882a593Smuzhiyun pr_info("%s: can't add rawv6 mh filter\n", __func__);
484*4882a593Smuzhiyun goto mip6_rawv6_mh_fail;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun return 0;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun mip6_rawv6_mh_fail:
491*4882a593Smuzhiyun xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
492*4882a593Smuzhiyun mip6_rthdr_xfrm_fail:
493*4882a593Smuzhiyun xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
494*4882a593Smuzhiyun mip6_destopt_xfrm_fail:
495*4882a593Smuzhiyun return -EAGAIN;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
mip6_fini(void)498*4882a593Smuzhiyun static void __exit mip6_fini(void)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
501*4882a593Smuzhiyun pr_info("%s: can't remove rawv6 mh filter\n", __func__);
502*4882a593Smuzhiyun xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
503*4882a593Smuzhiyun xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun module_init(mip6_init);
507*4882a593Smuzhiyun module_exit(mip6_fini);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun MODULE_LICENSE("GPL");
510*4882a593Smuzhiyun MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
511*4882a593Smuzhiyun MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);
512