We don't currently build ld-elf as binary for i386 and even if
[dragonfly.git] / contrib / ipfilter / ip_lfil.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #if !defined(lint)
7 static const char rcsid[] = "@(#)$Id: ip_lfil.c,v 2.6.2.5 2002/10/03 13:47:19 darrenr Exp $";
8 #endif
9
10 #if defined(KERNEL) && !defined(_KERNEL)
11 # define        _KERNEL
12 #endif
13 #include <sys/errno.h>
14 #include <sys/types.h>
15 #include <sys/param.h>
16 #include <sys/file.h>
17 #include <sys/ioctl.h>
18 #include <sys/time.h>
19 #include <sys/dir.h>
20 #include <sys/socket.h>
21 #ifndef _KERNEL
22 # include <stdio.h>
23 # include <string.h>
24 # include <stdlib.h>
25 # include <ctype.h>
26 #else
27 # include <linux/module.h>
28 #endif
29
30 #include <net/if.h>
31 #include <net/route.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <netinet/ip.h>
35 #include <netinet/tcp.h>
36 #include <netinet/udp.h>
37 #include <netinet/ip_icmp.h>
38 #ifndef _KERNEL
39 # include <syslog.h>
40 #endif
41 #include "netinet/ip_compat.h"
42 #include <netinet/tcpip.h>
43 #include "netinet/ip_fil.h"
44 #include "netinet/ip_nat.h"
45 #include "netinet/ip_proxy.h"
46 #include "netinet/ip_frag.h"
47 #include "netinet/ip_state.h"
48 #include "netinet/ip_auth.h"
49 #ifdef _KERNEL
50 #include <net/ip_forward.h>
51 #endif
52 #ifndef MIN
53 #define MIN(a,b)        (((a)<(b))?(a):(b))
54 #endif
55
56
57 #ifndef _KERNEL
58 # include "ipt.h"
59 static  struct  ifnet **ifneta = NULL;
60 static  int     nifs = 0;
61 #endif
62
63 int     fr_running = 0;
64 int     ipl_unreach = ICMP_UNREACH_FILTER;
65 u_long  ipl_frouteok[2] = {0, 0};
66
67 static  int     frzerostats __P((caddr_t));
68 static  void    frsync __P((void));
69 #if defined(__NetBSD__) || defined(__OpenBSD__)
70 static  int     frrequest __P((int, u_long, caddr_t, int));
71 #else
72 static  int     frrequest __P((int, u_long, caddr_t, int));
73 #endif
74 #ifdef  _KERNEL
75 static  int     (*fr_savep) __P((ip_t *, int, void *, int, mb_t **));
76 #else
77 int     ipllog __P((void));
78 void    init_ifp __P((void));
79 static int      no_output __P((mb_t *, struct ifnet *));
80 static int      write_output __P((mb_t *, struct ifnet *));
81 #endif
82
83 #ifdef  _KERNEL
84
85 int fr_precheck(struct iphdr *ip, struct device *dev, int out, struct device **ifp)
86 {
87         int hlen = ip->ihl << 2;
88
89         return fr_check((ip_t *)ip, hlen, dev, out, (mb_t **)ifp);
90 }
91
92
93 int iplattach()
94 {
95         char *defpass;
96         int s;
97
98         if (fr_running || (fr_checkp == fr_precheck)) {
99                 printk("IP Filter: already initialized\n");
100                 return EBUSY;
101         }
102
103         fr_running = 1;
104         bzero((char *)frcache, sizeof(frcache));
105         bzero((char *)nat_table, sizeof(nat_table));
106         fr_savep = fr_checkp;
107         fr_checkp = fr_precheck;
108
109 # ifdef IPFILTER_LOG
110         ipflog_init();
111 # endif
112         if (fr_pass & FR_PASS)
113                 defpass = "pass";
114         else if (fr_pass & FR_BLOCK)
115                 defpass = "block";
116         else
117                 defpass = "no-match -> block";
118
119         printk("IP Filter: initialized.  Default = %s all, Logging = %s\n",
120                 defpass,
121 # ifdef IPFILTER_LOG
122                 "enabled");
123 # else
124                 "disabled");
125 # endif
126         return 0;
127 }
128
129
130 /*
131  * Disable the filter by removing the hooks from the IP input/output
132  * stream.
133  */
134 int ipldetach()
135 {
136         int s, i = FR_INQUE|FR_OUTQUE;
137
138         if (!fr_running)
139         {
140                 printk("IP Filter: not initialized\n");
141                 return 0;
142         }
143
144         fr_checkp = fr_savep;
145         i = frflush(IPL_LOGIPF, i);
146         fr_running = 0;
147
148         ipfr_unload();
149         ip_natunload();
150         fr_stateunload();
151         fr_authunload();
152
153         printk("IP Filter: unloaded\n");
154
155         return 0;
156 }
157 #endif /* _KERNEL */
158
159
160 static  int     frzerostats(data)
161 caddr_t data;
162 {
163         struct  friostat        fio;
164         int error;
165
166         bcopy((char *)frstats, (char *)fio.f_st,
167                 sizeof(struct filterstats) * 2);
168         fio.f_fin[0] = ipfilter[0][0];
169         fio.f_fin[1] = ipfilter[0][1];
170         fio.f_fout[0] = ipfilter[1][0];
171         fio.f_fout[1] = ipfilter[1][1];
172         fio.f_acctin[0] = ipacct[0][0];
173         fio.f_acctin[1] = ipacct[0][1];
174         fio.f_acctout[0] = ipacct[1][0];
175         fio.f_acctout[1] = ipacct[1][1];
176         fio.f_active = fr_active;
177         fio.f_froute[0] = ipl_frouteok[0];
178         fio.f_froute[1] = ipl_frouteok[1];
179         error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio));
180         if (!error)
181                 bzero((char *)frstats, sizeof(*frstats) * 2);
182         return error;
183 }
184
185
186 /*
187  * Filter ioctl interface.
188  */
189 #if defined(_KERNEL)
190 int iplioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
191 {
192         int s;
193         caddr_t data = (caddr_t)arg;
194
195         int mode = file->f_mode;
196 #else
197 int iplioctl(dev_t dev, int cmd, caddr_t data, int mode)
198 {
199 #endif
200         int error = 0, unit = 0, tmp;
201
202 #ifdef  _KERNEL
203         unit = GET_MINOR(inode->i_rdev);
204         if ((IPL_LOGMAX < unit) || (unit < 0))
205                 return ENXIO;
206 #endif
207
208         if (unit == IPL_LOGNAT) {
209                 error = nat_ioctl(data, cmd, mode);
210                 return error;
211         }
212         if (unit == IPL_LOGSTATE) {
213                 error = fr_state_ioctl(data, cmd, mode);
214                 return error;
215         }
216
217         switch (cmd) {
218         case FIONREAD :
219 #ifdef IPFILTER_LOG
220                 error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], data,
221                                sizeof(iplused[IPL_LOGIPF]));
222 #endif
223                 break;
224 #if !defined(IPFILTER_LKM) && defined(_KERNEL)
225         case SIOCFRENB :
226         {
227                 u_int   enable;
228
229                 if (!(mode & FWRITE))
230                         error = EPERM;
231                 else {
232                         error = IRCOPY(data, (caddr_t)&enable, sizeof(enable));
233                         if (error)
234                                 break;
235                         if (enable)
236                                 error = iplattach();
237                         else
238                                 error = ipldetach();
239                 }
240                 break;
241         }
242 #endif
243         case SIOCSETFF :
244                 if (!(mode & FWRITE))
245                         error = EPERM;
246                 else
247                         error = IRCOPY(data, (caddr_t)&fr_flags,
248                                        sizeof(fr_flags));
249                 break;
250         case SIOCGETFF :
251                 error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
252                 break;
253         case SIOCINAFR :
254         case SIOCRMAFR :
255         case SIOCADAFR :
256         case SIOCZRLST :
257                 if (!(mode & FWRITE))
258                         error = EPERM;
259                 else
260                         error = frrequest(unit, cmd, data, fr_active);
261                 break;
262         case SIOCINIFR :
263         case SIOCRMIFR :
264         case SIOCADIFR :
265                 if (!(mode & FWRITE))
266                         error = EPERM;
267                 else
268                         error = frrequest(unit, cmd, data, 1 - fr_active);
269                 break;
270         case SIOCSWAPA :
271                 if (!(mode & FWRITE))
272                         error = EPERM;
273                 else {
274                         bzero((char *)frcache, sizeof(frcache[0]) * 2);
275                         *(u_int *)data = fr_active;
276                         fr_active = 1 - fr_active;
277                 }
278                 break;
279         case SIOCGETFS :
280         {
281                 struct  friostat        fio;
282
283                 bcopy((char *)frstats, (char *)fio.f_st,
284                         sizeof(struct filterstats) * 2);
285                 fio.f_fin[0] = ipfilter[0][0];
286                 fio.f_fin[1] = ipfilter[0][1];
287                 fio.f_fout[0] = ipfilter[1][0];
288                 fio.f_fout[1] = ipfilter[1][1];
289                 fio.f_acctin[0] = ipacct[0][0];
290                 fio.f_acctin[1] = ipacct[0][1];
291                 fio.f_acctout[0] = ipacct[1][0];
292                 fio.f_acctout[1] = ipacct[1][1];
293                 fio.f_auth = ipauth;
294                 fio.f_active = fr_active;
295                 fio.f_froute[0] = ipl_frouteok[0];
296                 fio.f_froute[1] = ipl_frouteok[1];
297                 error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio));
298                 break;
299         }
300         case    SIOCFRZST :
301                 if (!(mode & FWRITE))
302                         error = EPERM;
303                 else
304                         error = frzerostats(data);
305                 break;
306         case    SIOCIPFFL :
307                 if (!(mode & FWRITE))
308                         error = EPERM;
309                 else {
310                         error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp));
311                         if (!error) {
312                                 tmp = frflush(unit, tmp);
313                                 error = IWCOPY((caddr_t)&tmp, data,
314                                                sizeof(tmp));
315                         }
316                 }
317                 break;
318 #ifdef  IPFILTER_LOG
319         case    SIOCIPFFB :
320                 if (!(mode & FWRITE))
321                         error = EPERM;
322                 else
323                         *(int *)data = ipflog_clear(unit);
324                 break;
325 #endif /* IPFILTER_LOG */
326         case SIOCGFRST :
327                 error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data,
328                                sizeof(ipfrstat_t));
329                 break;
330         case SIOCFRSYN :
331                 if (!(mode & FWRITE))
332                         error = EPERM;
333                 else {
334 #if defined(_KERNEL) && defined(__sgi)
335                         ipfsync();
336 #endif
337                         frsync();
338                 }
339                 break;
340         default :
341                 error = EINVAL;
342                 break;
343         }
344         return error;
345 }
346
347
348 static void frsync()
349 {
350 #ifdef _KERNEL
351         struct device *dev;
352
353         for (dev = dev_base; dev; dev = dev->next)
354                 ip_natsync(dev);
355 #endif
356 }
357
358
359 static int frrequest(unit, req, data, set)
360 int unit;
361 u_long req;
362 int set;
363 caddr_t data;
364 {
365         register frentry_t *fp, *f, **fprev;
366         register frentry_t **ftail;
367         frentry_t frd;
368         frdest_t *fdp;
369         frgroup_t *fg = NULL;
370         int error = 0, in;
371         u_int group;
372
373         fp = &frd;
374         error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp));
375         if (error)
376                 return error;
377
378         /*
379          * Check that the group number does exist and that if a head group
380          * has been specified, doesn't exist.
381          */
382         if (fp->fr_grhead &&
383             fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL))
384                 return EEXIST;
385         if (fp->fr_group &&
386             !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL))
387                 return ESRCH;
388
389         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
390
391         if (unit == IPL_LOGAUTH)
392                 ftail = fprev = &ipauth;
393         else if (fp->fr_flags & FR_ACCOUNT)
394                 ftail = fprev = &ipacct[in][set];
395         else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
396                 ftail = fprev = &ipfilter[in][set];
397         else
398                 return ESRCH;
399
400         if ((group = fp->fr_group)) {
401                 if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL)))
402                         return ESRCH;
403                 ftail = fprev = fg->fg_start;
404         }
405
406         bzero((char *)frcache, sizeof(frcache[0]) * 2);
407
408         if (*fp->fr_ifname) {
409                 fp->fr_ifa = GETUNIT(fp->fr_ifname, fp->fr_ip.fi_v);
410                 if (!fp->fr_ifa)
411                         fp->fr_ifa = (void *)-1;
412         }
413
414         fdp = &fp->fr_dif;
415         fp->fr_flags &= ~FR_DUP;
416         if (*fdp->fd_ifname) {
417                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_ip.fi_v);
418                 if (!fdp->fd_ifp)
419                         fdp->fd_ifp = (struct ifnet *)-1;
420                 else
421                         fp->fr_flags |= FR_DUP;
422         }
423
424         fdp = &fp->fr_tif;
425         if (*fdp->fd_ifname) {
426                 fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_ip.fi_v);
427                 if (!fdp->fd_ifp)
428                         fdp->fd_ifp = (struct ifnet *)-1;
429         }
430
431         /*
432          * Look for a matching filter rule, but don't include the next or
433          * interface pointer in the comparison (fr_next, fr_ifa).
434          */
435         for (; (f = *ftail); ftail = &f->fr_next)
436                 if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip,
437                          FR_CMPSIZ) == 0)
438                         break;
439
440         /*
441          * If zero'ing statistics, copy current to caller and zero.
442          */
443         if (req == SIOCZRLST) {
444                 if (!f)
445                         return ESRCH;
446                 error = IWCOPYPTR((caddr_t)f, data, sizeof(*f));
447                 if (error)
448                         return error;
449                 f->fr_hits = 0;
450                 f->fr_bytes = 0;
451                 return 0;
452         }
453
454         if (!f) {
455                 if (req == SIOCINAFR || req == SIOCINIFR) {
456                         ftail = fprev;
457                         if (fp->fr_hits) {
458                                 while (--fp->fr_hits && (f = *ftail)) {
459                                         ftail = &f->fr_next;
460                                 }
461                         }
462                 }
463                 f = NULL;
464         }
465
466         if (req == SIOCRMAFR || req == SIOCRMIFR) {
467                 if (!f)
468                         error = ESRCH;
469                 else {
470                         if (f->fr_ref > 1)
471                                 return EBUSY;
472                         if (fg && fg->fg_head)
473                                 fg->fg_head->fr_ref--;
474                         if (unit == IPL_LOGAUTH)
475                                 return fr_auth_ioctl(data, mode, req, f, ftail);
476                         if (f->fr_grhead)
477                                 fr_delgroup((u_int)f->fr_grhead, fp->fr_flags,
478                                             unit, set);
479                         fixskip(fprev, f, -1);
480                         *ftail = f->fr_next;
481                         KFREE(f);
482                 }
483         } else {
484                 if (f)
485                         error = EEXIST;
486                 else {
487                         if (unit == IPL_LOGAUTH)
488                                 return fr_auth_ioctl(data, mode, req, f, ftail);
489                         KMALLOC(f, frentry_t *);
490                         if (f != NULL) {
491                                 if (fg && fg->fg_head)
492                                         fg->fg_head->fr_ref++;
493                                 bcopy((char *)fp, (char *)f, sizeof(*f));
494                                 f->fr_ref = 1;
495                                 f->fr_hits = 0;
496                                 f->fr_next = *ftail;
497                                 *ftail = f;
498                                 if (req == SIOCINIFR || req == SIOCINAFR)
499                                         fixskip(fprev, f, 1);
500                                 f->fr_grp = NULL;
501                                 if ((group = f->fr_grhead))
502                                         fg = fr_addgroup(group, f, unit, set);
503                         } else
504                                 error = ENOMEM;
505                 }
506         }
507         return (error);
508 }
509
510
511 #ifdef  _KERNEL
512 /*
513  * routines below for saving IP headers to buffer
514  */
515 int iplopen(struct inode *inode, struct file *file)
516 {
517         u_int min = GET_MINOR(inode->i_rdev);
518
519         if (IPL_LOGMAX < min)
520                 min = ENXIO;
521         else {
522                 MOD_INC_USE_COUNT;
523                 min = 0;
524         }
525         return min;
526 }
527
528
529 void iplclose(struct inode *inode, struct file *file)
530 {
531         u_int   min = GET_MINOR(inode->i_rdev);
532
533         if (IPL_LOGMAX >= min) {
534                 MOD_DEC_USE_COUNT;
535         }
536 }
537
538 /*
539  * iplread/ipllog
540  * both of these must operate with at least splnet() lest they be
541  * called during packet processing and cause an inconsistancy to appear in
542  * the filter lists.
543  */
544 int iplread(struct inode *inode, struct file *file, char *buf, int nbytes)
545 {
546         struct uio uiob, *uio = &uiob;
547
548         uio->uio_buf = buf;
549         uio->uio_resid = nbytes;
550 #  ifdef IPFILTER_LOG
551         return ipflog_read(GET_MINOR(inode->i_rdev), uio);
552 #  else
553         return ENXIO;
554 #  endif
555 }
556
557
558 /*
559  * send_reset - this could conceivably be a call to tcp_respond(), but that
560  * requires a large amount of setting up and isn't any more efficient.
561  */
562 int send_reset(ti, ifp)
563 struct tcpiphdr *ti;
564 struct ifnet *ifp;
565 {
566         tcphdr_t *tcp;
567         int tlen = 0;
568         ip_t *ip;
569         mb_t *m;
570
571         if (ti->ti_flags & TH_RST)
572                 return -1;              /* feedback loop */
573
574         m = alloc_skb(sizeof(tcpiphdr_t), GFP_ATOMIC);
575         if (m == NULL)
576                 return -1;
577
578         if (ti->ti_flags & TH_SYN)
579                 tlen = 1;
580
581         m->dev = ifp;
582         m->csum = 0;
583         ip = mtod(m, ip_t *);
584         m->h.iph = ip;
585         m->ip_hdr = NULL;
586         m->m_len = sizeof(tcpiphdr_t);
587         tcp = (tcphdr_t *)((char *)ip + sizeof(ip_t));
588         bzero((char *)ip, sizeof(tcpiphdr_t));
589  
590         ip->ip_v = IPVERSION;
591         ip->ip_hl = sizeof(ip_t) >> 2;
592         ip->ip_tos = ((ip_t *)ti)->ip_tos;
593         ip->ip_p = ((ip_t *)ti)->ip_p;
594         ip->ip_id = ((ip_t *)ti)->ip_id;
595         ip->ip_len = htons(sizeof(tcpiphdr_t));
596         ip->ip_ttl = 127;
597         ip->ip_src.s_addr = ti->ti_dst.s_addr;
598         ip->ip_dst.s_addr = ti->ti_src.s_addr;
599         tcp->th_dport = ti->ti_sport;
600         tcp->th_sport = ti->ti_dport;
601         tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen);
602         tcp->th_off = sizeof(tcphdr_t) >> 2;
603         tcp->th_flags = TH_RST|TH_ACK;
604  
605         ip->ip_sum = 0;
606         ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(ip_t));
607         tcp->th_sum = fr_tcpsum(m, ip, tcp);
608         return ip_forward(m, NULL, IPFWD_NOTTLDEC, ip->ip_dst.s_addr);
609 }
610
611
612 size_t mbufchainlen(m0)
613 register mb_t *m0;
614 {
615         register size_t len = 0;
616
617         for (; m0; m0 = m0->m_next)
618                 len += m0->m_len;
619         return len;
620 }
621
622
623 void ipfr_fastroute(m0, fin, fdp)
624 mb_t *m0;
625 fr_info_t *fin;
626 frdest_t *fdp;
627 {
628 #if notyet
629         register ip_t *ip, *mhip;
630         register mb_t *m = m0;
631         register struct route *ro;
632         struct ifnet *ifp = fdp->fd_ifp;
633         int len, off, error = 0;
634         int hlen = fin->fin_hlen;
635         struct route iproute;
636         struct sockaddr_in *dst;
637
638         ip = mtod(m0, ip_t *);
639         /*
640          * Route packet.
641          */
642         ro = &iproute;
643         bzero((caddr_t)ro, sizeof (*ro));
644         dst = (struct sockaddr_in *)&ro->ro_dst;
645         dst->sin_family = AF_INET;
646         dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;
647         /*
648          * XXX -allocate route here
649          */
650         if (!ifp) {
651                 if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) {
652                         error = -2;
653                         goto bad;
654                 }
655                 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
656                         if (in_localaddr(ip->ip_dst))
657                                 error = EHOSTUNREACH;
658                         else
659                                 error = ENETUNREACH;
660                         goto bad;
661                 }
662                 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
663                         dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
664         }
665         ro->ro_rt->rt_use++;
666
667         /*
668          * For input packets which are being "fastrouted", they won't
669          * go back through output filtering and miss their chance to get
670          * NAT'd.
671          */
672         (void) ip_natout(ip, hlen, fin);
673         if (fin->fin_out)
674                 ip->ip_sum = 0;
675         /*
676          * If small enough for interface, can just send directly.
677          */
678         if (ip->ip_len <= ifp->if_mtu) {
679 # ifndef sparc
680                 ip->ip_id = htons(ip->ip_id);
681                 ip->ip_len = htons(ip->ip_len);
682                 ip->ip_off = htons(ip->ip_off);
683 # endif
684                 if (!ip->ip_sum)
685                         ip->ip_sum = in_cksum(m, hlen);
686                 error = (*ifp->hard_start_xmit)(m, ifp, m);
687                 goto done;
688         }
689         /*
690          * Too large for interface; fragment if possible.
691          * Must be able to put at least 8 bytes per fragment.
692          */
693         if (ip->ip_off & IP_DF) {
694                 error = EMSGSIZE;
695                 goto bad;
696         }
697         len = (ifp->if_mtu - hlen) &~ 7;
698         if (len < 8) {
699                 error = EMSGSIZE;
700                 goto bad;
701         }
702
703     {
704         int mhlen, firstlen = len;
705         mb_t **mnext = &m->m_act;
706
707         /*
708          * Loop through length of segment after first fragment,
709          * make new header and copy data of each part and link onto chain.
710          */
711         m0 = m;
712         mhlen = sizeof (struct ip);
713         for (off = hlen + len; off < ip->ip_len; off += len) {
714                 MGET(m, M_DONTWAIT, MT_HEADER);
715                 if (m == 0) {
716                         error = ENOBUFS;
717                         goto bad;
718                 }
719                 m->m_data += max_linkhdr;
720                 mhip = mtod(m, struct ip *);
721                 bcopy((char *)ip, (char *)mhip, sizeof(*ip));
722                 if (hlen > sizeof (struct ip)) {
723                         mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
724                         mhip->ip_hl = mhlen >> 2;
725                 }
726                 m->m_len = mhlen;
727                 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
728                 if (ip->ip_off & IP_MF)
729                         mhip->ip_off |= IP_MF;
730                 if (off + len >= ip->ip_len)
731                         len = ip->ip_len - off;
732                 else
733                         mhip->ip_off |= IP_MF;
734                 mhip->ip_len = htons((u_short)(len + mhlen));
735                 m->m_next = m_copy(m0, off, len);
736                 if (m->m_next == 0) {
737                         error = ENOBUFS;        /* ??? */
738                         goto sendorfree;
739                 }
740 # ifndef sparc
741                 mhip->ip_off = htons((u_short)mhip->ip_off);
742 # endif
743                 mhip->ip_sum = 0;
744                 mhip->ip_sum = in_cksum(m, mhlen);
745                 *mnext = m;
746                 mnext = &m->m_act;
747         }
748         /*
749          * Update first fragment by trimming what's been copied out
750          * and updating header, then send each fragment (in order).
751          */
752         m_adj(m0, hlen + firstlen - ip->ip_len);
753         ip->ip_len = htons((u_short)(hlen + firstlen));
754         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
755         ip->ip_sum = 0;
756         ip->ip_sum = in_cksum(m0, hlen);
757 sendorfree:
758         for (m = m0; m; m = m0) {
759                 m0 = m->m_act;
760                 m->m_act = 0;
761                 if (error == 0)
762                         error = (*ifp->if_output)(ifp, m,
763                             (struct sockaddr *)dst);
764                 else
765                         m_freem(m);
766         }
767     }   
768 done:
769         if (!error)
770                 ipl_frouteok[0]++;
771         else
772                 ipl_frouteok[1]++;
773
774         if (ro->ro_rt) {
775                 RTFREE(ro->ro_rt);
776         }
777         return;
778 bad:
779         m_freem(m);
780         goto done;
781 # endif
782 }
783
784
785 /*
786  * Fake BSD uiomove() call.
787  */
788 int uiomove(caddr_t src, size_t ssize, int rw, struct uio *uio)
789 {
790         int error;
791         size_t mv = MIN(ssize, uio->uio_resid);
792
793         if (rw == UIO_READ) {
794                 error = IWCOPY(src, (caddr_t)uio->uio_buf, mv);
795         } else if (rw == UIO_WRITE) {
796                 error = IRCOPY((caddr_t)uio->uio_buf, src, mv);
797         } else
798                 error = EINVAL;
799         if (!error) {
800                 uio->uio_resid -= mv;
801                 uio->uio_buf += mv;
802         }
803         return error;
804 }
805
806 # ifdef IPFILTER_LKM
807 #  ifndef       IPL_MAJOR
808 #   define      IPL_MAJOR       95
809 #  endif
810
811 #  ifndef       IPL_NAME
812 #   define      IPL_NAME        "/dev/ipl"
813 #  endif
814
815 static struct file_operations ipl_fops = {
816         NULL,           /* lseek */
817         iplread,        /* read */
818         NULL,           /* write */
819         NULL,           /* readdir */
820         NULL,           /* select */
821         iplioctl,       /* ioctl */
822         NULL,           /* mmap */
823         iplopen,        /* open */
824         iplclose,       /* release */
825         NULL,           /* fsync */
826         NULL,           /* fasync */
827         NULL,           /* check_media_change */
828         NULL,           /* revalidate */
829 };
830
831
832 int init_module(void)
833 {
834         int error = 0, major;
835
836         if (register_chrdev(IPL_MAJOR, "ipf", &ipl_fops)) {
837                 printk("ipf: unable to get major number: %d\n", IPL_MAJOR);
838                 return -EIO;
839         }
840
841         error = iplattach();
842         if (!error)
843                 register_symtab(0);
844         return -error;
845 }
846
847 void cleanup_module(void)
848 {
849         unregister_chrdev(IPL_MAJOR, "ipf");
850         (void) ipldetach();
851 }
852 # endif /* IPFILTER_LKM */
853 #else /* #ifdef _KERNEL */
854
855
856 static int no_output __P((mb_t *m, struct ifnet *ifp))
857 {
858         return 0;
859 }
860
861
862 static int write_output __P((mb_t *m, struct ifnet *ifp))
863 {
864         FILE *fp;
865         char fname[32];
866         ip_t *ip;
867
868         ip = mtod(m, ip_t *);
869         sprintf(fname, "/tmp/%s", ifp->name);
870         if ((fp = fopen(fname, "a"))) {
871                 fwrite((char *)ip, ntohs(ip->ip_len), 1, fp);
872                 fclose(fp);
873         }
874         return 0;
875 }
876
877
878 struct ifnet *get_unit(name, v)
879 char *name;
880 int v;
881 {
882         struct ifnet *ifp, **ifa;
883         char ifname[32], *s;
884
885         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
886                 (void) sprintf(ifname, "%s", ifp->name);
887                 if (!strcmp(name, ifname))
888                         return ifp;
889         }
890
891         if (!ifneta) {
892                 ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
893                 ifneta[1] = NULL;
894                 ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
895                 nifs = 1;
896         } else {
897                 nifs++;
898                 ifneta = (struct ifnet **)realloc(ifneta,
899                                                   (nifs + 1) * sizeof(*ifa));
900                 ifneta[nifs] = NULL;
901                 ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
902         }
903         ifp = ifneta[nifs - 1];
904
905         for (s = name; *s && !isdigit(*s); s++)
906                 ;
907         if (*s && isdigit(*s)) {
908                 ifp->name = (char *)malloc(s - name + 1);
909                 strncpy(ifp->name, name, s - name);
910                 ifp->name[s - name] = '\0';
911         } else {
912                 ifp->name = strdup(name);
913         }
914         ifp->hard_start_xmit = no_output;
915         return ifp;
916 }
917
918
919
920 void init_ifp()
921 {
922         FILE *fp;
923         struct ifnet *ifp, **ifa;
924         char fname[32];
925
926         for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) {
927                 ifp->hard_start_xmit = write_output;
928                 sprintf(fname, "/tmp/%s", ifp->name);
929                 if ((fp = fopen(fname, "w")))
930                         fclose(fp);
931         }
932 }
933
934
935 void ipfr_fastroute(ip, fin, fdp)
936 ip_t *ip;
937 fr_info_t *fin;
938 frdest_t *fdp;
939 {
940         struct ifnet *ifp = fdp->fd_ifp;
941
942         if (!ifp)
943                 return; /* no routing table out here */
944
945         ip->ip_len = htons((u_short)ip->ip_len);
946         ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
947         ip->ip_sum = 0;
948         (*ifp->hard_start_xmit)((mb_t *)ip, ifp);
949 }
950
951
952 int ipllog __P((void))
953 {
954         verbose("l");
955         return 0;
956 }
957
958
959 int send_reset(ip, ifp)
960 ip_t *ip;
961 struct ifnet *ifp;
962 {
963         verbose("- TCP RST sent\n");
964         return 0;
965 }
966
967
968 int icmp_error(ip, ifp)
969 ip_t *ip;
970 struct ifnet *ifp;
971 {
972         verbose("- TCP RST sent\n");
973         return 0;
974 }
975 #endif /* _KERNEL */