xref: /openbmc/linux/net/ipv6/xfrm6_input.c (revision 7785bba2)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * xfrm6_input.c: based on net/ipv4/xfrm4_input.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Authors:
51da177e4SLinus Torvalds  *	Mitsuru KANDA @USAGI
61da177e4SLinus Torvalds  *	Kazunori MIYAZAWA @USAGI
71da177e4SLinus Torvalds  *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
81da177e4SLinus Torvalds  *	YOSHIFUJI Hideaki @USAGI
91da177e4SLinus Torvalds  *		IPv6 support
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/string.h>
14b05e1066SPatrick McHardy #include <linux/netfilter.h>
15b05e1066SPatrick McHardy #include <linux/netfilter_ipv6.h>
161da177e4SLinus Torvalds #include <net/ipv6.h>
171da177e4SLinus Torvalds #include <net/xfrm.h>
181da177e4SLinus Torvalds 
19227620e2SHerbert Xu int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
20227620e2SHerbert Xu {
21227620e2SHerbert Xu 	return xfrm6_extract_header(skb);
22227620e2SHerbert Xu }
23227620e2SHerbert Xu 
2463c43787SNicolas Dichtel int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi,
2563c43787SNicolas Dichtel 		  struct ip6_tnl *t)
261da177e4SLinus Torvalds {
2763c43787SNicolas Dichtel 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
282fcb45b6SHerbert Xu 	XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
29716062fdSHerbert Xu 	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
30716062fdSHerbert Xu 	return xfrm_input(skb, nexthdr, spi, 0);
311da177e4SLinus Torvalds }
32716062fdSHerbert Xu EXPORT_SYMBOL(xfrm6_rcv_spi);
331da177e4SLinus Torvalds 
34716062fdSHerbert Xu int xfrm6_transport_finish(struct sk_buff *skb, int async)
35716062fdSHerbert Xu {
367785bba2SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
377785bba2SSteffen Klassert 
3860d5fcfbSHerbert Xu 	skb_network_header(skb)[IP6CB(skb)->nhoff] =
3960d5fcfbSHerbert Xu 		XFRM_MODE_SKB_CB(skb)->protocol;
4060d5fcfbSHerbert Xu 
410883ae0eSHerbert Xu #ifndef CONFIG_NETFILTER
420883ae0eSHerbert Xu 	if (!async)
430883ae0eSHerbert Xu 		return 1;
440883ae0eSHerbert Xu #endif
450883ae0eSHerbert Xu 
460660e03fSArnaldo Carvalho de Melo 	ipv6_hdr(skb)->payload_len = htons(skb->len);
47d56f90a7SArnaldo Carvalho de Melo 	__skb_push(skb, skb->data - skb_network_header(skb));
48b05e1066SPatrick McHardy 
497785bba2SSteffen Klassert 	if (xo && (xo->flags & XFRM_GRO)) {
507785bba2SSteffen Klassert 		skb_mac_header_rebuild(skb);
517785bba2SSteffen Klassert 		return -1;
527785bba2SSteffen Klassert 	}
537785bba2SSteffen Klassert 
5429a26a56SEric W. Biederman 	NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
5529a26a56SEric W. Biederman 		dev_net(skb->dev), NULL, skb, skb->dev, NULL,
56b05e1066SPatrick McHardy 		ip6_rcv_finish);
57b05e1066SPatrick McHardy 	return -1;
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds 
6063c43787SNicolas Dichtel int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t)
611da177e4SLinus Torvalds {
6233b5ecb8SHerbert Xu 	return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
6363c43787SNicolas Dichtel 			     0, t);
6463c43787SNicolas Dichtel }
6563c43787SNicolas Dichtel EXPORT_SYMBOL(xfrm6_rcv_tnl);
6663c43787SNicolas Dichtel 
6763c43787SNicolas Dichtel int xfrm6_rcv(struct sk_buff *skb)
6863c43787SNicolas Dichtel {
6963c43787SNicolas Dichtel 	return xfrm6_rcv_tnl(skb, NULL);
701da177e4SLinus Torvalds }
717159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv);
72fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
73fbd9a5b4SMasahide NAKAMURA 		     xfrm_address_t *saddr, u8 proto)
74fbd9a5b4SMasahide NAKAMURA {
7559c9940eSAlexey Dobriyan 	struct net *net = dev_net(skb->dev);
76fbd9a5b4SMasahide NAKAMURA 	struct xfrm_state *x = NULL;
77fbd9a5b4SMasahide NAKAMURA 	int i = 0;
78fbd9a5b4SMasahide NAKAMURA 
79b0fcee82SSteffen Klassert 	if (secpath_set(skb)) {
8059c9940eSAlexey Dobriyan 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
819473e1f6SMasahide NAKAMURA 		goto drop;
829473e1f6SMasahide NAKAMURA 	}
839473e1f6SMasahide NAKAMURA 
849473e1f6SMasahide NAKAMURA 	if (1 + skb->sp->len == XFRM_MAX_DEPTH) {
8559c9940eSAlexey Dobriyan 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
869473e1f6SMasahide NAKAMURA 		goto drop;
879473e1f6SMasahide NAKAMURA 	}
889473e1f6SMasahide NAKAMURA 
89fbd9a5b4SMasahide NAKAMURA 	for (i = 0; i < 3; i++) {
90fbd9a5b4SMasahide NAKAMURA 		xfrm_address_t *dst, *src;
91a002c6fdSYOSHIFUJI Hideaki 
92fbd9a5b4SMasahide NAKAMURA 		switch (i) {
93fbd9a5b4SMasahide NAKAMURA 		case 0:
94fbd9a5b4SMasahide NAKAMURA 			dst = daddr;
95fbd9a5b4SMasahide NAKAMURA 			src = saddr;
96fbd9a5b4SMasahide NAKAMURA 			break;
97fbd9a5b4SMasahide NAKAMURA 		case 1:
98fbd9a5b4SMasahide NAKAMURA 			/* lookup state with wild-card source address */
99fbd9a5b4SMasahide NAKAMURA 			dst = daddr;
100a002c6fdSYOSHIFUJI Hideaki 			src = (xfrm_address_t *)&in6addr_any;
101fbd9a5b4SMasahide NAKAMURA 			break;
102fbd9a5b4SMasahide NAKAMURA 		default:
103fbd9a5b4SMasahide NAKAMURA 			/* lookup state with wild-card addresses */
104a002c6fdSYOSHIFUJI Hideaki 			dst = (xfrm_address_t *)&in6addr_any;
105a002c6fdSYOSHIFUJI Hideaki 			src = (xfrm_address_t *)&in6addr_any;
106fbd9a5b4SMasahide NAKAMURA 			break;
107fbd9a5b4SMasahide NAKAMURA 		}
108fbd9a5b4SMasahide NAKAMURA 
109bd55775cSJamal Hadi Salim 		x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6);
110fbd9a5b4SMasahide NAKAMURA 		if (!x)
111fbd9a5b4SMasahide NAKAMURA 			continue;
112fbd9a5b4SMasahide NAKAMURA 
113fbd9a5b4SMasahide NAKAMURA 		spin_lock(&x->lock);
114fbd9a5b4SMasahide NAKAMURA 
115a002c6fdSYOSHIFUJI Hideaki 		if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
116a002c6fdSYOSHIFUJI Hideaki 		    likely(x->km.state == XFRM_STATE_VALID) &&
117a002c6fdSYOSHIFUJI Hideaki 		    !xfrm_state_check_expire(x)) {
118fbd9a5b4SMasahide NAKAMURA 			spin_unlock(&x->lock);
119a002c6fdSYOSHIFUJI Hideaki 			if (x->type->input(x, skb) > 0) {
120a002c6fdSYOSHIFUJI Hideaki 				/* found a valid state */
1219473e1f6SMasahide NAKAMURA 				break;
1229473e1f6SMasahide NAKAMURA 			}
123a002c6fdSYOSHIFUJI Hideaki 		} else
124a002c6fdSYOSHIFUJI Hideaki 			spin_unlock(&x->lock);
125a002c6fdSYOSHIFUJI Hideaki 
126a002c6fdSYOSHIFUJI Hideaki 		xfrm_state_put(x);
127a002c6fdSYOSHIFUJI Hideaki 		x = NULL;
128a002c6fdSYOSHIFUJI Hideaki 	}
1299473e1f6SMasahide NAKAMURA 
1309473e1f6SMasahide NAKAMURA 	if (!x) {
13159c9940eSAlexey Dobriyan 		XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
132afeb14b4SPaul Moore 		xfrm_audit_state_notfound_simple(skb, AF_INET6);
1339473e1f6SMasahide NAKAMURA 		goto drop;
1349473e1f6SMasahide NAKAMURA 	}
1359473e1f6SMasahide NAKAMURA 
1369473e1f6SMasahide NAKAMURA 	skb->sp->xvec[skb->sp->len++] = x;
1379473e1f6SMasahide NAKAMURA 
1389473e1f6SMasahide NAKAMURA 	spin_lock(&x->lock);
1399473e1f6SMasahide NAKAMURA 
140fbd9a5b4SMasahide NAKAMURA 	x->curlft.bytes += skb->len;
141fbd9a5b4SMasahide NAKAMURA 	x->curlft.packets++;
142fbd9a5b4SMasahide NAKAMURA 
143fbd9a5b4SMasahide NAKAMURA 	spin_unlock(&x->lock);
144fbd9a5b4SMasahide NAKAMURA 
145fbd9a5b4SMasahide NAKAMURA 	return 1;
1469473e1f6SMasahide NAKAMURA 
147fbd9a5b4SMasahide NAKAMURA drop:
148fbd9a5b4SMasahide NAKAMURA 	return -1;
149fbd9a5b4SMasahide NAKAMURA }
1507159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr);
151