Blame view

net/ipv6/xfrm6_mode_transport.c 3.27 KB
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * xfrm6_mode_transport.c - Transport mode encapsulation for IPv6.
   *
   * Copyright (C) 2002 USAGI/WIDE Project
   * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
   */
  
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/stringify.h>
  #include <net/dst.h>
  #include <net/ipv6.h>
  #include <net/xfrm.h>
c35fe4106   Steffen Klassert   xfrm: Add mode ha...
16
  #include <net/protocol.h>
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
17
18
19
20
21
  
  /* Add encapsulation header.
   *
   * The IP header and mutable extension headers will be moved forward to make
   * space for the encapsulation header.
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
22
   */
eb878e845   Jamal Hadi Salim   [IPSEC]: output m...
23
  static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
24
  {
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
25
26
27
  	struct ipv6hdr *iph;
  	u8 *prevhdr;
  	int hdr_len;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
28
  	iph = ipv6_hdr(skb);
f1bd7d659   Ilan Tayari   xfrm: Add encapsu...
29
  	skb_set_inner_transport_header(skb, skb_transport_offset(skb));
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
30

aee5adb43   Masahide NAKAMURA   [XFRM] STATE: Add...
31
  	hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
6e80ac5cc   Ben Hutchings   ipv6: xfrm: Handl...
32
33
  	if (hdr_len < 0)
  		return hdr_len;
007f0211a   Herbert Xu   [IPSEC]: Store IP...
34
  	skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data);
7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
35
  	skb_set_network_header(skb, -x->props.header_len);
37fedd3aa   Herbert Xu   [IPSEC]: Use IPv6...
36
  	skb->transport_header = skb->network_header + hdr_len;
7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
37
38
  	__skb_pull(skb, hdr_len);
  	memmove(ipv6_hdr(skb), iph, hdr_len);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
39
40
  	return 0;
  }
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
41
42
43
44
45
46
47
48
  /* Remove encapsulation header.
   *
   * The IP header will be moved over the top of the encapsulation header.
   *
   * On entry, skb->h shall point to where the IP header should be and skb->nh
   * shall be set to where the IP header currently is.  skb->data shall point
   * to the start of the payload.
   */
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
49
50
  static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
51
  	int ihl = skb->data - skb_transport_header(skb);
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
52

b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
53
  	if (skb->transport_header != skb->network_header) {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
54
55
  		memmove(skb_transport_header(skb),
  			skb_network_header(skb), ihl);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
56
  		skb->network_header = skb->transport_header;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
57
  	}
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
58
  	ipv6_hdr(skb)->payload_len = htons(skb->len + ihl -
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
59
  					   sizeof(struct ipv6hdr));
a95d9004f   Sowmini Varadhan   xfrm: reset trans...
60
  	skb_reset_transport_header(skb);
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
61
62
  	return 0;
  }
c35fe4106   Steffen Klassert   xfrm: Add mode ha...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
  						   struct sk_buff *skb,
  						   netdev_features_t features)
  {
  	const struct net_offload *ops;
  	struct sk_buff *segs = ERR_PTR(-EINVAL);
  	struct xfrm_offload *xo = xfrm_offload(skb);
  
  	skb->transport_header += x->props.header_len;
  	ops = rcu_dereference(inet6_offloads[xo->proto]);
  	if (likely(ops && ops->callbacks.gso_segment))
  		segs = ops->callbacks.gso_segment(skb, features);
  
  	return segs;
  }
  
  static void xfrm6_transport_xmit(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct xfrm_offload *xo = xfrm_offload(skb);
  
  	skb_reset_mac_len(skb);
  	pskb_pull(skb, skb->mac_len + sizeof(struct ipv6hdr) + x->props.header_len);
  
  	if (xo->flags & XFRM_GSO_SEGMENT) {
  		 skb_reset_transport_header(skb);
  		 skb->transport_header -= x->props.header_len;
  	}
  }
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
91
92
93
  static struct xfrm_mode xfrm6_transport_mode = {
  	.input = xfrm6_transport_input,
  	.output = xfrm6_transport_output,
c35fe4106   Steffen Klassert   xfrm: Add mode ha...
94
95
  	.gso_segment = xfrm4_transport_gso_segment,
  	.xmit = xfrm6_transport_xmit,
b59f45d0b   Herbert Xu   [IPSEC] xfrm: Abs...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  	.owner = THIS_MODULE,
  	.encap = XFRM_MODE_TRANSPORT,
  };
  
  static int __init xfrm6_transport_init(void)
  {
  	return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6);
  }
  
  static void __exit xfrm6_transport_exit(void)
  {
  	int err;
  
  	err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6);
  	BUG_ON(err);
  }
  
  module_init(xfrm6_transport_init);
  module_exit(xfrm6_transport_exit);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT);