]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/solaris.c
Bring the binutils_2_13_20021110_snap version of this to the HEAD branch.
[FreeBSD/FreeBSD.git] / contrib / ipfilter / solaris.c
1 /*
2  * Copyright (C) 1993-2002 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 /* #pragma ident   "@(#)solaris.c       1.12 6/5/96 (C) 1995 Darren Reed"*/
7 #pragma ident "@(#)$Id: solaris.c,v 2.15.2.30 2002/04/23 14:57:51 darrenr Exp $"
8
9 #include <sys/systm.h>
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <sys/errno.h>
13 #include <sys/uio.h>
14 #include <sys/buf.h>
15 #include <sys/modctl.h>
16 #include <sys/open.h>
17 #include <sys/kmem.h>
18 #include <sys/conf.h>
19 #include <sys/cmn_err.h>
20 #include <sys/stat.h>
21 #include <sys/cred.h>
22 #include <sys/dditypes.h>
23 #include <sys/stream.h>
24 #include <sys/poll.h>
25 #include <sys/autoconf.h>
26 #include <sys/byteorder.h>
27 #include <sys/socket.h>
28 #include <sys/dlpi.h>
29 #include <sys/stropts.h>
30 #include <sys/sockio.h>
31 #include <net/if.h>
32 #if SOLARIS2 >= 6
33 # include <net/if_types.h>
34 #endif
35 #include <net/af.h>
36 #include <net/route.h>
37 #include <netinet/in.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/if_ether.h>
40 #include <netinet/ip.h>
41 #include <netinet/ip_var.h>
42 #include <netinet/tcp.h>
43 #include <netinet/udp.h>
44 #include <netinet/tcpip.h>
45 #include <netinet/ip_icmp.h>
46 #include <sys/ddi.h>
47 #include <sys/sunddi.h>
48 #include "ip_compat.h"
49 #include "ipl.h"
50 #include "ip_fil.h"
51 #include "ip_nat.h"
52 #include "ip_state.h"
53
54
55 char    _depends_on[] = "drv/ip";
56
57
58 void    solipdrvattach __P((void));
59 int     solipdrvdetach __P((void));
60
61 void    solattach __P((void));
62 int     soldetach __P((void));
63
64 extern  struct  filterstats     frstats[];
65 extern  KRWLOCK_T       ipf_mutex, ipfs_mutex, ipf_nat, ipf_solaris;
66 extern  kmutex_t        ipf_rw;
67 extern  int     fr_running;
68 extern  int     fr_flags;
69
70 extern ipnat_t *nat_list;
71
72 static  qif_t   *qif_head = NULL;
73 static  int     ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
74                                  void *, void **));
75 static  int     ipf_probe __P((dev_info_t *));
76 static  int     ipf_identify __P((dev_info_t *));
77 static  int     ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
78 static  int     ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
79 static  qif_t   *qif_from_queue __P((queue_t *));
80 static  void    fr_donotip __P((int, qif_t *, queue_t *, mblk_t *,
81                                 mblk_t *, ip_t *, size_t));
82 static  char    *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH,
83                                     NULL };
84 static  int     (*ipf_ip_inp) __P((queue_t *, mblk_t *)) = NULL;
85
86
87 #if SOLARIS2 >= 7
88 extern  void    ipfr_slowtimer __P((void *));
89 timeout_id_t    ipfr_timer_id;
90 static  timeout_id_t    synctimeoutid = 0;
91 #else
92 extern  void    ipfr_slowtimer __P((void));
93 int     ipfr_timer_id;
94 static  int     synctimeoutid = 0;
95 #endif
96 int     ipf_debug = 0;
97 int     ipf_debug_verbose = 0;
98
99 /* #undef       IPFDEBUG        1 */
100 /* #undef       IPFDEBUG_VERBOSE        1 */
101 #ifdef  IPFDEBUG
102 void    printire __P((ire_t *));
103 #endif
104 #define isdigit(x)      ((x) >= '0' && (x) <= '9')
105
106 static int      fr_precheck __P((mblk_t **, queue_t *, qif_t *, int));
107
108
109 static struct cb_ops ipf_cb_ops = {
110         iplopen,
111         iplclose,
112         nodev,          /* strategy */
113         nodev,          /* print */
114         nodev,          /* dump */
115         iplread,
116         nodev,          /* write */
117         iplioctl,       /* ioctl */
118         nodev,          /* devmap */
119         nodev,          /* mmap */
120         nodev,          /* segmap */
121         nochpoll,       /* poll */
122         ddi_prop_op,
123         NULL,
124         D_MTSAFE,
125 #if SOLARIS2 > 4
126         CB_REV,
127         nodev,          /* aread */
128         nodev,          /* awrite */
129 #endif
130 };
131
132 static struct dev_ops ipf_ops = {
133         DEVO_REV,
134         0,
135         ipf_getinfo,
136         ipf_identify,
137         ipf_probe,
138         ipf_attach,
139         ipf_detach,
140         nodev,          /* reset */
141         &ipf_cb_ops,
142         (struct bus_ops *)0
143 };
144
145 extern struct mod_ops mod_driverops;
146 static struct modldrv iplmod = {
147         &mod_driverops, IPL_VERSION, &ipf_ops };
148 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
149
150 #if SOLARIS2 >= 6
151 static  size_t  hdrsizes[57][2] = {
152         { 0, 0 },
153         { IFT_OTHER, 0 },
154         { IFT_1822, 14 },       /* 14 for ire0 ?? */
155         { IFT_HDH1822, 0 },
156         { IFT_X25DDN, 0 },
157         { IFT_X25, 0 },
158         { IFT_ETHER, 14 },
159         { IFT_ISO88023, 14 },
160         { IFT_ISO88024, 0 },
161         { IFT_ISO88025, 0 },
162         { IFT_ISO88026, 0 },
163         { IFT_STARLAN, 0 },
164         { IFT_P10, 0 },
165         { IFT_P80, 0 },
166         { IFT_HY, 0 },
167         { IFT_FDDI, 24 },
168         { IFT_LAPB, 0 },
169         { IFT_SDLC, 0 },
170         { IFT_T1, 0 },
171         { IFT_CEPT, 0 },
172         { IFT_ISDNBASIC, 0 },
173         { IFT_ISDNPRIMARY, 0 },
174         { IFT_PTPSERIAL, 0 },
175         { IFT_PPP, 0 },
176         { IFT_LOOP, 0 },
177         { IFT_EON, 0 },
178         { IFT_XETHER, 0 },
179         { IFT_NSIP, 0 },
180         { IFT_SLIP, 0 },
181         { IFT_ULTRA, 0 },
182         { IFT_DS3, 0 },
183         { IFT_SIP, 0 },
184         { IFT_FRELAY, 0 },
185         { IFT_RS232, 0 },
186         { IFT_PARA, 0 },
187         { IFT_ARCNET, 0 },
188         { IFT_ARCNETPLUS, 0 },
189         { IFT_ATM, 0 },
190         { IFT_MIOX25, 0 },
191         { IFT_SONET, 0 },
192         { IFT_X25PLE, 0 },
193         { IFT_ISO88022LLC, 0 },
194         { IFT_LOCALTALK, 0 },
195         { IFT_SMDSDXI, 0 },
196         { IFT_FRELAYDCE, 0 },
197         { IFT_V35, 0 },
198         { IFT_HSSI, 0 },
199         { IFT_HIPPI, 0 },
200         { IFT_MODEM, 0 },
201         { IFT_AAL5, 0 },
202         { IFT_SONETPATH, 0 },
203         { IFT_SONETVT, 0 },
204         { IFT_SMDSICIP, 0 },
205         { IFT_PROPVIRTUAL, 0 },
206         { IFT_PROPMUX, 0 },
207 };
208 #endif /* SOLARIS2 >= 6 */
209
210 static dev_info_t *ipf_dev_info = NULL;
211
212
213 int _init()
214 {
215         int ipfinst;
216
217         ipfinst = mod_install(&modlink1);
218 #ifdef  IPFDEBUG
219         if (ipf_debug)
220                 cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
221 #endif
222         return ipfinst;
223 }
224
225
226 int _fini(void)
227 {
228         int ipfinst;
229
230         ipfinst = mod_remove(&modlink1);
231 #ifdef  IPFDEBUG
232         if (ipf_debug)
233                 cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
234 #endif
235         return ipfinst;
236 }
237
238
239 int _info(modinfop)
240 struct modinfo *modinfop;
241 {
242         int ipfinst;
243
244         ipfinst = mod_info(&modlink1, modinfop);
245 #ifdef  IPFDEBUG
246         if (ipf_debug)
247                 cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x",
248                         modinfop, ipfinst);
249 #endif
250         if (fr_running > 0)
251                 ipfsync();
252         return ipfinst;
253 }
254
255
256 static int ipf_probe(dip)
257 dev_info_t *dip;
258 {
259         if (fr_running < 0)
260                 return DDI_PROBE_FAILURE;
261 #ifdef  IPFDEBUG
262         if (ipf_debug)
263                 cmn_err(CE_NOTE, "IP Filter: ipf_probe(%x)", dip);
264 #endif
265         return DDI_PROBE_SUCCESS;
266 }
267
268
269 static int ipf_identify(dip)
270 dev_info_t *dip;
271 {
272 #ifdef  IPFDEBUG
273         if (ipf_debug)
274                 cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip);
275 #endif
276         if (strcmp(ddi_get_name(dip), "ipf") == 0)
277                 return (DDI_IDENTIFIED);
278         return (DDI_NOT_IDENTIFIED);
279 }
280
281
282 static void ipf_ire_walk(ire, arg)
283 ire_t *ire;
284 void *arg;
285 {
286         qif_t *qif = arg;
287
288         if ((ire->ire_type == IRE_CACHE) &&
289 #if SOLARIS2 >= 6
290             (ire->ire_ipif != NULL) &&
291             (ire->ire_ipif->ipif_ill == qif->qf_ill)
292 #else
293             (ire_to_ill(ire) == qif->qf_ill)
294 #endif
295             ) {
296 #if SOLARIS2 >= 8
297                 mblk_t *m = ire->ire_fp_mp;
298 #else
299                 mblk_t *m = ire->ire_ll_hdr_mp;
300 #endif
301                 if (m != NULL)
302                         qif->qf_hl = m->b_wptr - m->b_rptr;
303         }
304 }
305
306
307 static int ipf_attach(dip, cmd)
308 dev_info_t *dip;
309 ddi_attach_cmd_t cmd;
310 {
311 #ifdef  IPFDEBUG
312         int instance;
313
314         if (ipf_debug)
315                 cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd);
316 #endif
317         switch (cmd) {
318         case DDI_ATTACH:
319                 if (fr_running < 0)
320                         break;
321 #ifdef  IPFDEBUG
322                 instance = ddi_get_instance(dip);
323
324         if (ipf_debug)
325                 cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance);
326 #endif
327                 if (ddi_create_minor_node(dip, "ipf", S_IFCHR, IPL_LOGIPF,
328                                           DDI_PSEUDO, 0) == DDI_FAILURE) {
329                         ddi_remove_minor_node(dip, NULL);
330                         goto attach_failed;
331                 }
332                 if (ddi_create_minor_node(dip, "ipnat", S_IFCHR, IPL_LOGNAT,
333                                           DDI_PSEUDO, 0) == DDI_FAILURE) {
334                         ddi_remove_minor_node(dip, NULL);
335                         goto attach_failed;
336                 }
337                 if (ddi_create_minor_node(dip, "ipstate", S_IFCHR,IPL_LOGSTATE,
338                                           DDI_PSEUDO, 0) == DDI_FAILURE) {
339                         ddi_remove_minor_node(dip, NULL);
340                         goto attach_failed;
341                 }
342                 if (ddi_create_minor_node(dip, "ipauth", S_IFCHR, IPL_LOGAUTH,
343                                           DDI_PSEUDO, 0) == DDI_FAILURE) {
344                         ddi_remove_minor_node(dip, NULL);
345                         goto attach_failed;
346                 }
347                 ipf_dev_info = dip;
348                 sync();
349                 /*
350                  * Initialize mutex's
351                  */
352                 if (iplattach() == -1)
353                         goto attach_failed;
354                 /*
355                  * Lock people out while we set things up.
356                  */
357                 WRITE_ENTER(&ipf_solaris);
358                 solattach();
359                 solipdrvattach();
360                 RWLOCK_EXIT(&ipf_solaris);
361                 cmn_err(CE_CONT, "%s, attaching complete.\n",
362                         ipfilter_version);
363                 sync();
364                 if (fr_running == 0)
365                         fr_running = 1;
366                 if (ipfr_timer_id == 0)
367                         ipfr_timer_id = timeout(ipfr_slowtimer, NULL,
368                                                 drv_usectohz(500000));
369                 if (fr_running == 1)
370                         return DDI_SUCCESS;
371 #if SOLARIS2 >= 8
372         case DDI_RESUME :
373         case DDI_PM_RESUME :
374                 if (ipfr_timer_id == 0)
375                         ipfr_timer_id = timeout(ipfr_slowtimer, NULL,
376                                                 drv_usectohz(500000));
377                 return DDI_SUCCESS;
378 #endif
379         default:
380                 return DDI_FAILURE;
381         }
382
383 attach_failed:
384         cmn_err(CE_NOTE, "IP Filter: failed to attach\n");
385         /*
386          * Use our own detach routine to toss
387          * away any stuff we allocated above.
388          */
389         (void) ipf_detach(dip, DDI_DETACH);
390         return DDI_FAILURE;
391 }
392
393
394 static int ipf_detach(dip, cmd)
395 dev_info_t *dip;
396 ddi_detach_cmd_t cmd;
397 {
398         int i;
399
400 #ifdef  IPFDEBUG
401         if (ipf_debug)
402                 cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
403 #endif
404         switch (cmd) {
405         case DDI_DETACH:
406                 if (fr_running <= 0)
407                         break;
408                 /*
409                  * Make sure we're the only one's modifying things.  With
410                  * this lock others should just fall out of the loop.
411                  */
412                 mutex_enter(&ipf_rw);
413                 if (ipfr_timer_id != 0) {
414                         untimeout(ipfr_timer_id);
415                         ipfr_timer_id = 0;
416                 }
417                 mutex_exit(&ipf_rw);
418                 WRITE_ENTER(&ipf_solaris);
419                 mutex_enter(&ipf_rw);
420                 if (fr_running <= 0) {
421                         mutex_exit(&ipf_rw);
422                         return DDI_FAILURE;
423                 }
424                 fr_running = -1;
425                 mutex_exit(&ipf_rw);
426                 /* NOTE: ipf_solaris rwlock is released in ipldetach */
427
428                 /*
429                  * Undo what we did in ipf_attach, freeing resources
430                  * and removing things we installed.  The system
431                  * framework guarantees we are not active with this devinfo
432                  * node in any other entry points at this time.
433                  */
434                 ddi_prop_remove_all(dip);
435                 i = ddi_get_instance(dip);
436                 ddi_remove_minor_node(dip, NULL);
437                 sync();
438                 i = solipdrvdetach();
439                 if (i > 0) {
440                         cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
441                         return DDI_FAILURE;
442                 }
443                 if (!soldetach()) {
444                         cmn_err(CE_CONT, "%s detached\n", ipfilter_version);
445                         return (DDI_SUCCESS);
446                 }
447 #if SOLARIS2 >= 8
448         case DDI_SUSPEND :
449         case DDI_PM_SUSPEND :
450                 if (ipfr_timer_id != 0) {
451                         untimeout(ipfr_timer_id);
452                         ipfr_timer_id = 0;
453                 }
454                 if (synctimeoutid) {
455                         untimeout(synctimeoutid);
456                         synctimeoutid = 0;
457                 }
458                 return DDI_SUCCESS;
459 #endif
460         default:
461                 return (DDI_FAILURE);
462         }
463         return DDI_FAILURE;
464 }
465
466
467 static int ipf_getinfo(dip, infocmd, arg, result)
468 dev_info_t *dip;
469 ddi_info_cmd_t infocmd;
470 void *arg, **result;
471 {
472         int error;
473
474         if (fr_running <= 0)
475                 return DDI_FAILURE;
476         error = DDI_FAILURE;
477 #ifdef  IPFDEBUG
478         if (ipf_debug)
479                 cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)",
480                         dip, infocmd, arg);
481 #endif
482         switch (infocmd) {
483         case DDI_INFO_DEVT2DEVINFO:
484                 *result = ipf_dev_info;
485                 error = DDI_SUCCESS;
486                 break;
487         case DDI_INFO_DEVT2INSTANCE:
488                 *result = (void *)getminor((dev_t) arg);
489                 error = DDI_SUCCESS;
490                 break;
491         default:
492                 break;
493         }
494         return (error);
495 }
496
497 /*
498  * find the filter structure setup for this queue
499  */
500 static qif_t *qif_from_queue(q)
501 queue_t *q;
502 {
503         qif_t *qif;
504
505         for (qif = qif_head; qif; qif = qif->qf_next)
506                 if ((qif->qf_iptr == q->q_ptr) || (qif->qf_optr == q->q_ptr))
507                         break;
508         return qif;
509 }
510
511
512 /*
513  * OK, this is pretty scrappy code, but then it's essentially just here for
514  * debug purposes and that's it.  Packets should not normally come through
515  * here, and if they do, well, we would like to see as much information as
516  * possible about them and what they claim to hold.
517  */
518 void fr_donotip(out, qif, q, m, mt, ip, off)
519 int out;
520 qif_t *qif;
521 queue_t *q;
522 mblk_t *m, *mt;
523 ip_t *ip;
524 size_t off;
525 {
526         u_char *s, outb[256], *t;
527         int i;
528
529         outb[0] = '\0';
530         outb[1] = '\0';
531         outb[2] = '\0';
532         outb[3] = '\0';
533         s = ip ? (u_char *)ip : outb;
534         if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA))
535                 m = m->b_cont;
536
537         cmn_err(CE_CONT, " !IP %s:%d %d %p %p %p %d %p/%d %p/%d %p %d %d %p\n",
538                 qif ? qif->qf_name : "?", out, qif ? qif->qf_hl : -1, q,
539                 q ? q->q_ptr : NULL, q ? q->q_qinfo : NULL,
540                 mt->b_wptr - mt->b_rptr, m, MTYPE(m), mt, MTYPE(mt), m->b_rptr,
541                 m->b_wptr - m->b_rptr, off, ip);
542         cmn_err(CE_CONT, "%02x%02x%02x%02x\n", *s, *(s+1), *(s+2), *(s+3));
543         while (m != mt) {
544                 i = 0;
545                 t = outb;
546                 s = mt->b_rptr;
547                 sprintf((char *)t, "%d:", MTYPE(mt));
548                 t += strlen((char *)t);
549                 for (; (i < 100) && (s < mt->b_wptr); i++) {
550                         sprintf((char *)t, "%02x%s", *s++,
551                                 ((i & 3) == 3) ? " " : "");
552                         t += ((i & 3) == 3) ? 3 : 2;
553                 }
554                 *t++ = '\n';
555                 *t = '\0';
556                 cmn_err(CE_CONT, "%s", outb);
557                 mt = mt->b_cont;
558         }
559         i = 0;
560         t = outb;
561         s = m->b_rptr;
562         sprintf((char *)t, "%d:", MTYPE(m));
563         t += strlen((char *)t);
564         for (; (i < 100) && (s < m->b_wptr); i++) {
565                 sprintf((char *)t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
566                 t += ((i & 3) == 3) ? 3 : 2;
567         }
568         *t++ = '\n';
569         *t = '\0';
570         cmn_err(CE_CONT, "%s", outb);
571 }
572
573
574 /*
575  * find the first data mblk, if present, in the chain we're processing.  Also
576  * make a few sanity checks to try prevent the filter from causing a panic -
577  * none of the nice IP sanity checks (including checksumming) should have been
578  * done yet (for incoming packets) - dangerous!
579  */
580 static int fr_precheck(mp, q, qif, out)
581 mblk_t **mp;
582 queue_t *q;
583 qif_t *qif;
584 int out;
585 {
586         register mblk_t *m, *mt = *mp;
587         register ip_t *ip;
588         size_t hlen, len, off, off2, mlen, iphlen, plen, woff;
589         int err, synced = 0, sap, p, realigned = 0, multi = 0;
590         u_char *bp;
591 #if SOLARIS2 >= 8
592         ip6_t *ip6;
593 #endif
594 #ifndef sparc
595         u_short __ipoff;
596 #endif
597 tryagain:
598         ip = NULL;
599         m = NULL;
600         /*
601          * If there is only M_DATA for a packet going out, then any header
602          * information (which would otherwise appear in an M_PROTO mblk before
603          * the M_DATA) is prepended before the IP header.  We need to set the
604          * offset to account for this. - see MMM
605          */
606         off = (out) ? qif->qf_hl : 0;
607
608         /*
609          * If the message protocol block indicates that there isn't a data
610          * block following it, just return back.
611          */
612         bp = (u_char *)ALIGN32(mt->b_rptr);
613         if (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO) {
614                 dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp;
615                 if (dl->dl_primitive == DL_UNITDATA_IND) {
616                         multi = dl->dl_group_address;
617                         m = mt->b_cont;
618                         /*
619                          * This is a complete kludge to try and work around
620                          * some bizarre packets which drop through into
621                          * fr_donotip.
622                          */
623                         if (m && multi && ((*((u_char *)m->b_rptr) == 0x0) &&
624                             ((*((u_char *)m->b_rptr + 2) == 0x45)))) {
625                                 ip = (ip_t *)(m->b_rptr + 2);
626                                 off = 2;
627                         } else
628                                 off = 0;
629                 } else if (dl->dl_primitive != DL_UNITDATA_REQ) {
630                         ip = (ip_t *)dl;
631                         if ((ip->ip_v == IPVERSION) &&
632                             (ip->ip_hl == (sizeof(*ip) >> 2)) &&
633                             (ntohs(ip->ip_len) == mt->b_wptr - mt->b_rptr)) {
634                                 off = 0;
635                                 m = mt;
636                         } else {
637                                 frstats[out].fr_notdata++;
638                                 return 0;
639                         }
640                 }
641         }
642
643         /*
644          * Find the first data block, count the data blocks in this chain and
645          * the total amount of data.
646          */
647         if (ip == NULL)
648                 for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont)
649                         off = 0;        /* Any non-M_DATA cancels the offset */
650
651         if (!m) {
652                 frstats[out].fr_nodata++;
653                 return 0;       /* No data blocks */
654         }
655
656         ip = (ip_t *)(m->b_rptr + off);         /* MMM */
657
658         /*
659          * We might have a 1st data block which is really M_PROTO, i.e. it is
660          * only big enough for the link layer header
661          */
662         while ((u_char *)ip >= m->b_wptr) {
663                 len = (u_char *)ip - m->b_wptr;
664                 m = m->b_cont;
665                 if (m == NULL)
666                         return 0;       /* not enough data for IP */
667                 ip = (ip_t *)(m->b_rptr + len);
668         }
669         off = (u_char *)ip - m->b_rptr;
670         if (off != 0)
671                 m->b_rptr = (u_char *)ip;
672
673         len = m->b_wptr - m->b_rptr;
674         if (m->b_wptr < m->b_rptr) {
675                 cmn_err(CE_NOTE, "!IP Filter: Bad packet: wptr %p < rptr %p",
676                         m->b_wptr, m->b_rptr);
677                 frstats[out].fr_bad++;
678                 return -1;
679         }
680
681         mlen = msgdsize(m);
682         sap = qif->qf_ill->ill_sap;
683
684         if (sap == 0x800) {
685                 u_short tlen;
686
687                 hlen = sizeof(*ip);
688
689                 /* XXX - might not be aligned (from ppp?) */
690                 ((char *)&tlen)[0] = ((char *)&ip->ip_len)[0];
691                 ((char *)&tlen)[1] = ((char *)&ip->ip_len)[1];
692
693                 plen = ntohs(tlen);
694
695                 sap = 0;
696         }
697 #if SOLARIS2 >= 8
698         else if (sap == IP6_DL_SAP) {
699                 u_short tlen;
700
701                 hlen = sizeof(ip6_t);
702                 ip6 = (ip6_t *)ip;
703                 /* XXX - might not be aligned (from ppp?) */
704                 ((char *)&tlen)[0] = ((char *)&ip6->ip6_plen)[0];
705                 ((char *)&tlen)[1] = ((char *)&ip6->ip6_plen)[1];
706                 plen = ntohs(tlen);
707                 if (!plen)
708                         return -1;      /* Jumbo gram */
709                 plen += sizeof(*ip6);
710         }
711 #endif
712         else {
713                 plen = 0;
714                 hlen = 0;
715                 sap = -1;
716         }
717
718         /*
719          * Ok, the IP header isn't on a 32bit aligned address so junk it.
720          */
721         if (((u_long)ip & 0x3) || (plen > mlen) || (len < hlen) ||
722             (sap == -1)) {
723                 mblk_t *m1, *m2;
724                 u_char *s, c;
725                 int v;
726
727                 /*
728                  * Junk using pullupmsg - it's next to useless.
729                  */
730 fixalign:
731                 if (off)
732                         m->b_rptr -= off;
733                 c = *(u_char *)ip;
734                 c >>= 4;
735                 if (c != 4
736 #if SOLARIS2 >= 8
737                     && c != 6
738 #endif
739                 ) {
740                         frstats[out].fr_notip++;
741                         return (fr_flags & FF_BLOCKNONIP) ? -1 : 0;
742                 }
743
744                 if (realigned)
745                         return -1;
746                 realigned = 1;
747                 off2 = (size_t)((u_long)ip & 0x3);
748                 if (off2)
749                         off2 = 4 - off2;
750                 len = msgdsize(m);
751                 m2 = allocb(len + off2, BPRI_HI);
752                 if (m2 == NULL) {
753                         frstats[out].fr_pull[1]++;
754                         return -1;
755                 }
756
757                 MTYPE(m2) = M_DATA;
758                 if (m->b_rptr != (u_char *)ip)
759                         m2->b_rptr += off2;
760                 m2->b_wptr = m2->b_rptr + len;
761                 m1 = m;
762                 s = (u_char *)m->b_rptr;
763                 for (bp = m2->b_rptr; m1 && (bp < m2->b_wptr); bp += len) {
764                         len = MIN(m1->b_wptr - s, m2->b_wptr - bp);
765                         bcopy(s, bp, len);
766                         m1 = m1->b_cont;
767                         if (m1)
768                                 s = m1->b_rptr;
769                 }
770
771                 if (mt != m && mt->b_cont == m && !off) {
772                         /*
773                          * check if the buffer we're changing is chained in-
774                          * between other buffers and unlink/relink as required.
775                          */
776                         (void) unlinkb(mt);     /* should return 'm' */
777                         m1 = unlinkb(m);
778                         if (m1)
779                                 linkb(m2, m1);
780                         freemsg(m);
781                         linkb(mt, m2);
782                 } else {
783                         if (m == mt) {
784                                 m1 = unlinkb(mt);
785                                 if (m1)
786                                         linkb(m2, m1);
787                         }
788                         freemsg(mt);
789                         *mp = m2;
790                         mt = m2;
791                 }
792
793                 frstats[out].fr_pull[0]++;
794                 synced = 1;
795                 off = 0;
796                 goto tryagain;
797         }
798
799         if (((sap == 0) && (ip->ip_v != IP_VERSION))
800 #if SOLARIS2 >= 8
801             || ((sap == IP6_DL_SAP) && ((ip6->ip6_vfc >> 4) != 6))
802 #endif
803         ) {
804                 m->b_rptr -= off;
805                 return -2;
806         }
807
808 #ifndef sparc
809 # if SOLARIS2 >= 8
810         if (sap == IP6_DL_SAP) {
811                 ip6->ip6_plen = plen - sizeof(*ip6);
812         } else {
813 # endif
814                 __ipoff = (u_short)ip->ip_off;
815
816                 ip->ip_len = plen;
817                 ip->ip_off = ntohs(__ipoff);
818 # if SOLARIS2 >= 8
819         }
820 # endif
821 #endif
822         if (sap == 0)
823                 iphlen = ip->ip_hl << 2;
824 #if SOLARIS2 >= 8
825         else if (sap == IP6_DL_SAP)
826                 iphlen = sizeof(ip6_t);
827 #endif
828
829         if ((
830 #if SOLARIS2 >= 8
831              (sap == IP6_DL_SAP) && (mlen < plen)) ||
832             ((sap == 0) &&
833 #endif
834              ((iphlen < hlen) || (iphlen > plen) || (mlen < plen)))) {
835                 /*
836                  * Bad IP packet or not enough data/data length mismatches
837                  */
838 #ifndef sparc
839 # if SOLARIS2 >= 8
840                 if (sap == IP6_DL_SAP) {
841                         ip6->ip6_plen = htons(plen - sizeof(*ip6));
842                 } else {
843 # endif
844                         __ipoff = (u_short)ip->ip_off;
845
846                         ip->ip_len = htons(plen);
847                         ip->ip_off = htons(__ipoff);
848 # if SOLARIS2 >= 8
849                 }
850 # endif
851 #endif
852                 m->b_rptr -= off;
853                 frstats[out].fr_bad++;
854                 return -1;
855         }
856
857         /*
858          * Make hlen the total size of the IP header plus TCP/UDP/ICMP header
859          * (if it is one of these three).
860          */
861         if (sap == 0)
862                 p = ip->ip_p;
863 #if SOLARIS2 >= 8
864         else if (sap == IP6_DL_SAP)
865                 p = ip6->ip6_nxt;
866
867         if ((sap == IP6_DL_SAP) || ((ip->ip_off & IP_OFFMASK) == 0))
868 #else
869         if ((ip->ip_off & IP_OFFMASK) == 0)
870 #endif
871                 switch (p)
872                 {
873                 case IPPROTO_TCP :
874                         hlen += sizeof(tcphdr_t);
875                         break;
876                 case IPPROTO_UDP :
877                         hlen += sizeof(udphdr_t);
878                         break;
879                 case IPPROTO_ICMP :
880                         /* 76 bytes is enough for a complete ICMP error. */
881                         hlen += 76 + sizeof(icmphdr_t);
882                         break;
883                 default :
884                         break;
885                 }
886
887         woff = 0;
888         if (hlen > mlen) {
889                 hlen = mlen;
890         } else if (m->b_wptr - m->b_rptr > plen) {
891                 woff = m->b_wptr - m->b_rptr - plen;
892                 m->b_wptr -= woff;
893         }
894
895         /*
896          * If we don't have enough data in the mblk or we haven't yet copied
897          * enough (above), then copy some more.
898          */
899         if ((hlen > len)) {
900                 if (!pullupmsg(m, (int)hlen)) {
901                         cmn_err(CE_NOTE, "pullupmsg failed");
902                         frstats[out].fr_pull[1]++;
903                         return -1;
904                 }
905                 frstats[out].fr_pull[0]++;
906                 ip = (ip_t *)ALIGN32(m->b_rptr);
907         }
908         qif->qf_m = m;
909         qif->qf_q = q;
910         qif->qf_off = off;
911         qif->qf_len = len;
912         err = fr_check(ip, iphlen, qif->qf_ill, out, qif, mp);
913         if (err == 2) {
914                 goto fixalign;
915         }
916         /*
917          * Copy back the ip header data if it was changed, we haven't yet
918          * freed the message and we aren't going to drop the packet.
919          * BUT only do this if there were no changes to the buffer, else
920          * we can't be sure that the ip pointer is still correct!
921          */
922         if (*mp != NULL) {
923                 if (*mp == mt) {
924                         m->b_wptr += woff;
925                         m->b_rptr -= off;
926 #ifndef sparc
927 # if SOLARIS2 >= 8
928                         if (sap == IP6_DL_SAP) {
929                                 ip6->ip6_plen = htons(plen - sizeof(*ip6));
930                         } else {
931 # endif
932                                 __ipoff = (u_short)ip->ip_off;
933                                 /*
934                                  * plen is useless because of NAT.
935                                  */
936                                 ip->ip_len = htons(ip->ip_len);
937                                 ip->ip_off = htons(__ipoff);
938 # if SOLARIS2 >= 8
939                         }
940 # endif
941 #endif
942                 } else
943                         cmn_err(CE_NOTE,
944                                 "!IP Filter: *mp %p mt %p %s", *mp, mt,
945                                 "mblk changed, cannot revert ip_len, ip_off");
946         }
947         return err;
948 }
949
950
951 /*
952  * Only called for M_IOCACK messages
953  */
954 void fr_qif_update(qif, mp)
955 qif_t *qif;
956 mblk_t *mp;
957 {
958         struct iocblk *iocp;
959
960         if (!qif || !mp)
961                 return;
962         iocp = (struct iocblk *)mp->b_rptr;
963         if (mp->b_cont && (iocp->ioc_cmd == DL_IOC_HDR_INFO)) {
964                 mp = mp->b_cont;
965                 if (MTYPE(mp) == M_PROTO && mp->b_cont) {
966                         mp = mp->b_cont;
967                         if (MTYPE(mp) == M_DATA) {
968                                 qif->qf_hl = mp->b_wptr - mp->b_rptr;
969                         }
970                 }
971         }
972 }
973
974
975 int fr_qin(q, mb)
976 queue_t *q;
977 mblk_t *mb;
978 {
979         int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
980         qif_t qf, *qif;
981
982 #ifdef  IPFDEBUG_VERBOSE
983         if (ipf_debug_verbose)
984                 cmn_err(CE_CONT,
985                         "fr_qin(%lx,%lx) ptr %lx type 0x%x ref %d len %d\n",
986                         q, q->q_ptr, mb, MTYPE(mb), mb->b_datap->db_ref,
987                         msgdsize(mb));
988 #endif
989
990         /*
991          * IPFilter is still in the packet path but not enabled.  Drop whatever
992          * it is that has come through.
993          */
994         if (fr_running <= 0) {
995                 mb->b_prev = NULL;
996                 freemsg(mb);
997                 return 0;
998         }
999
1000         type = MTYPE(mb);
1001
1002         /*
1003          * If a mblk has more than one reference, make a copy, filter that and
1004          * free a reference to the original.
1005          */
1006         if (mb->b_datap->db_ref > 1) {
1007                 mblk_t *m1;
1008
1009                 m1 = copymsg(mb);
1010                 if (!m1) {
1011                         frstats[0].fr_drop++;
1012                         mb->b_prev = NULL;
1013                         freemsg(mb);
1014                         return 0;
1015                 }
1016                 mb->b_prev = NULL;
1017                 freemsg(mb);
1018                 mb = m1;
1019                 frstats[0].fr_copy++;
1020         }
1021
1022         READ_ENTER(&ipf_solaris);
1023 again:
1024         if (fr_running <= 0) {
1025                 mb->b_prev = NULL;
1026                 freemsg(mb);
1027                 RWLOCK_EXIT(&ipf_solaris);
1028                 return 0;
1029         }
1030         READ_ENTER(&ipfs_mutex);
1031         if (!(qif = qif_from_queue(q))) {
1032                 for (qif = qif_head; qif; qif = qif->qf_next)
1033                         if (&qif->qf_rqinit == q->q_qinfo && qif->qf_rqinfo &&
1034                                         qif->qf_rqinfo->qi_putp) {
1035                                 pnext = qif->qf_rqinfo->qi_putp;
1036                                 frstats[0].fr_notip++;
1037                                 RWLOCK_EXIT(&ipfs_mutex);
1038                                 if (!synced) {
1039                                         ipfsync();
1040                                         synced = 1;
1041                                         goto again;
1042                                 }
1043                                 RWLOCK_EXIT(&ipf_solaris);
1044                                 /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
1045                                 return (*pnext)(q, mb);
1046                         }
1047                 RWLOCK_EXIT(&ipfs_mutex);
1048                 if (!synced) {
1049                         ipfsync();
1050                         synced = 1;
1051                         goto again;
1052                 }
1053                 cmn_err(CE_WARN,
1054                         "!IP Filter: dropped: fr_qin(%x,%x): type %x qif %x",
1055                         q, mb, type, qif);
1056                 cmn_err(CE_CONT,
1057                         "!IP Filter: info %x next %x ptr %x fsrv %x bsrv %x\n",
1058                         q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
1059                         q->q_nbsrv);
1060                 cmn_err(CE_CONT, "!IP Filter: info: putp %x srvp %x info %x\n",
1061                         q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
1062 #if SOLARIS > 3
1063                         q->q_qinfo->qi_infop
1064 #else
1065                         0
1066 #endif
1067                         );
1068                 frstats[0].fr_drop++;
1069                 mb->b_prev = NULL;
1070                 freemsg(mb);
1071                 RWLOCK_EXIT(&ipf_solaris);
1072                 return 0;
1073         }
1074
1075         qif->qf_incnt++;
1076         pnext = qif->qf_rqinfo->qi_putp;
1077         if (type == M_IOCACK)
1078                 fr_qif_update(qif, mb);
1079         bcopy((char *)qif, (char *)&qf, sizeof(qf));
1080         if (datamsg(type) || (type == M_BREAK))
1081                 err = fr_precheck(&mb, q, &qf, 0);
1082
1083         RWLOCK_EXIT(&ipfs_mutex);
1084
1085         if ((err == 0) && (mb != NULL)) {
1086                 if (pnext) {
1087                         RWLOCK_EXIT(&ipf_solaris);
1088                         return (*pnext)(q, mb);
1089                 }
1090
1091                 cmn_err(CE_WARN,
1092                         "!IP Filter: inp NULL: qif %x %s q %x info %x",
1093                         qif, qf.qf_name, q, q->q_qinfo);
1094         }
1095
1096         if (err == -2) {
1097                 if (synced == 0) {
1098                         ipfsync();
1099                         synced = 1;
1100                         goto again;
1101                 }
1102                 frstats[0].fr_notip++;
1103                 if (!(fr_flags & FF_BLOCKNONIP) && (pnext != NULL)) {
1104                         RWLOCK_EXIT(&ipf_solaris);
1105                         return (*pnext)(q, mb);
1106                 }
1107         }
1108         
1109
1110         if (mb) {
1111                 mb->b_prev = NULL;
1112                 freemsg(mb);
1113         }
1114         RWLOCK_EXIT(&ipf_solaris);
1115         return 1;
1116 }
1117
1118
1119 int fr_qout(q, mb)
1120 queue_t *q;
1121 mblk_t *mb;
1122 {
1123         int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
1124         qif_t qf, *qif;
1125
1126 #ifdef  IPFDEBUG_VERBOSE
1127         if (ipf_debug_verbose)
1128                 cmn_err(CE_CONT,
1129                         "fr_qout(%lx,%lx) ptr %lx type 0x%x ref %d len %d\n",
1130                         q, q->q_ptr, mb, MTYPE(mb), mb->b_datap->db_ref,
1131                         msgdsize(mb));
1132 #endif
1133
1134         if (fr_running <= 0) {
1135                 mb->b_prev = NULL;
1136                 freemsg(mb);
1137                 return 0;
1138         }
1139
1140         type = MTYPE(mb);
1141
1142 #if SOLARIS2 >= 6
1143         if ((!dohwcksum || mb->b_ick_flag != ICK_VALID) &&
1144             (mb->b_datap->db_ref > 1))
1145 #else
1146         if (mb->b_datap->db_ref > 1)
1147 #endif
1148         {
1149                 mblk_t *m1;
1150
1151                 m1 = copymsg(mb);
1152                 if (!m1) {
1153                         frstats[1].fr_drop++;
1154                         mb->b_prev = NULL;
1155                         freemsg(mb);
1156                         return 0;
1157                 }
1158                 mb->b_prev = NULL;
1159                 freemsg(mb);
1160                 mb = m1;
1161                 frstats[1].fr_copy++;
1162         }
1163
1164         READ_ENTER(&ipf_solaris);
1165 again:
1166         if (fr_running <= 0) {
1167                 mb->b_prev = NULL;
1168                 freemsg(mb);
1169                 RWLOCK_EXIT(&ipf_solaris);
1170                 return 0;
1171         }
1172         READ_ENTER(&ipfs_mutex);
1173         if (!(qif = qif_from_queue(q))) {
1174                 for (qif = qif_head; qif; qif = qif->qf_next)
1175                         if (&qif->qf_wqinit == q->q_qinfo && qif->qf_wqinfo &&
1176                                         qif->qf_wqinfo->qi_putp) {
1177                                 pnext = qif->qf_wqinfo->qi_putp;
1178                                 RWLOCK_EXIT(&ipfs_mutex);
1179                                 frstats[1].fr_notip++;
1180                                 if (!synced) {
1181                                         ipfsync();
1182                                         synced = 1;
1183                                         goto again;
1184                                 }
1185                                 /* fr_donotip(1, NULL, q, mb, mb, NULL, 0); */
1186                                 RWLOCK_EXIT(&ipf_solaris);
1187                                 return (*pnext)(q, mb);
1188                         }
1189                 RWLOCK_EXIT(&ipfs_mutex);
1190                 if (!synced) {
1191                         ipfsync();
1192                         synced = 1;
1193                         goto again;
1194                 }
1195                 cmn_err(CE_WARN,
1196                         "!IP Filter: dropped: fr_qout(%x,%x): type %x: qif %x",
1197                         q, mb, type, qif);
1198                 cmn_err(CE_CONT,
1199                         "!IP Filter: info %x next %x ptr %x fsrv %x bsrv %x\n",
1200                         q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
1201                         q->q_nbsrv);
1202                 cmn_err(CE_CONT, "!IP Filter: info: putp %x srvp %x info %x\n",
1203                         q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
1204 #if SOLARIS > 3
1205                         q->q_qinfo->qi_infop
1206 #else
1207                         0
1208 #endif
1209                         );
1210                 if (q->q_nfsrv)
1211                         cmn_err(CE_CONT,
1212                                 "!IP Filter: nfsrv: info %x next %x ptr %x\n",
1213                                 q->q_nfsrv->q_qinfo, q->q_nfsrv->q_next,
1214                                 q->q_nfsrv->q_ptr);
1215                 if (q->q_nbsrv)
1216                         cmn_err(CE_CONT,
1217                                 "!IP Filter: nbsrv: info %x next %x ptr %x\n",
1218                                 q->q_nbsrv->q_qinfo, q->q_nbsrv->q_next,
1219                                 q->q_nbsrv->q_ptr);
1220                 frstats[1].fr_drop++;
1221                 mb->b_prev = NULL;
1222                 freemsg(mb);
1223                 RWLOCK_EXIT(&ipf_solaris);
1224                 return 0;
1225         }
1226
1227         qif->qf_outcnt++;
1228         pnext = qif->qf_wqinfo->qi_putp;
1229         if (type == M_IOCACK)
1230                 fr_qif_update(qif, mb);
1231         bcopy((char *)qif, (char *)&qf, sizeof(qf));
1232         if (datamsg(type) || (type == M_BREAK))
1233                 err = fr_precheck(&mb, q, &qf, 1);
1234
1235         RWLOCK_EXIT(&ipfs_mutex);
1236
1237         if ((err == 0) && (mb != NULL)) {
1238                 if (pnext) {
1239                         RWLOCK_EXIT(&ipf_solaris);
1240                         return (*pnext)(q, mb);
1241                 }
1242
1243                 cmn_err(CE_WARN,
1244                         "!IP Filter: outp NULL: qif %x %s q %x info %x",
1245                         qif, qf.qf_name, q, q->q_qinfo);
1246         }
1247
1248         if (err == -2) {
1249                 if (synced == 0) {
1250                         ipfsync();
1251                         synced = 1;
1252                         goto again;
1253                 }
1254                 frstats[1].fr_notip++;
1255                 if (!(fr_flags & FF_BLOCKNONIP) && (pnext != NULL)) {
1256                         RWLOCK_EXIT(&ipf_solaris);
1257                         return (*pnext)(q, mb);
1258                 }
1259         }
1260
1261         if (mb) {
1262                 mb->b_prev = NULL;
1263                 freemsg(mb);
1264         }
1265         RWLOCK_EXIT(&ipf_solaris);
1266         return 1;
1267 }
1268
1269
1270 void ipf_synctimeout(arg)
1271 void *arg;
1272 {
1273         if (fr_running < 0)
1274                 return;
1275         READ_ENTER(&ipf_solaris);
1276         ipfsync();
1277         WRITE_ENTER(&ipfs_mutex);
1278         synctimeoutid = 0;
1279         RWLOCK_EXIT(&ipfs_mutex);
1280         RWLOCK_EXIT(&ipf_solaris);
1281 }
1282
1283
1284 static int ipf_ip_qin(q, mb)
1285 queue_t *q;
1286 mblk_t *mb;
1287 {
1288         struct iocblk *ioc;
1289         int ret;
1290
1291         if (fr_running <= 0) {
1292                 mb->b_prev = NULL;
1293                 freemsg(mb);
1294                 return 0;
1295         }
1296
1297         if (MTYPE(mb) != M_IOCTL)
1298                 return (*ipf_ip_inp)(q, mb);
1299
1300         READ_ENTER(&ipf_solaris);
1301         if (fr_running <= 0) {
1302                 RWLOCK_EXIT(&ipf_solaris);
1303                 mb->b_prev = NULL;
1304                 freemsg(mb);
1305                 return 0;
1306         }
1307         ioc = (struct iocblk *)mb->b_rptr;
1308
1309         switch (ioc->ioc_cmd)
1310         {
1311         case DL_IOC_HDR_INFO:
1312                 fr_qif_update(qif_from_queue(q), mb);
1313                 break;
1314         case I_LINK:
1315         case I_UNLINK:
1316         case SIOCSIFADDR:
1317         case SIOCSIFFLAGS:
1318 #ifdef  IPFDEBUG
1319                 if (ipf_debug)
1320                         cmn_err(CE_NOTE,
1321                                 "IP Filter: ipf_ip_qin() M_IOCTL type=0x%x",
1322                                 ioc->ioc_cmd);
1323 #endif
1324                 WRITE_ENTER(&ipfs_mutex);
1325                 if (synctimeoutid == 0) {
1326                         synctimeoutid = timeout(ipf_synctimeout,
1327                                                 NULL,
1328                                                 drv_usectohz(1000000) /*1 sec*/
1329                                         );
1330                 }
1331                 RWLOCK_EXIT(&ipfs_mutex);
1332                 break;
1333         default:
1334                 break;
1335         }
1336         RWLOCK_EXIT(&ipf_solaris);
1337         return (*ipf_ip_inp)(q, mb);
1338 }
1339
1340 static int ipdrvattcnt = 0;
1341 extern struct streamtab ipinfo;
1342
1343 void solipdrvattach()
1344 {
1345 #ifdef  IPFDEBUG
1346         if (ipf_debug)
1347                 cmn_err(CE_NOTE, "IP Filter: solipdrvattach() %d ipinfo=0x%lx",
1348                         ipdrvattcnt, &ipinfo);
1349 #endif
1350
1351         if (++ipdrvattcnt == 1) {
1352                 if (ipf_ip_inp == NULL) {
1353                         ipf_ip_inp = ipinfo.st_wrinit->qi_putp;
1354                         ipinfo.st_wrinit->qi_putp = ipf_ip_qin;
1355                 }
1356         }
1357 }
1358
1359 int solipdrvdetach()
1360 {
1361 #ifdef  IPFDEBUG
1362         if (ipf_debug)
1363                 cmn_err(CE_NOTE, "IP Filter: solipdrvdetach() %d ipinfo=0x%lx",
1364                         ipdrvattcnt, &ipinfo);
1365 #endif
1366
1367         WRITE_ENTER(&ipfs_mutex);
1368         if (--ipdrvattcnt <= 0) {
1369                 if (ipf_ip_inp && (ipinfo.st_wrinit->qi_putp == ipf_ip_qin)) {
1370                         ipinfo.st_wrinit->qi_putp = ipf_ip_inp;
1371                         ipf_ip_inp = NULL;
1372                 }
1373                 if (synctimeoutid) {
1374                         untimeout(synctimeoutid);
1375                         synctimeoutid = 0;
1376                 }
1377         }
1378         RWLOCK_EXIT(&ipfs_mutex);
1379         return ipdrvattcnt;
1380 }
1381
1382 /*
1383  * attach the packet filter to each interface that is defined as having an
1384  * IP address associated with it and save some of the info. for that struct
1385  * so we're not out of date as soon as the ill disappears - but we must sync
1386  * to be correct!
1387  */
1388 void solattach()
1389 {
1390         queue_t *in, *out;
1391         struct frentry *f;
1392         qif_t *qif, *qf2;
1393         ipnat_t *np;
1394         size_t len;
1395         ill_t *il;
1396
1397         for (il = ill_g_head; il; il = il->ill_next) {
1398                 in = il->ill_rq;
1399                 if (!in || !il->ill_wq)
1400                         continue;
1401
1402                 out = il->ill_wq->q_next;
1403
1404                 WRITE_ENTER(&ipfs_mutex);
1405                 /*
1406                  * Look for entry already setup for this device
1407                  */
1408                 for (qif = qif_head; qif; qif = qif->qf_next)
1409                         if (qif->qf_iptr == in->q_ptr &&
1410                             qif->qf_optr == out->q_ptr)
1411                                 break;
1412                 if (qif) {
1413                         RWLOCK_EXIT(&ipfs_mutex);
1414                         continue;
1415                 }
1416 #ifdef  IPFDEBUGX
1417                 if (ipf_debug)
1418                 cmn_err(CE_NOTE,
1419                         "IP Filter: il %x ipt %x opt %x ipu %x opu %x i %x/%x",
1420                         il, in->q_ptr,  out->q_ptr, in->q_qinfo->qi_putp,
1421                         out->q_qinfo->qi_putp, out->q_qinfo, in->q_qinfo);
1422 #endif
1423                 KMALLOC(qif, qif_t *);
1424                 if (!qif) {
1425                         cmn_err(CE_WARN,
1426                                 "IP Filter: malloc(%d) for qif_t failed",
1427                                 sizeof(qif_t));
1428                         RWLOCK_EXIT(&ipfs_mutex);
1429                         continue;
1430                 }
1431
1432                 if (in->q_qinfo->qi_putp == fr_qin) {
1433                         for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
1434                                 if (&qf2->qf_rqinit == in->q_qinfo) {
1435                                         qif->qf_rqinfo = qf2->qf_rqinfo;
1436                                         break;
1437                                 }
1438                         if (!qf2) {
1439 #ifdef  IPFDEBUGX
1440                                 if (ipf_debug)
1441                                 cmn_err(CE_WARN,
1442                                         "IP Filter: rq:%s put %x qi %x",
1443                                         il->ill_name, in->q_qinfo->qi_putp,
1444                                         in->q_qinfo);
1445 #endif
1446                                 RWLOCK_EXIT(&ipfs_mutex);
1447                                 KFREE(qif);
1448                                 continue;
1449                         }
1450                 } else
1451                         qif->qf_rqinfo = in->q_qinfo;
1452
1453                 if (out->q_qinfo->qi_putp == fr_qout) {
1454                         for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
1455                                 if (&qf2->qf_wqinit == out->q_qinfo) {
1456                                         qif->qf_wqinfo = qf2->qf_wqinfo;
1457                                         break;
1458                                 }
1459                         if (!qf2) {
1460 #ifdef  IPFDEBUGX
1461                                 if (ipf_debug)
1462                                 cmn_err(CE_WARN,
1463                                         "IP Filter: wq:%s put %x qi %x",
1464                                         il->ill_name, out->q_qinfo->qi_putp,
1465                                         out->q_qinfo);
1466 #endif
1467                                 RWLOCK_EXIT(&ipfs_mutex);
1468                                 KFREE(qif);
1469                                 continue;
1470                         }
1471                 } else
1472                         qif->qf_wqinfo = out->q_qinfo;
1473
1474                 qif->qf_ill = il;
1475                 qif->qf_in = in;
1476                 qif->qf_out = out;
1477                 qif->qf_iptr = in->q_ptr;
1478                 qif->qf_optr = out->q_ptr;
1479 #if SOLARIS2 < 8
1480                 qif->qf_hl = il->ill_hdr_length;
1481 #else
1482                 {
1483                 ire_t *ire;
1484                 mblk_t *m;
1485
1486                 qif->qf_hl = 0;
1487                 qif->qf_sap = il->ill_sap;
1488 # if 0
1489                 /*
1490                  * Can't seem to lookup a route for the IP address on the
1491                  * interface itself.
1492                  */
1493                 ire = ire_route_lookup(il->ill_ipif->ipif_lcl_addr, 0xffffffff,
1494                                         0, 0, NULL, NULL, NULL,
1495                                         MATCH_IRE_DSTONLY|MATCH_IRE_RECURSIVE);
1496                 if ((ire != NULL) && (m = ire->ire_fp_mp))
1497                         qif->qf_hl = m->b_wptr - m->b_rptr;
1498 # endif
1499                 if ((qif->qf_hl == 0) && (il->ill_type > 0) &&
1500                     (il->ill_type < 0x37) &&
1501                     (hdrsizes[il->ill_type][0] == il->ill_type))
1502                         qif->qf_hl = hdrsizes[il->ill_type][1];
1503
1504                 /* DREADFUL VLAN HACK - JUST HERE TO CHECK IT WORKS */
1505                 if (il->ill_type == IFT_ETHER &&
1506                     il->ill_name[0] == 'c' && il->ill_name[1] == 'e' &&
1507                     isdigit(il->ill_name[2]) && il->ill_name_length >= 6) {
1508                         cmn_err(CE_NOTE, "VLAN HACK ENABLED");
1509                         qif->qf_hl += 4;
1510                 }
1511                 /* DREADFUL VLAN HACK - JUST HERE TO CHECK IT WORKS */
1512
1513                 if (qif->qf_hl == 0 && il->ill_type != IFT_OTHER)
1514                         cmn_err(CE_WARN,
1515                                 "Unknown layer 2 header size for %s type %d",
1516                                 il->ill_name, il->ill_type);
1517                 }
1518
1519                 /*
1520                  * XXX Awful hack for PPP; fix when PPP/snoop fixed.
1521                  */
1522                 if (il->ill_type == IFT_ETHER && !il->ill_bcast_addr_length)
1523                         qif->qf_hl = 0;
1524 #endif
1525                 strncpy(qif->qf_name, il->ill_name, sizeof(qif->qf_name));
1526                 qif->qf_name[sizeof(qif->qf_name) - 1] = '\0';
1527
1528                 qif->qf_next = qif_head;
1529                 qif_head = qif;
1530
1531                 /*
1532                  * Activate any rules directly associated with this interface
1533                  */
1534                 WRITE_ENTER(&ipf_mutex);
1535                 for (f = ipfilter[0][fr_active]; f; f = f->fr_next) {
1536                         if ((f->fr_ifa == (struct ifnet *)-1)) {
1537                                 len = strlen(f->fr_ifname) + 1;
1538                                 if ((len != 0) &&
1539                                     (len == (size_t)il->ill_name_length) &&
1540                                     !strncmp(il->ill_name, f->fr_ifname, len))
1541                                         f->fr_ifa = il;
1542                         }
1543                 }
1544                 for (f = ipfilter[1][fr_active]; f; f = f->fr_next) {
1545                         if ((f->fr_ifa == (struct ifnet *)-1)) {
1546                                 len = strlen(f->fr_ifname) + 1;
1547                                 if ((len != 0) &&
1548                                     (len == (size_t)il->ill_name_length) &&
1549                                     !strncmp(il->ill_name, f->fr_ifname, len))
1550                                         f->fr_ifa = il;
1551                         }
1552                 }
1553 #if SOLARIS2 >= 8
1554                 for (f = ipfilter6[0][fr_active]; f; f = f->fr_next) {
1555                         if ((f->fr_ifa == (struct ifnet *)-1)) {
1556                                 len = strlen(f->fr_ifname) + 1;
1557                                 if ((len != 0) &&
1558                                     (len == (size_t)il->ill_name_length) &&
1559                                     !strncmp(il->ill_name, f->fr_ifname, len))
1560                                         f->fr_ifa = il;
1561                         }
1562                 }
1563                 for (f = ipfilter6[1][fr_active]; f; f = f->fr_next) {
1564                         if ((f->fr_ifa == (struct ifnet *)-1)) {
1565                                 len = strlen(f->fr_ifname) + 1;
1566                                 if ((len != 0) &&
1567                                     (len == (size_t)il->ill_name_length) &&
1568                                     !strncmp(il->ill_name, f->fr_ifname, len))
1569                                         f->fr_ifa = il;
1570                         }
1571                 }
1572 #endif
1573                 RWLOCK_EXIT(&ipf_mutex);
1574                 WRITE_ENTER(&ipf_nat);
1575                 for (np = nat_list; np; np = np->in_next) {
1576                         if ((np->in_ifp == (struct ifnet *)-1)) {
1577                                 len = strlen(np->in_ifname) + 1;
1578                                 if ((len != 0) &&
1579                                     (len == (size_t)il->ill_name_length) &&
1580                                     !strncmp(il->ill_name, np->in_ifname, len))
1581                                         np->in_ifp = il;
1582                         }
1583                 }
1584                 RWLOCK_EXIT(&ipf_nat);
1585
1586                 bcopy((caddr_t)qif->qf_rqinfo, (caddr_t)&qif->qf_rqinit,
1587                       sizeof(struct qinit));
1588                 qif->qf_rqinit.qi_putp = fr_qin;
1589 #ifdef  IPFDEBUG
1590                 if (ipf_debug)
1591                         cmn_err(CE_NOTE,
1592                                 "IP Filter: solattach: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1593                                 in, in->q_qinfo, &qif->qf_rqinit);
1594 #endif
1595                 in->q_qinfo = &qif->qf_rqinit;
1596
1597                 bcopy((caddr_t)qif->qf_wqinfo, (caddr_t)&qif->qf_wqinit,
1598                       sizeof(struct qinit));
1599                 qif->qf_wqinit.qi_putp = fr_qout;
1600 #ifdef  IPFDEBUG
1601                 if (ipf_debug)
1602                         cmn_err(CE_NOTE,
1603                                 "IP Filter: solattach: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1604                                 out, out->q_qinfo, &qif->qf_wqinit);
1605 #endif
1606                 out->q_qinfo = &qif->qf_wqinit;
1607
1608                 ire_walk(ipf_ire_walk, (char *)qif);
1609                 RWLOCK_EXIT(&ipfs_mutex);
1610                 cmn_err(CE_CONT, "IP Filter: attach to [%s,%d] - %s\n",
1611                         qif->qf_name, il->ill_ppa,
1612 #if SOLARIS2 >= 8
1613                         il->ill_isv6 ? "IPv6" : "IPv4"
1614 #else
1615                         "IPv4"
1616 #endif
1617                         );
1618         }
1619         if (!qif_head)
1620                 cmn_err(CE_CONT, "IP Filter: not attached to any interfaces\n");
1621         return;
1622 }
1623
1624
1625 /*
1626  * look for bad consistancies between the list of interfaces the filter knows
1627  * about and those which are currently configured.
1628  */
1629 int ipfsync()
1630 {
1631         register struct frentry *f;
1632         register ipnat_t *np;
1633         register qif_t *qif, **qp;
1634         register ill_t *il;
1635         queue_t *in, *out;
1636
1637         WRITE_ENTER(&ipfs_mutex);
1638         for (qp = &qif_head; (qif = *qp); ) {
1639                 for (il = ill_g_head; il; il = il->ill_next)
1640                         if ((qif->qf_ill == il) &&
1641                             !strcmp(qif->qf_name, il->ill_name)) {
1642 #if SOLARIS2 < 8
1643                                 mblk_t  *m = il->ill_hdr_mp;
1644
1645                                 qif->qf_hl = il->ill_hdr_length;
1646                                 if (m && qif->qf_hl != (m->b_wptr - m->b_rptr))
1647                                         cmn_err(CE_NOTE,
1648                                                 "IP Filter: ILL Header Length Mismatch\n");
1649 #endif
1650                                 break;
1651                         }
1652                 if (il) {
1653                         qp = &qif->qf_next;
1654                         continue;
1655                 }
1656                 cmn_err(CE_CONT, "IP Filter: detaching [%s] - %s\n",
1657                         qif->qf_name,
1658 #if SOLARIS2 >= 8
1659                         (qif->qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4"
1660 #else
1661                         "IPv4"
1662 #endif
1663                         );
1664                 *qp = qif->qf_next;
1665
1666                 /*
1667                  * Disable any rules directly associated with this interface
1668                  */
1669                 WRITE_ENTER(&ipf_nat);
1670                 for (np = nat_list; np; np = np->in_next)
1671                         if (np->in_ifp == (void *)qif->qf_ill)
1672                                 np->in_ifp = (struct ifnet *)-1;
1673                 RWLOCK_EXIT(&ipf_nat);
1674                 WRITE_ENTER(&ipf_mutex);
1675                 for (f = ipfilter[0][fr_active]; f; f = f->fr_next)
1676                         if (f->fr_ifa == (void *)qif->qf_ill)
1677                                 f->fr_ifa = (struct ifnet *)-1;
1678                 for (f = ipfilter[1][fr_active]; f; f = f->fr_next)
1679                         if (f->fr_ifa == (void *)qif->qf_ill)
1680                                 f->fr_ifa = (struct ifnet *)-1;
1681 #if SOLARIS2 >= 8
1682                 for (f = ipfilter6[0][fr_active]; f; f = f->fr_next)
1683                         if (f->fr_ifa == (void *)qif->qf_ill)
1684                                 f->fr_ifa = (struct ifnet *)-1;
1685                 for (f = ipfilter6[1][fr_active]; f; f = f->fr_next)
1686                         if (f->fr_ifa == (void *)qif->qf_ill)
1687                                 f->fr_ifa = (struct ifnet *)-1;
1688 #endif
1689
1690 #if 0 /* XXX */
1691                 /*
1692                  * As well as the ill disappearing when a device is unplumb'd,
1693                  * it also appears that the associated queue structures also
1694                  * disappear - at least in the case of ppp, which is the most
1695                  * volatile here.  Thanks to Greg for finding this problem.
1696                  */
1697                 /*
1698                  * Restore q_qinfo pointers in interface queues
1699                  */
1700                 out = qif->qf_out;
1701                 in = qif->qf_in;
1702                 if (in) {
1703 # ifdef IPFDEBUG
1704                         if (ipf_debug)
1705                                 cmn_err(CE_NOTE,
1706                                         "IP Filter: ipfsync: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1707                                         in, in->q_qinfo, qif->qf_rqinfo);
1708 # endif
1709                         in->q_qinfo = qif->qf_rqinfo;
1710                 }
1711                 if (out) {
1712 # ifdef IPFDEBUG
1713                         if (ipf_debug)
1714                                 cmn_err(CE_NOTE,
1715                                         "IP Filter: ipfsync: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1716                                         out, out->q_qinfo, qif->qf_wqinfo);
1717 # endif
1718                         out->q_qinfo = qif->qf_wqinfo;
1719                 }
1720 #endif /* XXX */
1721                 RWLOCK_EXIT(&ipf_mutex);
1722                 KFREE(qif);
1723                 qif = *qp;
1724         }
1725         RWLOCK_EXIT(&ipfs_mutex);
1726         solattach();
1727
1728         frsync();
1729         /*
1730          * Resync. any NAT `connections' using this interface and its IP #.
1731          */
1732         for (il = ill_g_head; il; il = il->ill_next) {
1733                 ip_natsync((void *)il);
1734                 ip_statesync((void *)il);
1735         }
1736         return 0;
1737 }
1738
1739
1740 /*
1741  * unhook the IP filter from all defined interfaces with IP addresses
1742  */
1743 int soldetach()
1744 {
1745         queue_t *in, *out;
1746         qif_t *qif, **qp;
1747         ill_t *il;
1748
1749         WRITE_ENTER(&ipfs_mutex);
1750         /*
1751          * Make two passes, first get rid of all the unknown devices, next
1752          * unlink known devices.
1753          */
1754         for (qp = &qif_head; (qif = *qp); ) {
1755                 for (il = ill_g_head; il; il = il->ill_next)
1756                         if (qif->qf_ill == il)
1757                                 break;
1758                 if (il) {
1759                         qp = &qif->qf_next;
1760                         continue;
1761                 }
1762                 cmn_err(CE_CONT, "IP Filter: removing [%s]\n", qif->qf_name);
1763                 *qp = qif->qf_next;
1764                 KFREE(qif);
1765         }
1766
1767         while ((qif = qif_head)) {
1768                 qif_head = qif->qf_next;
1769                 for (il = ill_g_head; il; il = il->ill_next)
1770                         if (qif->qf_ill == il)
1771                                 break;
1772                 if (il) {
1773                         in = qif->qf_in;
1774                         out = qif->qf_out;
1775                         cmn_err(CE_CONT, "IP Filter: detaching [%s,%d] - %s\n",
1776                                 qif->qf_name, il->ill_ppa,
1777 #if SOLARIS2 >= 8
1778                         (qif->qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4"
1779 #else
1780                         "IPv4"
1781 #endif
1782                         );
1783
1784 #ifdef  IPFDEBUG
1785                         if (ipf_debug)
1786                                 cmn_err(CE_NOTE,
1787                                         "IP Filter: soldetach: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1788                                         in, in->q_qinfo, qif->qf_rqinfo);
1789 #endif
1790                         in->q_qinfo = qif->qf_rqinfo;
1791
1792                         /*
1793                          * and the write queue...
1794                          */
1795 #ifdef  IPFDEBUG
1796                         if (ipf_debug)
1797                                 cmn_err(CE_NOTE,
1798                                         "IP Filter: soldetach: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1799                                         out, out->q_qinfo, qif->qf_wqinfo);
1800 #endif
1801                         out->q_qinfo = qif->qf_wqinfo;
1802                 }
1803                 KFREE(qif);
1804         }
1805         RWLOCK_EXIT(&ipfs_mutex);
1806         return ipldetach();
1807 }
1808
1809
1810 #ifdef  IPFDEBUG
1811 void printire(ire)
1812 ire_t *ire;
1813 {
1814         if (!ipf_debug)
1815                 return;
1816         printf("ire: ll_hdr_mp %p rfq %p stq %p src_addr %x max_frag %d\n",
1817 # if SOLARIS2 >= 8
1818                 NULL,
1819 # else
1820                 ire->ire_ll_hdr_mp,
1821 # endif
1822                 ire->ire_rfq, ire->ire_stq,
1823                 ire->ire_src_addr, ire->ire_max_frag);
1824         printf("ire: mask %x addr %x gateway_addr %x type %d\n",
1825                 ire->ire_mask, ire->ire_addr, ire->ire_gateway_addr,
1826                 ire->ire_type);
1827         printf("ire: ll_hdr_length %d ll_hdr_saved_mp %p\n",
1828                 ire->ire_ll_hdr_length,
1829 # if SOLARIS2 >= 8
1830                 NULL
1831 # else
1832                 ire->ire_ll_hdr_saved_mp
1833 # endif
1834                 );
1835 }
1836 #endif
1837
1838
1839 int ipfr_fastroute(ip, mb, mpp, fin, fdp)
1840 ip_t *ip;
1841 mblk_t *mb, **mpp;
1842 fr_info_t *fin;
1843 frdest_t *fdp;
1844 {
1845 #ifdef  USE_INET6
1846         ip6_t *ip6 = (ip6_t *)ip;
1847 #endif
1848         ire_t *ir, *dir, *gw;
1849         struct in_addr dst;
1850         queue_t *q = NULL;
1851         mblk_t *mp = NULL;
1852         size_t hlen = 0;
1853         frentry_t *fr;
1854         frdest_t fd;
1855         ill_t *ifp;
1856         u_char *s;
1857         qif_t *qf;
1858         int p;
1859
1860 #ifndef sparc
1861         u_short __iplen, __ipoff;
1862 #endif
1863         qf = fin->fin_qif;
1864
1865         /*
1866          * If this is a duplicate mblk then we want ip to point at that
1867          * data, not the original, if and only if it is already pointing at
1868          * the current mblk data.
1869          */
1870         if ((ip == (ip_t *)qf->qf_m->b_rptr) && (qf->qf_m != mb))
1871                 ip = (ip_t *)mb->b_rptr;
1872
1873         /*
1874          * If there is another M_PROTO, we don't want it
1875          */
1876         if (*mpp != mb) {
1877                 mp = *mpp;
1878                 (void) unlinkb(mp);
1879                 mp = (*mpp)->b_cont;
1880                 (*mpp)->b_cont = NULL;
1881                 (*mpp)->b_prev = NULL;
1882                 freemsg(*mpp);
1883                 *mpp = mp;
1884         }
1885
1886         if (!fdp) {
1887                 ipif_t *ipif;
1888
1889                 ifp = fin->fin_ifp;
1890                 ipif = ifp->ill_ipif;
1891                 if (!ipif)
1892                         goto bad_fastroute;
1893 #if SOLARIS2 > 5
1894                 ir = ire_ctable_lookup(ipif->ipif_local_addr, 0, IRE_LOCAL,
1895                                        NULL, NULL, MATCH_IRE_TYPE);
1896 #else
1897                 ir = ire_lookup_myaddr(ipif->ipif_local_addr);
1898 #endif
1899                 if (!ir)
1900                         ir = (ire_t *)-1;
1901
1902                 fd.fd_ifp = (struct ifnet *)ir;
1903                 fd.fd_ip = ip->ip_dst;
1904                 fdp = &fd;
1905         }
1906
1907         ir = (ire_t *)fdp->fd_ifp;
1908
1909         if (fdp->fd_ip.s_addr)
1910                 dst = fdp->fd_ip;
1911         else
1912                 dst.s_addr = fin->fin_fi.fi_daddr;
1913
1914 #if SOLARIS2 >= 6
1915         gw = NULL;
1916         if (fin->fin_v == 4) {
1917                 p = ip->ip_p;
1918                 dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL,
1919                                         &gw, NULL, MATCH_IRE_DSTONLY|
1920                                         MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE);
1921         }
1922 # ifdef USE_INET6
1923         else if (fin->fin_v == 6) {
1924                 p = ip6->ip6_nxt;
1925                 dir = ire_route_lookup_v6(&ip6->ip6_dst, NULL, 0, 0,
1926                                         NULL, &gw, NULL, MATCH_IRE_DSTONLY|
1927                                         MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE);
1928         }
1929 # endif
1930 #else
1931         dir = ire_lookup(dst.s_addr);
1932 #endif
1933 #if SOLARIS2 < 8
1934         if (dir)
1935                 if (!dir->ire_ll_hdr_mp || !dir->ire_ll_hdr_length)
1936                         dir = NULL;
1937 #else
1938         if (dir)
1939                 if (!dir->ire_fp_mp || !dir->ire_dlureq_mp)
1940                         dir = NULL;
1941 #endif
1942
1943         if (!ir)
1944                 ir = dir;
1945
1946         if (ir && dir) {
1947                 ifp = ire_to_ill(ir);
1948                 if (ifp == NULL)
1949                         goto bad_fastroute;
1950                 fr = fin->fin_fr;
1951
1952                 /*
1953                  * In case we're here due to "to <if>" being used with
1954                  * "keep state", check that we're going in the correct
1955                  * direction.
1956                  */
1957                 if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
1958                     (fin->fin_rev != 0) && (fdp == &fr->fr_tif))
1959                         return 1;
1960
1961                 fin->fin_ifp = ifp;
1962                 if (fin->fin_out == 0) {
1963                         fin->fin_fr = ipacct[1][fr_active];
1964                         if ((fin->fin_fr != NULL) &&
1965                             (fr_scanlist(FR_NOMATCH, ip, fin, mb)&FR_ACCOUNT)){
1966                                 ATOMIC_INCL(frstats[1].fr_acct);
1967                         }
1968                         fin->fin_fr = NULL;
1969                         if (!fr || !(fr->fr_flags & FR_RETMASK))
1970                                 (void) fr_checkstate(ip, fin);
1971                         (void) ip_natout(ip, fin);
1972                 }
1973 #ifndef sparc
1974                 if (fin->fin_v == 4) {
1975                         __iplen = (u_short)ip->ip_len,
1976                         __ipoff = (u_short)ip->ip_off;
1977
1978                         ip->ip_len = htons(__iplen);
1979                         ip->ip_off = htons(__ipoff);
1980                 }
1981 #endif
1982
1983 #if SOLARIS2 < 8
1984                 mp = dir->ire_ll_hdr_mp;
1985                 hlen = dir->ire_ll_hdr_length;
1986 #else
1987                 mp = dir->ire_fp_mp;
1988                 hlen = mp ? mp->b_wptr - mp->b_rptr : 0;
1989                 mp = dir->ire_dlureq_mp;
1990 #endif
1991                 if (mp != NULL) {
1992                         s = mb->b_rptr;
1993                         if (
1994 #if SOLARIS2 >= 6
1995                             (dohwcksum &&
1996                              ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC) ||
1997 #endif
1998                             (hlen && (s - mb->b_datap->db_base) >= hlen)) {
1999                                 s -= hlen;
2000                                 mb->b_rptr = (u_char *)s;
2001                                 bcopy((char *)mp->b_rptr, (char *)s, hlen);
2002                         } else {
2003                                 mblk_t  *mp2;
2004
2005                                 mp2 = copyb(mp);
2006                                 if (!mp2)
2007                                         goto bad_fastroute;
2008                                 linkb(mp2, mb);
2009                                 mb = mp2;
2010                         }
2011                 }
2012                 *mpp = mb;
2013
2014                 if (ir->ire_stq)
2015                         q = ir->ire_stq;
2016                 else if (ir->ire_rfq)
2017                         q = WR(ir->ire_rfq);
2018                 if (q) {
2019                         mb->b_prev = NULL;
2020                         mb->b_queue = q;
2021                         RWLOCK_EXIT(&ipfs_mutex);
2022                         RWLOCK_EXIT(&ipf_solaris);
2023 #if SOLARIS2 >= 6
2024                         if ((p == IPPROTO_TCP) && dohwcksum &&
2025                             (ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {
2026                                 tcphdr_t *tcp;
2027                                 u_32_t t;
2028
2029                                 tcp = (tcphdr_t *)((char *)ip + fin->fin_hlen);
2030                                 t = ip->ip_src.s_addr;
2031                                 t += ip->ip_dst.s_addr;
2032                                 t += 30;
2033                                 t = (t & 0xffff) + (t >> 16);
2034                                 tcp->th_sum = t & 0xffff;
2035                         }
2036 #endif
2037                         putnext(q, mb);
2038                         READ_ENTER(&ipf_solaris);
2039                         READ_ENTER(&ipfs_mutex);
2040                         ipl_frouteok[0]++;
2041                         *mpp = NULL;
2042                         return 0;
2043                 }
2044         }
2045 bad_fastroute:
2046         mb->b_prev = NULL;
2047         freemsg(mb);
2048         ipl_frouteok[1]++;
2049         *mpp = NULL;
2050         return -1;
2051 }
2052
2053
2054 void copyout_mblk(m, off, len, buf)
2055 mblk_t *m;
2056 size_t off, len;
2057 char *buf;
2058 {
2059         u_char *s, *bp = (u_char *)buf;
2060         size_t mlen, olen, clen;
2061
2062         for (; m && len; m = m->b_cont) {
2063                 if (MTYPE(m) != M_DATA)
2064                         continue;
2065                 s = m->b_rptr;
2066                 mlen = m->b_wptr - s;
2067                 olen = MIN(off, mlen);
2068                 if ((olen == mlen) || (olen < off)) {
2069                         off -= olen;
2070                         continue;
2071                 } else if (olen) {
2072                         off -= olen;
2073                         s += olen;
2074                         mlen -= olen;
2075                 }
2076                 clen = MIN(mlen, len);
2077                 bcopy(s, bp, clen);
2078                 len -= clen;
2079                 bp += clen;
2080         }
2081 }
2082
2083
2084 void copyin_mblk(m, off, len, buf)
2085 mblk_t *m;
2086 size_t off, len;
2087 char *buf;
2088 {
2089         u_char *s, *bp = (u_char *)buf;
2090         size_t mlen, olen, clen;
2091
2092         for (; m && len; m = m->b_cont) {
2093                 if (MTYPE(m) != M_DATA)
2094                         continue;
2095                 s = m->b_rptr;
2096                 mlen = m->b_wptr - s;
2097                 olen = MIN(off, mlen);
2098                 if ((olen == mlen) || (olen < off)) {
2099                         off -= olen;
2100                         continue;
2101                 } else if (olen) {
2102                         off -= olen;
2103                         s += olen;
2104                         mlen -= olen;
2105                 }
2106                 clen = MIN(mlen, len);
2107                 bcopy(bp, s, clen);
2108                 len -= clen;
2109                 bp += clen;
2110         }
2111 }
2112
2113
2114 int fr_verifysrc(ipa, ifp)
2115 struct in_addr ipa;
2116 void *ifp;
2117 {
2118         ire_t *ir, *dir, *gw;
2119
2120 #if SOLARIS2 >= 6
2121         dir = ire_route_lookup(ipa.s_addr, 0xffffffff, 0, 0, NULL, &gw, NULL,
2122                                 MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|
2123                                 MATCH_IRE_RECURSIVE);
2124 #else
2125         dir = ire_lookup(ipa.s_addr);
2126 #endif
2127
2128         if (!dir)
2129                 return 0;
2130         return (ire_to_ill(dir) == ifp);
2131 }