]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_enc.c
This commit was generated by cvs2svn to compensate for changes in r162621,
[FreeBSD/FreeBSD.git] / sys / net / if_enc.c
1 /*-
2  * Copyright (c) 2006 The FreeBSD Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/mbuf.h>
35 #include <sys/module.h>
36 #include <machine/bus.h>
37 #include <sys/rman.h>
38 #include <sys/socket.h>
39 #include <sys/sockio.h>
40 #include <sys/sysctl.h>
41
42 #include <net/if.h>
43 #include <net/if_clone.h>
44 #include <net/if_types.h>
45 #include <net/pfil.h>
46 #include <net/route.h>
47 #include <net/netisr.h>
48 #include <net/bpf.h>
49 #include <net/bpfdesc.h>
50
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <netinet/ip_var.h>
55 #include <netinet/in_var.h>
56 #include "opt_inet6.h"
57
58 #ifdef INET6
59 #include <netinet/ip6.h>
60 #include <netinet6/ip6_var.h>
61 #endif
62
63 #include <netipsec/ipsec.h>
64
65 #define ENCMTU          (1024+512)
66
67 /* XXX this define must have the same value as in OpenBSD */
68 #define M_CONF          0x0400  /* payload was encrypted (ESP-transport) */
69 #define M_AUTH          0x0800  /* payload was authenticated (AH or ESP auth) */
70 #define M_AUTH_AH       0x2000  /* header was authenticated (AH) */
71
72 struct enchdr {
73         u_int32_t af;
74         u_int32_t spi;
75         u_int32_t flags;
76 };
77
78 static struct ifnet     *encif;
79 static struct mtx       enc_mtx;
80
81 struct enc_softc {
82         struct  ifnet *sc_ifp;
83 };
84
85 static int      enc_ioctl(struct ifnet *, u_long, caddr_t);
86 static int      enc_output(struct ifnet *ifp, struct mbuf *m,
87                     struct sockaddr *dst, struct rtentry *rt);
88 static int      enc_clone_create(struct if_clone *, int, caddr_t);
89 static void     enc_clone_destroy(struct ifnet *);
90
91 IFC_SIMPLE_DECLARE(enc, 1);
92
93 static void
94 enc_clone_destroy(struct ifnet *ifp)
95 {
96         KASSERT(ifp != encif, ("%s: destroying encif", __func__));
97
98         bpfdetach(ifp);
99         if_detach(ifp);
100         if_free(ifp);
101 }
102
103 static int
104 enc_clone_create(struct if_clone *ifc, int unit, caddr_t params)
105 {
106         struct ifnet *ifp;
107         struct enc_softc *sc;
108
109         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
110         ifp = sc->sc_ifp = if_alloc(IFT_ENC);
111         if (ifp == NULL) {
112                 free(sc, M_DEVBUF);
113                 return (ENOSPC);
114         }
115
116         if_initname(ifp, ifc->ifc_name, unit);
117         ifp->if_mtu = ENCMTU;
118         ifp->if_ioctl = enc_ioctl;
119         ifp->if_output = enc_output;
120         ifp->if_snd.ifq_maxlen = ifqmaxlen;
121         ifp->if_softc = sc;
122         if_attach(ifp);
123         bpfattach(ifp, DLT_ENC, sizeof(struct enchdr));
124
125         mtx_lock(&enc_mtx);
126         /* grab a pointer to enc0, ignore the rest */
127         if (encif == NULL)
128                 encif = ifp;
129         mtx_unlock(&enc_mtx);
130
131         return (0);
132 }
133
134 static int
135 enc_modevent(module_t mod, int type, void *data)
136 {
137         switch (type) {
138         case MOD_LOAD:
139                 mtx_init(&enc_mtx, "enc mtx", NULL, MTX_DEF);
140                 if_clone_attach(&enc_cloner);
141                 break;
142         case MOD_UNLOAD:
143                 printf("enc module unload - not possible for this module\n");
144                 return (EINVAL);
145         default:
146                 return (EOPNOTSUPP);
147         }
148         return (0);
149 }
150
151 static moduledata_t enc_mod = {
152         "enc",
153         enc_modevent,
154         0
155 };
156
157 DECLARE_MODULE(enc, enc_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
158
159 static int
160 enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
161     struct rtentry *rt)
162 {
163         m_freem(m);
164         return (0);
165 }
166
167 /*
168  * Process an ioctl request.
169  */
170 /* ARGSUSED */
171 static int
172 enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
173 {
174         int error = 0;
175
176         mtx_lock(&enc_mtx);
177
178         switch (cmd) {
179
180         case SIOCSIFFLAGS:
181                 if (ifp->if_flags & IFF_UP)
182                         ifp->if_drv_flags |= IFF_DRV_RUNNING;
183                 else
184                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
185
186                 break;
187
188         default:
189                 error = EINVAL;
190         }
191
192         mtx_unlock(&enc_mtx);
193         return (error);
194 }
195
196 int
197 ipsec_filter(struct mbuf **mp, int dir)
198 {
199         int error, i;
200         struct ip *ip;
201
202         KASSERT(encif != NULL, ("%s: encif is null", __func__));
203
204         if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0)
205                 return (0);
206
207         /* Skip pfil(9) if no filters are loaded */
208         if (!(PFIL_HOOKED(&inet_pfil_hook)
209 #ifdef INET6
210             || PFIL_HOOKED(&inet6_pfil_hook)
211 #endif
212             )) {
213                 return (0);
214         }
215
216         i = min((*mp)->m_pkthdr.len, max_protohdr);
217         if ((*mp)->m_len < i) {
218                 *mp = m_pullup(*mp, i);
219                 if (*mp == NULL) {
220                         printf("%s: m_pullup failed\n", __func__);
221                         return (-1);
222                 }
223         }
224
225         error = 0;
226         ip = mtod(*mp, struct ip *);
227         switch (ip->ip_v) {
228                 case 4:
229                         /*
230                          * before calling the firewall, swap fields the same as
231                          * IP does. here we assume the header is contiguous
232                          */
233                         ip->ip_len = ntohs(ip->ip_len);
234                         ip->ip_off = ntohs(ip->ip_off);
235
236                         error = pfil_run_hooks(&inet_pfil_hook, mp,
237                             encif, dir, NULL);
238
239                         if (*mp == NULL || error != 0)
240                                 break;
241
242                         /* restore byte ordering */
243                         ip = mtod(*mp, struct ip *);
244                         ip->ip_len = htons(ip->ip_len);
245                         ip->ip_off = htons(ip->ip_off);
246                         break;
247
248 #ifdef INET6
249                 case 6:
250                         error = pfil_run_hooks(&inet6_pfil_hook, mp,
251                             encif, dir, NULL);
252                         break;
253 #endif
254                 default:
255                         printf("%s: unknown IP version\n", __func__);
256         }
257
258         if (*mp == NULL)
259                 return (error);
260         if (error != 0)
261                 goto bad;
262
263         return (error);
264
265 bad:
266         m_freem(*mp);
267         *mp = NULL;
268         return (error);
269 }
270
271 void
272 ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af)
273 {
274         int flags;
275         struct enchdr hdr;
276
277         KASSERT(encif != NULL, ("%s: encif is null", __func__));
278         KASSERT(sav != NULL, ("%s: sav is null", __func__));
279
280         if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0)
281                 return;
282
283         if (encif->if_bpf) {
284                 flags = 0;
285                 if (sav->alg_enc != SADB_EALG_NONE)
286                         flags |= M_CONF;
287                 if (sav->alg_auth != SADB_AALG_NONE)
288                         flags |= M_AUTH;
289
290                 /*
291                  * We need to prepend the address family as a four byte
292                  * field.  Cons up a dummy header to pacify bpf.  This
293                  * is safe because bpf will only read from the mbuf
294                  * (i.e., it won't try to free it or keep a pointer a
295                  * to it).
296                  */
297                 hdr.af = af;
298                 hdr.spi = sav->spi;
299                 hdr.flags = flags;
300
301                 bpf_mtap2(encif->if_bpf, &hdr, sizeof(hdr), m);
302         }
303 }