Sync with FreeBSD. This adds read-only support for zip and ISO9660.
[dragonfly.git] / contrib / ipfilter / mln_ipl.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 /*
7  * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
8  * its own major char number! Way cool patch!
9  */
10
11
12 #include <sys/param.h>
13
14 /*
15  * Post NetBSD 1.2 has the PFIL interface for packet filters.  This turns
16  * on those hooks.  We don't need any special mods with this!
17  */
18 #if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
19     (defined(NetBSD1_2) && NetBSD1_2 > 1)
20 # define NETBSD_PF
21 #endif
22
23 #include <sys/systm.h>
24 #include <sys/conf.h>
25 #include <sys/file.h>
26 #include <sys/stat.h>
27 #include <sys/proc.h>
28 #include <sys/uio.h>
29 #include <sys/kernel.h>
30 #include <sys/vnode.h>
31 #include <sys/namei.h>
32 #include <sys/malloc.h>
33 #include <sys/mount.h>
34 #include <sys/exec.h>
35 #include <sys/mbuf.h>
36 #include <net/if.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <net/route.h>
41 #include <netinet/ip_var.h>
42 #include <netinet/tcp.h>
43 #include <netinet/tcpip.h>
44 #include <sys/lkm.h>
45 #include "ipl.h"
46 #include "ip_compat.h"
47 #include "ip_fil.h"
48
49 #if !defined(__NetBSD_Version__) || __NetBSD_Version__ < 103050000
50 #define vn_lock(v,f) VOP_LOCK(v)
51 #endif
52
53 #if !defined(VOP_LEASE) && defined(LEASE_CHECK)
54 #define VOP_LEASE       LEASE_CHECK
55 #endif
56
57 #ifndef MIN
58 #define MIN(a,b)        (((a)<(b))?(a):(b))
59 #endif
60
61
62 extern  int     lkmenodev __P((void));
63
64 #if (NetBSD >= 199706) || (defined(OpenBSD) && (OpenBSD >= 200211))
65 int     if_ipl_lkmentry __P((struct lkm_table *, int, int));
66 #else
67 #if defined(OpenBSD)
68 int     if_ipl __P((struct lkm_table *, int, int));
69 #else
70 int     xxxinit __P((struct lkm_table *, int, int));
71 #endif
72 #endif
73 static  int     ipl_unload __P((void));
74 static  int     ipl_load __P((void));
75 static  int     ipl_remove __P((void));
76 static  int     iplaction __P((struct lkm_table *, int));
77 static  char    *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH,
78                                     NULL };
79
80
81 #if (defined(NetBSD1_0) && (NetBSD1_0 > 1)) || \
82     (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199511))
83 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
84 extern const struct cdevsw ipl_cdevsw;
85 # else
86 struct  cdevsw  ipldevsw = 
87 {
88         iplopen,                /* open */
89         iplclose,               /* close */
90         iplread,                /* read */
91         0,                      /* write */
92         iplioctl,               /* ioctl */
93         0,                      /* stop */
94         0,                      /* tty */
95         0,                      /* select */
96         0,                      /* mmap */
97         NULL                    /* strategy */
98 };
99 # endif
100 #else
101 struct  cdevsw  ipldevsw = 
102 {
103         iplopen,                /* open */
104         iplclose,               /* close */
105         iplread,                /* read */
106         (void *)nullop,         /* write */
107         iplioctl,               /* ioctl */
108         (void *)nullop,         /* stop */
109 #ifndef OpenBSD
110         (void *)nullop,         /* reset */
111 #endif
112         (void *)NULL,           /* tty */
113         (void *)nullop,         /* select */
114         (void *)nullop,         /* mmap */
115         NULL                    /* strategy */
116 };
117 #endif
118 int     ipl_major = 0;
119
120 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
121 MOD_DEV(IPL_VERSION, "ipl", NULL, -1, &ipl_cdevsw, -1);
122 #else
123 MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
124 #endif
125
126 extern int vd_unuseddev __P((void));
127 extern struct cdevsw cdevsw[];
128 extern int nchrdev;
129
130
131 #if (NetBSD >= 199706) || (defined(OpenBSD) && (OpenBSD >= 200211))
132 int if_ipl_lkmentry(lkmtp, cmd, ver)
133 #else
134 #if defined(OpenBSD)
135 int if_ipl(lkmtp, cmd, ver)
136 #else
137 int xxxinit(lkmtp, cmd, ver)
138 #endif
139 #endif
140 struct lkm_table *lkmtp;
141 int cmd, ver;
142 {
143         DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
144 }
145
146 #ifdef OpenBSD
147 int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */
148 #endif
149
150 static int iplaction(lkmtp, cmd)
151 struct lkm_table *lkmtp;
152 int cmd;
153 {
154         struct lkm_dev *args = lkmtp->private.lkm_dev;
155         int err = 0;
156 #if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000)
157         int i;
158 #endif
159
160         switch (cmd)
161         {
162         case LKM_E_LOAD :
163                 if (lkmexists(lkmtp))
164                         return EEXIST;
165
166 #if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000)
167                 for (i = 0; i < nchrdev; i++)
168                         if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev ||
169                             cdevsw[i].d_open == iplopen)
170                                 break;
171                 if (i == nchrdev) {
172                         printf("IP Filter: No free cdevsw slots\n");
173                         return ENODEV;
174                 }
175
176                 ipl_major = i;
177                 args->lkm_offset = i;   /* slot in cdevsw[] */
178 #else
179                 err = devsw_attach(args->lkm_devname,
180                                    args->lkm_bdev, &args->lkm_bdevmaj,
181                                    args->lkm_cdev, &args->lkm_cdevmaj);
182                 if (err != 0)
183                         return (err);
184                 ipl_major = args->lkm_cdevmaj;
185 #endif
186                 printf("IP Filter: loaded into slot %d\n", ipl_major);
187                 return ipl_load();
188         case LKM_E_UNLOAD :
189 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
190                 devsw_detach(args->lkm_bdev, args->lkm_cdev);
191                 args->lkm_bdevmaj = -1;
192                 args->lkm_cdevmaj = -1;
193 #endif
194                 err = ipl_unload();
195                 if (!err)
196                         printf("IP Filter: unloaded from slot %d\n",
197                                ipl_major);
198                 break;
199         case LKM_E_STAT :
200                 break;
201         default:
202                 err = EIO;
203                 break;
204         }
205         return err;
206 }
207
208
209 static int ipl_remove()
210 {
211         char *name;
212         struct nameidata nd;
213         int error, i;
214
215         for (i = 0; (name = ipf_devfiles[i]); i++) {
216                 NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
217                 if ((error = namei(&nd)))
218                         return (error);
219                 VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
220 #ifdef OpenBSD
221                 VOP_LOCK(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, curproc);
222 #else
223 # if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000)
224                 vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY);
225 # endif
226 #endif
227                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
228                 (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
229         }
230         return 0;
231 }
232
233
234 static int ipl_unload()
235 {
236         int error = 0;
237
238         /*
239          * Unloading - remove the filter rule check from the IP
240          * input/output stream.
241          */
242 #if defined(__NetBSD__)
243         error = ipl_disable();
244 #else
245         error = ipldetach();
246 #endif
247
248         if (!error)
249                 error = ipl_remove();
250         return error;
251 }
252
253
254 static int ipl_load()
255 {
256         struct nameidata nd;
257         struct vattr vattr;
258         int error = 0, fmode = S_IFCHR|0600, i;
259         char *name;
260
261         /*
262          * XXX Remove existing device nodes prior to creating new ones
263          * XXX using the assigned LKM device slot's major number.  In a
264          * XXX perfect world we could use the ones specified by cdevsw[].
265          */
266         (void)ipl_remove();
267
268         error = ipl_enable();
269         if (error)
270                 return error;
271
272         for (i = 0; (name = ipf_devfiles[i]); i++) {
273                 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
274                 if ((error = namei(&nd)))
275                         return error;
276                 if (nd.ni_vp != NULL) {
277                         VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
278                         if (nd.ni_dvp == nd.ni_vp)
279                                 vrele(nd.ni_dvp);
280                         else
281                                 vput(nd.ni_dvp);
282                         vrele(nd.ni_vp);
283                         return (EEXIST);
284                 }
285                 VATTR_NULL(&vattr);
286                 vattr.va_type = VCHR;
287                 vattr.va_mode = (fmode & 07777);
288                 vattr.va_rdev = (ipl_major << 8) | i;
289                 VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
290                 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
291                 if (error)
292                         return error;
293         }
294         return error;
295 }