Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xfrm6_input.c
Go to the documentation of this file.
1 /*
2  * xfrm6_input.c: based on net/ipv4/xfrm4_input.c
3  *
4  * Authors:
5  * Mitsuru KANDA @USAGI
6  * Kazunori MIYAZAWA @USAGI
7  * Kunihiro Ishiguro <[email protected]>
8  * YOSHIFUJI Hideaki @USAGI
9  * IPv6 support
10  */
11 
12 #include <linux/module.h>
13 #include <linux/string.h>
14 #include <linux/netfilter.h>
15 #include <linux/netfilter_ipv6.h>
16 #include <net/ipv6.h>
17 #include <net/xfrm.h>
18 
20 {
21  return xfrm6_extract_header(skb);
22 }
23 
25 {
26  XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
27  XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
28  return xfrm_input(skb, nexthdr, spi, 0);
29 }
31 
33 {
34  skb_network_header(skb)[IP6CB(skb)->nhoff] =
35  XFRM_MODE_SKB_CB(skb)->protocol;
36 
37 #ifndef CONFIG_NETFILTER
38  if (!async)
39  return 1;
40 #endif
41 
42  ipv6_hdr(skb)->payload_len = htons(skb->len);
43  __skb_push(skb, skb->data - skb_network_header(skb));
44 
47  return -1;
48 }
49 
50 int xfrm6_rcv(struct sk_buff *skb)
51 {
52  return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
53  0);
54 }
55 
57 
60 {
61  struct net *net = dev_net(skb->dev);
62  struct xfrm_state *x = NULL;
63  int i = 0;
64 
65  /* Allocate new secpath or COW existing one. */
66  if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
67  struct sec_path *sp;
68 
69  sp = secpath_dup(skb->sp);
70  if (!sp) {
72  goto drop;
73  }
74  if (skb->sp)
75  secpath_put(skb->sp);
76  skb->sp = sp;
77  }
78 
79  if (1 + skb->sp->len == XFRM_MAX_DEPTH) {
81  goto drop;
82  }
83 
84  for (i = 0; i < 3; i++) {
86 
87  switch (i) {
88  case 0:
89  dst = daddr;
90  src = saddr;
91  break;
92  case 1:
93  /* lookup state with wild-card source address */
94  dst = daddr;
95  src = (xfrm_address_t *)&in6addr_any;
96  break;
97  default:
98  /* lookup state with wild-card addresses */
99  dst = (xfrm_address_t *)&in6addr_any;
100  src = (xfrm_address_t *)&in6addr_any;
101  break;
102  }
103 
104  x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6);
105  if (!x)
106  continue;
107 
108  spin_lock(&x->lock);
109 
110  if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
111  likely(x->km.state == XFRM_STATE_VALID) &&
113  spin_unlock(&x->lock);
114  if (x->type->input(x, skb) > 0) {
115  /* found a valid state */
116  break;
117  }
118  } else
119  spin_unlock(&x->lock);
120 
121  xfrm_state_put(x);
122  x = NULL;
123  }
124 
125  if (!x) {
127  xfrm_audit_state_notfound_simple(skb, AF_INET6);
128  goto drop;
129  }
130 
131  skb->sp->xvec[skb->sp->len++] = x;
132 
133  spin_lock(&x->lock);
134 
135  x->curlft.bytes += skb->len;
136  x->curlft.packets++;
137 
138  spin_unlock(&x->lock);
139 
140  return 1;
141 
142 drop:
143  return -1;
144 }
145