Core integer types header file reorganization stage 1/2: Create and/or modify
[dragonfly.git] / sys / netproto / ipsec / xform_ipip.c
1 /*      $FreeBSD: src/sys/netipsec/xform_ipip.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $ */
2 /*      $DragonFly: src/sys/netproto/ipsec/xform_ipip.c,v 1.5 2003/11/09 02:22:36 dillon Exp $  */
3 /*      $OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
4 /*
5  * The authors of this code are John Ioannidis (ji@tla.org),
6  * Angelos D. Keromytis (kermit@csd.uch.gr) and
7  * Niels Provos (provos@physnet.uni-hamburg.de).
8  *
9  * The original version of this code was written by John Ioannidis
10  * for BSD/OS in Athens, Greece, in November 1995.
11  *
12  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
13  * by Angelos D. Keromytis.
14  *
15  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
16  * and Niels Provos.
17  *
18  * Additional features in 1999 by Angelos D. Keromytis.
19  *
20  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
21  * Angelos D. Keromytis and Niels Provos.
22  * Copyright (c) 2001, Angelos D. Keromytis.
23  *
24  * Permission to use, copy, and modify this software with or without fee
25  * is hereby granted, provided that this entire notice is included in
26  * all copies of any software which is or includes a copy or
27  * modification of this software.
28  * You may use this code under the GNU public license if you so wish. Please
29  * contribute changes back to the authors under this freer than GPL license
30  * so that we may further the use of strong encryption without limitations to
31  * all.
32  *
33  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
34  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
35  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
36  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
37  * PURPOSE.
38  */
39
40 /*
41  * IP-inside-IP processing
42  */
43 #include "opt_inet.h"
44 #include "opt_inet6.h"
45 #include "opt_random_ip_id.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/mbuf.h>
50 #include <sys/socket.h>
51 #include <sys/kernel.h>
52 #include <sys/protosw.h>
53 #include <sys/sysctl.h>
54
55 #include <net/if.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
58
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/in_var.h>
62 #include <netinet/ip.h>
63 #include <netinet/ip_ecn.h>
64 #include <netinet/ip_var.h>
65 #include <netinet/ip_encap.h>
66 #include <netinet/ipprotosw.h>
67
68 #include "ipsec.h"
69 #include "xform.h"
70
71 #include "ipip_var.h"
72
73 #ifdef MROUTING
74 #include <netinet/ip_mroute.h>
75 #endif
76
77 #ifdef INET6
78 #include <netinet/ip6.h>
79 #include "ipsec6.h"
80 #include <netinet6/ip6_ecn.h>
81 #include <netinet6/in6_var.h>
82 #include <netinet6/ip6protosw.h>
83 #endif
84
85 #include "key.h"
86 #include "key_debug.h"
87
88 #include <machine/stdarg.h>
89
90 typedef void    pr_in_input_t (struct mbuf *, int, int); /* XXX FIX THIS */
91
92 /*
93  * We can control the acceptance of IP4 packets by altering the sysctl
94  * net.inet.ipip.allow value.  Zero means drop them, all else is acceptance.
95  */
96 int     ipip_allow = 0;
97 struct  ipipstat ipipstat;
98
99 SYSCTL_DECL(_net_inet_ipip);
100 SYSCTL_INT(_net_inet_ipip, OID_AUTO,
101         ipip_allow,     CTLFLAG_RW,     &ipip_allow,    0, "");
102 SYSCTL_STRUCT(_net_inet_ipip, IPSECCTL_STATS,
103         stats,          CTLFLAG_RD,     &ipipstat,      ipipstat, "");
104
105 /* XXX IPCOMP */
106 #define M_IPSEC (M_AUTHIPHDR|M_AUTHIPDGM|M_DECRYPTED)
107
108 static void _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp);
109
110 #ifdef INET6
111 /*
112  * Really only a wrapper for ipip_input(), for use with IPv6.
113  */
114 int
115 ip4_input6(struct mbuf **m, int *offp, int proto)
116 {
117 #if 0
118         /* If we do not accept IP-in-IP explicitly, drop.  */
119         if (!ipip_allow && ((*m)->m_flags & M_IPSEC) == 0) {
120                 DPRINTF(("ip4_input6: dropped due to policy\n"));
121                 ipipstat.ipips_pdrops++;
122                 m_freem(*m);
123                 return IPPROTO_DONE;
124         }
125 #endif
126         _ipip_input(*m, *offp, NULL);
127         return IPPROTO_DONE;
128 }
129 #endif /* INET6 */
130
131 #ifdef INET
132 /*
133  * Really only a wrapper for ipip_input(), for use with IPv4.
134  */
135 void
136 ip4_input(struct mbuf *m, ...)
137 {
138         __va_list ap;
139         int iphlen;
140
141 #if 0
142         /* If we do not accept IP-in-IP explicitly, drop.  */
143         if (!ipip_allow && (m->m_flags & M_IPSEC) == 0) {
144                 DPRINTF(("ip4_input: dropped due to policy\n"));
145                 ipipstat.ipips_pdrops++;
146                 m_freem(m);
147                 return;
148         }
149 #endif
150         __va_start(ap, m);
151         iphlen = __va_arg(ap, int);
152         __va_end(ap);
153
154         _ipip_input(m, iphlen, NULL);
155 }
156 #endif /* INET */
157
158 /*
159  * ipip_input gets called when we receive an IP{46} encapsulated packet,
160  * either because we got it at a real interface, or because AH or ESP
161  * were being used in tunnel mode (in which case the rcvif element will
162  * contain the address of the encX interface associated with the tunnel.
163  */
164
165 static void
166 _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
167 {
168         struct sockaddr_in *sin;
169         struct ifnet *ifp;
170         struct ifaddr *ifa;
171         struct ifqueue *ifq = NULL;
172         struct ip *ipo;
173 #ifdef INET6
174         struct sockaddr_in6 *sin6;
175         struct ip6_hdr *ip6 = NULL;
176         u_int8_t itos;
177 #endif
178         u_int8_t nxt;
179         int isr;
180         u_int8_t otos;
181         u_int8_t v;
182         int hlen;
183
184         ipipstat.ipips_ipackets++;
185
186         m_copydata(m, 0, 1, &v);
187
188         switch (v >> 4) {
189 #ifdef INET
190         case 4:
191                 hlen = sizeof(struct ip);
192                 break;
193 #endif /* INET */
194 #ifdef INET6
195         case 6:
196                 hlen = sizeof(struct ip6_hdr);
197                 break;
198 #endif
199         default:
200                 DPRINTF(("_ipip_input: bad protocol version 0x%x (%u) "
201                         "for outer header\n", v, v>>4));
202                 ipipstat.ipips_family++;
203                 m_freem(m);
204                 return /* EAFNOSUPPORT */;
205         }
206
207         /* Bring the IP header in the first mbuf, if not there already */
208         if (m->m_len < hlen) {
209                 if ((m = m_pullup(m, hlen)) == NULL) {
210                         DPRINTF(("ipip_input: m_pullup (1) failed\n"));
211                         ipipstat.ipips_hdrops++;
212                         return;
213                 }
214         }
215
216         ipo = mtod(m, struct ip *);
217
218 #ifdef MROUTING
219         if (ipo->ip_v == IPVERSION && ipo->ip_p == IPPROTO_IPV4) {
220                 if (IN_MULTICAST(((struct ip *)((char *) ipo + iphlen))->ip_dst.s_addr)) {
221                         ipip_mroute_input (m, iphlen);
222                         return;
223                 }
224         }
225 #endif /* MROUTING */
226
227         /* Keep outer ecn field. */
228         switch (v >> 4) {
229 #ifdef INET
230         case 4:
231                 otos = ipo->ip_tos;
232                 break;
233 #endif /* INET */
234 #ifdef INET6
235         case 6:
236                 otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff;
237                 break;
238 #endif
239         default:
240                 panic("ipip_input: unknown ip version %u (outer)", v>>4);
241         }
242
243         /* Remove outer IP header */
244         m_adj(m, iphlen);
245
246         /* Sanity check */
247         if (m->m_pkthdr.len < sizeof(struct ip))  {
248                 ipipstat.ipips_hdrops++;
249                 m_freem(m);
250                 return;
251         }
252
253         m_copydata(m, 0, 1, &v);
254
255         switch (v >> 4) {
256 #ifdef INET
257         case 4:
258                 hlen = sizeof(struct ip);
259                 break;
260 #endif /* INET */
261
262 #ifdef INET6
263         case 6:
264                 hlen = sizeof(struct ip6_hdr);
265                 break;
266 #endif
267         default:
268                 DPRINTF(("_ipip_input: bad protocol version 0x%x (%u) "
269                         "for inner header\n", v, v>>4));
270                 ipipstat.ipips_family++;
271                 m_freem(m);
272                 return; /* EAFNOSUPPORT */
273         }
274
275         /*
276          * Bring the inner IP header in the first mbuf, if not there already.
277          */
278         if (m->m_len < hlen) {
279                 if ((m = m_pullup(m, hlen)) == NULL) {
280                         DPRINTF(("ipip_input: m_pullup (2) failed\n"));
281                         ipipstat.ipips_hdrops++;
282                         return;
283                 }
284         }
285
286         /*
287          * RFC 1853 specifies that the inner TTL should not be touched on
288          * decapsulation. There's no reason this comment should be here, but
289          * this is as good as any a position.
290          */
291
292         /* Some sanity checks in the inner IP header */
293         switch (v >> 4) {
294 #ifdef INET
295         case 4:
296                 ipo = mtod(m, struct ip *);
297                 nxt = ipo->ip_p;
298                 ip_ecn_egress(ip4_ipsec_ecn, &otos, &ipo->ip_tos);
299                 break;
300 #endif /* INET */
301 #ifdef INET6
302         case 6:
303                 ip6 = (struct ip6_hdr *) ipo;
304                 nxt = ip6->ip6_nxt;
305                 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
306                 ip_ecn_egress(ip6_ipsec_ecn, &otos, &itos);
307                 ip6->ip6_flow &= ~htonl(0xff << 20);
308                 ip6->ip6_flow |= htonl((u_int32_t) itos << 20);
309                 break;
310 #endif
311         default:
312                 panic("ipip_input: unknown ip version %u (inner)", v>>4);
313         }
314
315         /* Check for local address spoofing. */
316         if ((m->m_pkthdr.rcvif == NULL ||
317             !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) &&
318             ipip_allow != 2) {
319                 for (ifp = ifnet.tqh_first; ifp != 0;
320                      ifp = ifp->if_list.tqe_next) {
321                         for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
322                              ifa = ifa->ifa_list.tqe_next) {
323 #ifdef INET
324                                 if (ipo) {
325                                         if (ifa->ifa_addr->sa_family !=
326                                             AF_INET)
327                                                 continue;
328
329                                         sin = (struct sockaddr_in *) ifa->ifa_addr;
330
331                                         if (sin->sin_addr.s_addr ==
332                                             ipo->ip_src.s_addr) {
333                                                 ipipstat.ipips_spoof++;
334                                                 m_freem(m);
335                                                 return;
336                                         }
337                                 }
338 #endif /* INET */
339
340 #ifdef INET6
341                                 if (ip6) {
342                                         if (ifa->ifa_addr->sa_family !=
343                                             AF_INET6)
344                                                 continue;
345
346                                         sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
347
348                                         if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_src)) {
349                                                 ipipstat.ipips_spoof++;
350                                                 m_freem(m);
351                                                 return;
352                                         }
353
354                                 }
355 #endif /* INET6 */
356                         }
357                 }
358         }
359
360         /* Statistics */
361         ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen;
362
363         /*
364          * Interface pointer stays the same; if no IPsec processing has
365          * been done (or will be done), this will point to a normal
366          * interface. Otherwise, it'll point to an enc interface, which
367          * will allow a packet filter to distinguish between secure and
368          * untrusted packets.
369          */
370
371         switch (v >> 4) {
372 #ifdef INET
373         case 4:
374                 ifq = &ipintrq;
375                 isr = NETISR_IP;
376                 break;
377 #endif
378 #ifdef INET6
379         case 6:
380                 ifq = &ip6intrq;
381                 isr = NETISR_IPV6;
382                 break;
383 #endif
384         default:
385                 panic("ipip_input: should never reach here");
386         }
387
388         if (!IF_HANDOFF(ifq, m, NULL)) {
389                 ipipstat.ipips_qfull++;
390
391                 DPRINTF(("ipip_input: packet dropped because of full queue\n"));
392         } else {
393                 schednetisr(isr);
394         }
395 }
396
397 int
398 ipip_output(
399         struct mbuf *m,
400         struct ipsecrequest *isr,
401         struct mbuf **mp,
402         int skip,
403         int protoff
404 )
405 {
406         struct secasvar *sav;
407         u_int8_t tp, otos;
408         struct secasindex *saidx;
409         int error;
410 #ifdef INET
411         u_int8_t itos;
412         struct ip *ipo;
413 #endif /* INET */
414 #ifdef INET6
415         struct ip6_hdr *ip6, *ip6o;
416 #endif /* INET6 */
417
418         SPLASSERT(net, "ipip_output");
419
420         sav = isr->sav;
421         KASSERT(sav != NULL, ("ipip_output: null SA"));
422         KASSERT(sav->sah != NULL, ("ipip_output: null SAH"));
423
424         /* XXX Deal with empty TDB source/destination addresses. */
425
426         m_copydata(m, 0, 1, &tp);
427         tp = (tp >> 4) & 0xff;  /* Get the IP version number. */
428
429         saidx = &sav->sah->saidx;
430         switch (saidx->dst.sa.sa_family) {
431 #ifdef INET
432         case AF_INET:
433                 if (saidx->src.sa.sa_family != AF_INET ||
434                     saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
435                     saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) {
436                         DPRINTF(("ipip_output: unspecified tunnel endpoint "
437                             "address in SA %s/%08lx\n",
438                             ipsec_address(&saidx->dst),
439                             (u_long) ntohl(sav->spi)));
440                         ipipstat.ipips_unspec++;
441                         error = EINVAL;
442                         goto bad;
443                 }
444
445                 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
446                 if (m == 0) {
447                         DPRINTF(("ipip_output: M_PREPEND failed\n"));
448                         ipipstat.ipips_hdrops++;
449                         error = ENOBUFS;
450                         goto bad;
451                 }
452
453                 ipo = mtod(m, struct ip *);
454
455                 ipo->ip_v = IPVERSION;
456                 ipo->ip_hl = 5;
457                 ipo->ip_len = htons(m->m_pkthdr.len);
458                 ipo->ip_ttl = ip_defttl;
459                 ipo->ip_sum = 0;
460                 ipo->ip_src = saidx->src.sin.sin_addr;
461                 ipo->ip_dst = saidx->dst.sin.sin_addr;
462
463 #ifdef RANDOM_IP_ID
464                 ipo->ip_id = ip_randomid();
465 #else
466                 ipo->ip_id = htons(ip_id++);
467 #endif
468
469                 /* If the inner protocol is IP... */
470                 if (tp == IPVERSION) {
471                         /* Save ECN notification */
472                         m_copydata(m, sizeof(struct ip) +
473                             offsetof(struct ip, ip_tos),
474                             sizeof(u_int8_t), (caddr_t) &itos);
475
476                         ipo->ip_p = IPPROTO_IPIP;
477
478                         /*
479                          * We should be keeping tunnel soft-state and
480                          * send back ICMPs if needed.
481                          */
482                         m_copydata(m, sizeof(struct ip) +
483                             offsetof(struct ip, ip_off),
484                             sizeof(u_int16_t), (caddr_t) &ipo->ip_off);
485                         ipo->ip_off = ntohs(ipo->ip_off);
486                         ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK);
487                         ipo->ip_off = htons(ipo->ip_off);
488                 }
489 #ifdef INET6
490                 else if (tp == (IPV6_VERSION >> 4)) {
491                         u_int32_t itos32;
492
493                         /* Save ECN notification. */
494                         m_copydata(m, sizeof(struct ip) +
495                             offsetof(struct ip6_hdr, ip6_flow),
496                             sizeof(u_int32_t), (caddr_t) &itos32);
497                         itos = ntohl(itos32) >> 20;
498                         ipo->ip_p = IPPROTO_IPV6;
499                         ipo->ip_off = 0;
500                 }
501 #endif /* INET6 */
502                 else {
503                         goto nofamily;
504                 }
505
506                 otos = 0;
507                 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
508                 ipo->ip_tos = otos;
509                 break;
510 #endif /* INET */
511
512 #ifdef INET6
513         case AF_INET6:
514                 if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) ||
515                     saidx->src.sa.sa_family != AF_INET6 ||
516                     IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) {
517                         DPRINTF(("ipip_output: unspecified tunnel endpoint "
518                             "address in SA %s/%08lx\n",
519                             ipsec_address(&saidx->dst),
520                             (u_long) ntohl(sav->spi)));
521                         ipipstat.ipips_unspec++;
522                         error = ENOBUFS;
523                         goto bad;
524                 }
525
526                 /* scoped address handling */
527                 ip6 = mtod(m, struct ip6_hdr *);
528                 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
529                         ip6->ip6_src.s6_addr16[1] = 0;
530                 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
531                         ip6->ip6_dst.s6_addr16[1] = 0;
532
533                 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
534                 if (m == 0) {
535                         DPRINTF(("ipip_output: M_PREPEND failed\n"));
536                         ipipstat.ipips_hdrops++;
537                         *mp = NULL;
538                         error = ENOBUFS;
539                         goto bad;
540                 }
541
542                 /* Initialize IPv6 header */
543                 ip6o = mtod(m, struct ip6_hdr *);
544                 ip6o->ip6_flow = 0;
545                 ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
546                 ip6o->ip6_vfc |= IPV6_VERSION;
547                 ip6o->ip6_plen = htons(m->m_pkthdr.len);
548                 ip6o->ip6_hlim = ip_defttl;
549                 ip6o->ip6_dst = saidx->dst.sin6.sin6_addr;
550                 ip6o->ip6_src = saidx->src.sin6.sin6_addr;
551
552 #ifdef INET
553                 if (tp == IPVERSION) {
554                         /* Save ECN notification */
555                         m_copydata(m, sizeof(struct ip6_hdr) +
556                             offsetof(struct ip, ip_tos), sizeof(u_int8_t),
557                             (caddr_t) &itos);
558
559                         /* This is really IPVERSION. */
560                         ip6o->ip6_nxt = IPPROTO_IPIP;
561                 } else
562 #endif /* INET */
563                         if (tp == (IPV6_VERSION >> 4)) {
564                                 u_int32_t itos32;
565
566                                 /* Save ECN notification. */
567                                 m_copydata(m, sizeof(struct ip6_hdr) +
568                                     offsetof(struct ip6_hdr, ip6_flow),
569                                     sizeof(u_int32_t), (caddr_t) &itos32);
570                                 itos = ntohl(itos32) >> 20;
571
572                                 ip6o->ip6_nxt = IPPROTO_IPV6;
573                         } else {
574                                 goto nofamily;
575                         }
576
577                 otos = 0;
578                 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
579                 ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
580                 break;
581 #endif /* INET6 */
582
583         default:
584 nofamily:
585                 DPRINTF(("ipip_output: unsupported protocol family %u\n",
586                     saidx->dst.sa.sa_family));
587                 ipipstat.ipips_family++;
588                 error = EAFNOSUPPORT;           /* XXX diffs from openbsd */
589                 goto bad;
590         }
591
592         ipipstat.ipips_opackets++;
593         *mp = m;
594
595 #ifdef INET
596         if (saidx->dst.sa.sa_family == AF_INET) {
597 #if 0
598                 if (sav->tdb_xform->xf_type == XF_IP4)
599                         tdb->tdb_cur_bytes +=
600                             m->m_pkthdr.len - sizeof(struct ip);
601 #endif
602                 ipipstat.ipips_obytes += m->m_pkthdr.len - sizeof(struct ip);
603         }
604 #endif /* INET */
605
606 #ifdef INET6
607         if (saidx->dst.sa.sa_family == AF_INET6) {
608 #if 0
609                 if (sav->tdb_xform->xf_type == XF_IP4)
610                         tdb->tdb_cur_bytes +=
611                             m->m_pkthdr.len - sizeof(struct ip6_hdr);
612 #endif
613                 ipipstat.ipips_obytes +=
614                     m->m_pkthdr.len - sizeof(struct ip6_hdr);
615         }
616 #endif /* INET6 */
617
618         return 0;
619 bad:
620         if (m)
621                 m_freem(m), *mp = NULL;
622         return (error);
623 }
624
625 #ifdef FAST_IPSEC
626 static int
627 ipe4_init(struct secasvar *sav, struct xformsw *xsp)
628 {
629         sav->tdb_xform = xsp;
630         return 0;
631 }
632
633 static int
634 ipe4_zeroize(struct secasvar *sav)
635 {
636         sav->tdb_xform = NULL;
637         return 0;
638 }
639
640 static int
641 ipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
642 {
643         /* This is a rather serious mistake, so no conditional printing. */
644         printf("ipe4_input: should never be called\n");
645         if (m)
646                 m_freem(m);
647         return EOPNOTSUPP;
648 }
649
650 static struct xformsw ipe4_xformsw = {
651         XF_IP4,         0,              "IPv4 Simple Encapsulation",
652         ipe4_init,      ipe4_zeroize,   ipe4_input,     ipip_output,
653 };
654
655 extern struct domain inetdomain;
656 static struct ipprotosw ipe4_protosw[] = {
657 { SOCK_RAW,     &inetdomain,    IPPROTO_IPV4,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
658   (pr_in_input_t*) ip4_input,
659                 0,              0,              rip_ctloutput,
660   0,
661   0,            0,              0,              0,
662   &rip_usrreqs
663 },
664 #ifdef INET6
665 { SOCK_RAW,     &inetdomain,    IPPROTO_IPV6,   PR_ATOMIC|PR_ADDR|PR_LASTHDR,
666   (pr_in_input_t*) ip4_input,
667                 0,              0,              rip_ctloutput,
668   0,
669   0,            0,              0,              0,
670   &rip_usrreqs
671 }
672 #endif
673 };
674
675 /*
676  * Check the encapsulated packet to see if we want it
677  */
678 static int
679 ipe4_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
680 {
681         /*
682          * Only take packets coming from IPSEC tunnels; the rest
683          * must be handled by the gif tunnel code.  Note that we
684          * also return a minimum priority when we want the packet
685          * so any explicit gif tunnels take precedence.
686          */
687         return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0);
688 }
689
690 static void
691 ipe4_attach(void)
692 {
693         xform_register(&ipe4_xformsw);
694         /* attach to encapsulation framework */
695         /* XXX save return cookie for detach on module remove */
696         (void) encap_attach_func(AF_INET, -1,
697                 ipe4_encapcheck, (struct protosw*) &ipe4_protosw[0], NULL);
698 #ifdef INET6
699         (void) encap_attach_func(AF_INET6, -1,
700                 ipe4_encapcheck, (struct protosw*) &ipe4_protosw[1], NULL);
701 #endif
702 }
703 SYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL);
704 #endif  /* FAST_IPSEC */