Commit | Line | Data |
---|---|---|
33f11d16 TH |
1 | #include <linux/errno.h> |
2 | #include <linux/ip.h> | |
3 | #include <linux/kernel.h> | |
4 | #include <linux/module.h> | |
5 | #include <linux/skbuff.h> | |
6 | #include <linux/socket.h> | |
7 | #include <linux/types.h> | |
8 | #include <net/checksum.h> | |
9 | #include <net/ip.h> | |
10 | #include <net/ip6_fib.h> | |
11 | #include <net/lwtunnel.h> | |
12 | #include <net/protocol.h> | |
13 | #include <uapi/linux/ila.h> | |
14 | #include "ila.h" | |
15 | ||
16 | static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) | |
17 | { | |
18 | if (*(__be64 *)&ip6h->daddr == p->locator_match) | |
19 | return p->csum_diff; | |
20 | else | |
21 | return compute_csum_diff8((__be32 *)&ip6h->daddr, | |
22 | (__be32 *)&p->locator); | |
23 | } | |
24 | ||
25 | void update_ipv6_locator(struct sk_buff *skb, struct ila_params *p) | |
26 | { | |
27 | __wsum diff; | |
28 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
29 | size_t nhoff = sizeof(struct ipv6hdr); | |
30 | ||
31 | /* First update checksum */ | |
32 | switch (ip6h->nexthdr) { | |
33 | case NEXTHDR_TCP: | |
34 | if (likely(pskb_may_pull(skb, nhoff + sizeof(struct tcphdr)))) { | |
35 | struct tcphdr *th = (struct tcphdr *) | |
36 | (skb_network_header(skb) + nhoff); | |
37 | ||
38 | diff = get_csum_diff(ip6h, p); | |
39 | inet_proto_csum_replace_by_diff(&th->check, skb, | |
40 | diff, true); | |
41 | } | |
42 | break; | |
43 | case NEXTHDR_UDP: | |
44 | if (likely(pskb_may_pull(skb, nhoff + sizeof(struct udphdr)))) { | |
45 | struct udphdr *uh = (struct udphdr *) | |
46 | (skb_network_header(skb) + nhoff); | |
47 | ||
48 | if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { | |
49 | diff = get_csum_diff(ip6h, p); | |
50 | inet_proto_csum_replace_by_diff(&uh->check, skb, | |
51 | diff, true); | |
52 | if (!uh->check) | |
53 | uh->check = CSUM_MANGLED_0; | |
54 | } | |
55 | } | |
56 | break; | |
57 | case NEXTHDR_ICMP: | |
58 | if (likely(pskb_may_pull(skb, | |
59 | nhoff + sizeof(struct icmp6hdr)))) { | |
60 | struct icmp6hdr *ih = (struct icmp6hdr *) | |
61 | (skb_network_header(skb) + nhoff); | |
62 | ||
63 | diff = get_csum_diff(ip6h, p); | |
64 | inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb, | |
65 | diff, true); | |
66 | } | |
67 | break; | |
68 | } | |
69 | ||
70 | /* Now change destination address */ | |
71 | *(__be64 *)&ip6h->daddr = p->locator; | |
72 | } | |
73 | ||
74 | static int __init ila_init(void) | |
75 | { | |
76 | int ret; | |
77 | ||
78 | ret = ila_lwt_init(); | |
79 | ||
80 | if (ret) | |
81 | goto fail_lwt; | |
82 | ||
7f00feaf TH |
83 | ret = ila_xlat_init(); |
84 | if (ret) | |
85 | goto fail_xlat; | |
86 | ||
87 | return 0; | |
88 | fail_xlat: | |
89 | ila_lwt_fini(); | |
33f11d16 TH |
90 | fail_lwt: |
91 | return ret; | |
92 | } | |
93 | ||
94 | static void __exit ila_fini(void) | |
95 | { | |
7f00feaf | 96 | ila_xlat_fini(); |
33f11d16 TH |
97 | ila_lwt_fini(); |
98 | } | |
99 | ||
100 | module_init(ila_init); | |
101 | module_exit(ila_fini); | |
102 | MODULE_AUTHOR("Tom Herbert <tom@herbertland.com>"); | |
103 | MODULE_LICENSE("GPL"); |