~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/fou6.c

Version: ~ [ linux-6.6-rc1 ] ~ [ linux-6.5.2 ] ~ [ linux-6.4.15 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.52 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.131 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.194 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.256 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.294 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.325 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #include <linux/module.h>
  2 #include <linux/errno.h>
  3 #include <linux/socket.h>
  4 #include <linux/skbuff.h>
  5 #include <linux/ip.h>
  6 #include <linux/udp.h>
  7 #include <linux/icmpv6.h>
  8 #include <linux/types.h>
  9 #include <linux/kernel.h>
 10 #include <net/fou.h>
 11 #include <net/ip.h>
 12 #include <net/ip6_tunnel.h>
 13 #include <net/ip6_checksum.h>
 14 #include <net/protocol.h>
 15 #include <net/udp.h>
 16 #include <net/udp_tunnel.h>
 17 
 18 #if IS_ENABLED(CONFIG_IPV6_FOU_TUNNEL)
 19 
 20 static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
 21                            struct flowi6 *fl6, u8 *protocol, __be16 sport)
 22 {
 23         struct udphdr *uh;
 24 
 25         skb_push(skb, sizeof(struct udphdr));
 26         skb_reset_transport_header(skb);
 27 
 28         uh = udp_hdr(skb);
 29 
 30         uh->dest = e->dport;
 31         uh->source = sport;
 32         uh->len = htons(skb->len);
 33         udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb,
 34                       &fl6->saddr, &fl6->daddr, skb->len);
 35 
 36         *protocol = IPPROTO_UDP;
 37 }
 38 
 39 static int fou6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
 40                              u8 *protocol, struct flowi6 *fl6)
 41 {
 42         __be16 sport;
 43         int err;
 44         int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ?
 45                 SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
 46 
 47         err = __fou_build_header(skb, e, protocol, &sport, type);
 48         if (err)
 49                 return err;
 50 
 51         fou6_build_udp(skb, e, fl6, protocol, sport);
 52 
 53         return 0;
 54 }
 55 
 56 static int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
 57                              u8 *protocol, struct flowi6 *fl6)
 58 {
 59         __be16 sport;
 60         int err;
 61         int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ?
 62                 SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
 63 
 64         err = __gue_build_header(skb, e, protocol, &sport, type);
 65         if (err)
 66                 return err;
 67 
 68         fou6_build_udp(skb, e, fl6, protocol, sport);
 69 
 70         return 0;
 71 }
 72 
 73 static int gue6_err_proto_handler(int proto, struct sk_buff *skb,
 74                                   struct inet6_skb_parm *opt,
 75                                   u8 type, u8 code, int offset, __be32 info)
 76 {
 77         const struct inet6_protocol *ipprot;
 78 
 79         ipprot = rcu_dereference(inet6_protos[proto]);
 80         if (ipprot && ipprot->err_handler) {
 81                 if (!ipprot->err_handler(skb, opt, type, code, offset, info))
 82                         return 0;
 83         }
 84 
 85         return -ENOENT;
 86 }
 87 
 88 static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 89                     u8 type, u8 code, int offset, __be32 info)
 90 {
 91         int transport_offset = skb_transport_offset(skb);
 92         struct guehdr *guehdr;
 93         size_t len, optlen;
 94         int ret;
 95 
 96         len = sizeof(struct udphdr) + sizeof(struct guehdr);
 97         if (!pskb_may_pull(skb, transport_offset + len))
 98                 return -EINVAL;
 99 
100         guehdr = (struct guehdr *)&udp_hdr(skb)[1];
101 
102         switch (guehdr->version) {
103         case 0: /* Full GUE header present */
104                 break;
105         case 1: {
106                 /* Direct encasulation of IPv4 or IPv6 */
107                 skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr));
108 
109                 switch (((struct iphdr *)guehdr)->version) {
110                 case 4:
111                         ret = gue6_err_proto_handler(IPPROTO_IPIP, skb, opt,
112                                                      type, code, offset, info);
113                         goto out;
114                 case 6:
115                         ret = gue6_err_proto_handler(IPPROTO_IPV6, skb, opt,
116                                                      type, code, offset, info);
117                         goto out;
118                 default:
119                         ret = -EOPNOTSUPP;
120                         goto out;
121                 }
122         }
123         default: /* Undefined version */
124                 return -EOPNOTSUPP;
125         }
126 
127         if (guehdr->control)
128                 return -ENOENT;
129 
130         optlen = guehdr->hlen << 2;
131 
132         if (!pskb_may_pull(skb, transport_offset + len + optlen))
133                 return -EINVAL;
134 
135         guehdr = (struct guehdr *)&udp_hdr(skb)[1];
136         if (validate_gue_flags(guehdr, optlen))
137                 return -EINVAL;
138 
139         /* Handling exceptions for direct UDP encapsulation in GUE would lead to
140          * recursion. Besides, this kind of encapsulation can't even be
141          * configured currently. Discard this.
142          */
143         if (guehdr->proto_ctype == IPPROTO_UDP ||
144             guehdr->proto_ctype == IPPROTO_UDPLITE)
145                 return -EOPNOTSUPP;
146 
147         skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr));
148         ret = gue6_err_proto_handler(guehdr->proto_ctype, skb,
149                                      opt, type, code, offset, info);
150 
151 out:
152         skb_set_transport_header(skb, transport_offset);
153         return ret;
154 }
155 
156 
157 static const struct ip6_tnl_encap_ops fou_ip6tun_ops = {
158         .encap_hlen = fou_encap_hlen,
159         .build_header = fou6_build_header,
160         .err_handler = gue6_err,
161 };
162 
163 static const struct ip6_tnl_encap_ops gue_ip6tun_ops = {
164         .encap_hlen = gue_encap_hlen,
165         .build_header = gue6_build_header,
166         .err_handler = gue6_err,
167 };
168 
169 static int ip6_tnl_encap_add_fou_ops(void)
170 {
171         int ret;
172 
173         ret = ip6_tnl_encap_add_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU);
174         if (ret < 0) {
175                 pr_err("can't add fou6 ops\n");
176                 return ret;
177         }
178 
179         ret = ip6_tnl_encap_add_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE);
180         if (ret < 0) {
181                 pr_err("can't add gue6 ops\n");
182                 ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU);
183                 return ret;
184         }
185 
186         return 0;
187 }
188 
189 static void ip6_tnl_encap_del_fou_ops(void)
190 {
191         ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU);
192         ip6_tnl_encap_del_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE);
193 }
194 
195 #else
196 
197 static int ip6_tnl_encap_add_fou_ops(void)
198 {
199         return 0;
200 }
201 
202 static void ip6_tnl_encap_del_fou_ops(void)
203 {
204 }
205 
206 #endif
207 
208 static int __init fou6_init(void)
209 {
210         int ret;
211 
212         ret = ip6_tnl_encap_add_fou_ops();
213 
214         return ret;
215 }
216 
217 static void __exit fou6_fini(void)
218 {
219         ip6_tnl_encap_del_fou_ops();
220 }
221 
222 module_init(fou6_init);
223 module_exit(fou6_fini);
224 MODULE_AUTHOR("Tom Herbert <therbert@google.com>");
225 MODULE_LICENSE("GPL");
226 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp