Blame view

net/ipv6/xfrm6_mode_beet.c 3.08 KB
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  /*
   * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6.
   *
   * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
   *                    Miika Komu     <miika@iki.fi>
   *                    Herbert Xu     <herbert@gondor.apana.org.au>
   *                    Abhinav Pathak <abhinav.pathak@hiit.fi>
   *                    Jeff Ahrenholz <ahrenholz@gmail.com>
   */
  
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/stringify.h>
  #include <net/dsfield.h>
  #include <net/dst.h>
  #include <net/inet_ecn.h>
  #include <net/ipv6.h>
  #include <net/xfrm.h>
  
  /* Add encapsulation header.
   *
   * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
   * The following fields in it shall be filled in by x->type->output:
   *	payload_len
   *
   * On exit, skb->h will be set to the start of the encapsulation header to be
   * filled in by x->type->output and skb->nh will be set to the nextheader field
   * of the extension header directly preceding the encapsulation header, or in
   * its absence, that of the top IP header.  The value of skb->data will always
   * point to the top IP header.
   */
  static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct ipv6hdr *iph, *top_iph;
  	u8 *prevhdr;
  	int hdr_len;
  
  	skb_push(skb, x->props.header_len);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
41
  	iph = ipv6_hdr(skb);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
42
43
  
  	hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
ddc7b8e32   Arnaldo Carvalho de Melo   [SK_BUFF]: Some m...
44
45
  	skb_set_network_header(skb,
  			       (prevhdr - x->props.header_len) - skb->data);
967b05f64   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
46
  	skb_set_transport_header(skb, hdr_len);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
47
  	memmove(skb->data, iph, hdr_len);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
48
  	skb_reset_network_header(skb);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
49
  	top_iph = ipv6_hdr(skb);
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
50
51
  	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
  	skb->network_header += offsetof(struct ipv6hdr, nexthdr);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
52
53
54
55
56
57
58
59
60
61
  
  	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
  	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
  
  	return 0;
  }
  
  static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct ipv6hdr *ip6h;
39f69c6f9   Arnaldo Carvalho de Melo   [SK_BUFF] xfrm: U...
62
  	const unsigned char *old_mac;
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
63
64
65
66
67
68
69
  	int size = sizeof(struct ipv6hdr);
  	int err = -EINVAL;
  
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto out;
  
  	skb_push(skb, size);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
70
  	memmove(skb->data, skb_network_header(skb), size);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
71
  	skb_reset_network_header(skb);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
72

98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
73
  	old_mac = skb_mac_header(skb);
39f69c6f9   Arnaldo Carvalho de Melo   [SK_BUFF] xfrm: U...
74
  	skb_set_mac_header(skb, -skb->mac_len);
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
75
  	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
76

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
77
  	ip6h = ipv6_hdr(skb);
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  	ip6h->payload_len = htons(skb->len - size);
  	ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
  	ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
  	err = 0;
  out:
  	return err;
  }
  
  static struct xfrm_mode xfrm6_beet_mode = {
  	.input = xfrm6_beet_input,
  	.output = xfrm6_beet_output,
  	.owner = THIS_MODULE,
  	.encap = XFRM_MODE_BEET,
  };
  
  static int __init xfrm6_beet_init(void)
  {
  	return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
  }
  
  static void __exit xfrm6_beet_exit(void)
  {
  	int err;
  
  	err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
  	BUG_ON(err);
  }
  
  module_init(xfrm6_beet_init);
  module_exit(xfrm6_beet_exit);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET);