2 * Copyright (C) 1993-1998 by Darren Reed.
4 * Redistribution and use in source and binary forms are permitted
5 * provided that this notice is preserved and due credit is given
6 * to the original author and the contributors.
8 /* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/
9 #pragma ident "@(#)$Id: solaris.c,v 2.1.2.5 1999/10/15 13:49:44 darrenr Exp $";
11 #include <sys/systm.h>
12 #include <sys/types.h>
13 #include <sys/param.h>
14 #include <sys/errno.h>
17 #include <sys/modctl.h>
21 #include <sys/cmn_err.h>
24 #include <sys/dditypes.h>
25 #include <sys/stream.h>
27 #include <sys/autoconf.h>
28 #include <sys/byteorder.h>
29 #include <sys/socket.h>
31 #include <sys/stropts.h>
32 #include <sys/sockio.h>
35 #include <net/route.h>
36 #include <netinet/in.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/if_ether.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_var.h>
41 #include <netinet/tcp.h>
42 #include <netinet/udp.h>
43 #include <netinet/tcpip.h>
44 #include <netinet/ip_icmp.h>
46 #include <sys/sunddi.h>
47 #include "ip_compat.h"
53 char _depends_on[] = "drv/ip";
56 void solipdrvattach __P((void));
57 int solipdrvdetach __P((void));
59 void solattach __P((void));
60 int soldetach __P((void));
62 extern struct filterstats frstats[];
63 extern KRWLOCK_T ipf_mutex, ipfs_mutex, ipf_nat, ipf_solaris;
64 extern kmutex_t ipf_rw;
65 extern int fr_running;
68 extern ipnat_t *nat_list;
70 static qif_t *qif_head = NULL;
71 static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
73 static int ipf_probe __P((dev_info_t *));
74 static int ipf_identify __P((dev_info_t *));
75 static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
76 static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
77 static qif_t *qif_from_queue __P((queue_t *));
78 static void fr_donotip __P((int, qif_t *, queue_t *, mblk_t *,
79 mblk_t *, ip_t *, size_t));
80 static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH,
82 static int (*ipf_ip_inp) __P((queue_t *, mblk_t *)) = NULL;
86 extern void ipfr_slowtimer __P((void *));
87 timeout_id_t ipfr_timer_id;
88 static timeout_id_t synctimeoutid = 0;
90 extern void ipfr_slowtimer __P((void));
92 static int synctimeoutid = 0;
96 void printire __P((ire_t *));
98 static int fr_precheck __P((mblk_t **, queue_t *, qif_t *, int));
101 static struct cb_ops ipf_cb_ops = {
104 nodev, /* strategy */
109 iplioctl, /* ioctl */
124 static struct dev_ops ipf_ops = {
137 extern struct mod_ops mod_driverops;
138 static struct modldrv iplmod = {
139 &mod_driverops, IPL_VERSION, &ipf_ops };
140 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
143 static dev_info_t *ipf_dev_info = NULL;
152 ipfinst = mod_install(&modlink1);
154 cmn_err(CE_NOTE, "IP Filter: _init() = %d\n", ipfinst);
166 ipfinst = mod_remove(&modlink1);
168 cmn_err(CE_NOTE, "IP Filter: _fini() = %d\n", ipfinst);
175 struct modinfo *modinfop;
181 ipfinst = mod_info(&modlink1, modinfop);
183 cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x\n", modinfop, ipfinst);
191 static int ipf_probe(dip)
195 return DDI_PROBE_FAILURE;
197 cmn_err(CE_NOTE, "IP Filter: ipf_probe(%x)", dip);
199 return DDI_PROBE_SUCCESS;
203 static int ipf_identify(dip)
207 cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip);
209 if (strcmp(ddi_get_name(dip), "ipf") == 0)
210 return (DDI_IDENTIFIED);
211 return (DDI_NOT_IDENTIFIED);
215 static int ipf_attach(dip, cmd)
217 ddi_attach_cmd_t cmd;
222 cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd);
229 instance = ddi_get_instance(dip);
231 cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance);
233 if (ddi_create_minor_node(dip, "ipf", S_IFCHR, IPL_LOGIPF,
234 DDI_PSEUDO, 0) == DDI_FAILURE) {
235 ddi_remove_minor_node(dip, NULL);
238 if (ddi_create_minor_node(dip, "ipnat", S_IFCHR, IPL_LOGNAT,
239 DDI_PSEUDO, 0) == DDI_FAILURE) {
240 ddi_remove_minor_node(dip, NULL);
243 if (ddi_create_minor_node(dip, "ipstate", S_IFCHR,IPL_LOGSTATE,
244 DDI_PSEUDO, 0) == DDI_FAILURE) {
245 ddi_remove_minor_node(dip, NULL);
248 if (ddi_create_minor_node(dip, "ipauth", S_IFCHR, IPL_LOGAUTH,
249 DDI_PSEUDO, 0) == DDI_FAILURE) {
250 ddi_remove_minor_node(dip, NULL);
258 if (iplattach() == -1)
261 * Lock people out while we set things up.
263 WRITE_ENTER(&ipf_solaris);
266 RWLOCK_EXIT(&ipf_solaris);
267 cmn_err(CE_CONT, "%s, attaching complete.\n", ipfilter_version);
271 if (ipfr_timer_id == 0)
272 ipfr_timer_id = timeout(ipfr_slowtimer, NULL,
273 drv_usectohz(500000));
281 cmn_err(CE_NOTE, "IP Filter: failed to attach\n");
283 * Use our own detach routine to toss
284 * away any stuff we allocated above.
286 (void) ipf_detach(dip, DDI_DETACH);
291 static int ipf_detach(dip, cmd)
293 ddi_detach_cmd_t cmd;
298 cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
305 * Make sure we're the only one's modifying things. With
306 * this lock others should just fall out of the loop.
308 mutex_enter(&ipf_rw);
309 if (ipfr_timer_id != 0) {
310 untimeout(ipfr_timer_id);
314 WRITE_ENTER(&ipf_solaris);
315 mutex_enter(&ipf_rw);
316 if (fr_running <= 0) {
322 /* NOTE: ipf_solaris rwlock is released in ipldetach */
325 * Undo what we did in ipf_attach, freeing resources
326 * and removing things we installed. The system
327 * framework guarantees we are not active with this devinfo
328 * node in any other entry points at this time.
330 ddi_prop_remove_all(dip);
331 i = ddi_get_instance(dip);
332 ddi_remove_minor_node(dip, NULL);
334 i = solipdrvdetach();
336 cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
340 cmn_err(CE_CONT, "IP Filter: detached\n");
341 return (DDI_SUCCESS);
344 return (DDI_FAILURE);
350 static int ipf_getinfo(dip, infocmd, arg, result)
352 ddi_info_cmd_t infocmd;
361 cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg);
364 case DDI_INFO_DEVT2DEVINFO:
365 *result = ipf_dev_info;
368 case DDI_INFO_DEVT2INSTANCE:
369 *result = (void *)getminor((dev_t) arg);
379 * find the filter structure setup for this queue
381 static qif_t *qif_from_queue(q)
386 for (qif = qif_head; qif; qif = qif->qf_next)
387 if ((qif->qf_iptr == q->q_ptr) || (qif->qf_optr == q->q_ptr))
394 * OK, this is pretty scrappy code, but then it's essentially just here for
395 * debug purposes and that's it. Packets should not normally come through
396 * here, and if they do, well, we would like to see as much information as
397 * possible about them and what they claim to hold.
399 void fr_donotip(out, qif, q, m, mt, ip, off)
407 u_char *s, outb[256], *t;
414 s = ip ? (u_char *)ip : outb;
415 if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA))
418 printf("!IP %s:%d %d %p %p %p %d %p/%d %p/%d %p %d %d %p\n",
419 qif ? qif->qf_name : "?", out, qif->qf_hl, q,
420 q ? q->q_ptr : NULL, q ? q->q_qinfo : NULL,
421 mt->b_wptr - mt->b_rptr, m, MTYPE(m), mt, MTYPE(mt), m->b_rptr,
422 m->b_wptr - m->b_rptr, off, ip);
423 printf("%02x%02x%02x%02x\n", *s, *(s+1), *(s+2), *(s+3));
428 sprintf((char *)t, "%d:", MTYPE(mt));
429 t += strlen((char *)t);
430 for (; (i < 100) && (s < mt->b_wptr); i++) {
431 sprintf((char *)t, "%02x%s", *s++,
432 ((i & 3) == 3) ? " " : "");
433 t += ((i & 3) == 3) ? 3 : 2;
443 sprintf((char *)t, "%d:", MTYPE(m));
444 t += strlen((char *)t);
445 for (; (i < 100) && (s < m->b_wptr); i++) {
446 sprintf((char *)t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
447 t += ((i & 3) == 3) ? 3 : 2;
456 * find the first data mblk, if present, in the chain we're processing. Also
457 * make a few sanity checks to try prevent the filter from causing a panic -
458 * none of the nice IP sanity checks (including checksumming) should have been
459 * done yet (for incoming packets) - dangerous!
461 static int fr_precheck(mp, q, qif, out)
467 register mblk_t *m, *mt = *mp;
469 size_t hlen, len, off, mlen, iphlen;
473 u_short __iplen, __ipoff;
477 * If there is only M_DATA for a packet going out, then any header
478 * information (which would otherwise appear in an M_PROTO mblk before
479 * the M_DATA) is prepended before the IP header. We need to set the
480 * offset to account for this. - see MMM
482 off = (out) ? qif->qf_hl : 0;
485 * If the message protocol block indicates that there isn't a data
486 * block following it, just return back.
488 bp = (u_char *)ALIGN32(mt->b_rptr);
489 if (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO) {
490 dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp;
491 if (dl->dl_primitive != DL_UNITDATA_IND &&
492 dl->dl_primitive != DL_UNITDATA_REQ) {
493 frstats[out].fr_notdata++;
499 * Find the first data block, count the data blocks in this chain and
500 * the total amount of data.
502 for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont)
503 off = 0; /* Any non-M_DATA cancels the offset */
506 frstats[out].fr_nodata++;
507 return 0; /* No data blocks */
511 * This is a complete kludge to try and work around some bizarre
512 * packets which drop through into fr_donotip.
514 if ((mt != m) && (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO)) {
515 dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp;
516 if ((dl->dl_primitive == DL_UNITDATA_IND) &&
517 (dl->dl_group_address == 1))
518 if (((*((u_char *)m->b_rptr) == 0x0) &&
519 ((*((u_char *)m->b_rptr + 2) == 0x45))))
523 ip = (ip_t *)(m->b_rptr + off); /* MMM */
526 * We might have a 1st data block which is really M_PROTO, i.e. it is
527 * only big enough for the link layer header
529 while ((u_char *)ip >= m->b_wptr) {
530 len = (u_char *)ip - m->b_wptr;
533 return 0; /* not enough data for IP */
534 ip = (ip_t *)(m->b_rptr + len);
536 off = (u_char *)ip - m->b_rptr;
538 m->b_rptr = (u_char *)ip;
541 len = m->b_wptr - m->b_rptr;
542 if (m->b_wptr < m->b_rptr) {
543 cmn_err(CE_NOTE, "IP Filter: Bad packet: wptr %p < rptr %p",
544 m->b_wptr, m->b_rptr);
545 frstats[out].fr_bad++;
549 * Ok, the IP header isn't on a 32bit aligned address so junk it.
551 if (((u_int)ip & 0x3) || (len < sizeof(*ip))) {
553 * We have link layer header and IP header in the same mbuf,
554 * problem being that a pullup without adjusting b_rptr will
555 * bring us back here again as it's likely that the start of
556 * the databuffer (b_datab->db_base) is already aligned. Hmm,
557 * should we pull it all up (length of -1 to pullupmsg) if we
561 if (off == (u_char *)ip - m->b_rptr) {
565 if (!pullupmsg(m, sizeof(ip_t) + off)) {
566 cmn_err(CE_NOTE, "pullupmsg failed\n");
567 frstats[out].fr_pull[1]++;
570 frstats[out].fr_pull[0]++;
576 if (ip->ip_v != IPVERSION) {
580 RWLOCK_EXIT(&ipfs_mutex);
582 READ_ENTER(&ipfs_mutex);
585 fr_donotip(out, qif, q, m, mt, ip, off);
586 frstats[out].fr_notip++;
587 return (fr_flags & FF_BLOCKNONIP) ? -1 : 0;
591 __iplen = (u_short)ip->ip_len,
592 __ipoff = (u_short)ip->ip_off;
594 ip->ip_len = ntohs(__iplen);
595 ip->ip_off = ntohs(__ipoff);
598 hlen = iphlen = ip->ip_hl << 2;
600 if ((iphlen < sizeof(ip_t)) || (iphlen > (u_short)ip->ip_len) ||
601 (mlen < (u_short)ip->ip_len)) {
603 * Bad IP packet or not enough data/data length mismatches
606 "IP Filter: Bad packet: iphlen %u ip_len %u mlen %u",
607 iphlen, ip->ip_len, mlen);
609 __iplen = (u_short)ip->ip_len,
610 __ipoff = (u_short)ip->ip_off;
612 ip->ip_len = htons(__iplen);
613 ip->ip_off = htons(__ipoff);
616 frstats[out].fr_bad++;
621 * Make hlen the total size of the IP header plus TCP/UDP/ICMP header
622 * (if it is one of these three).
624 if ((ip->ip_off & IP_OFFMASK) == 0)
628 hlen += sizeof(tcphdr_t);
631 hlen += sizeof(udphdr_t);
634 /* 76 bytes is enough for a complete ICMP error. */
635 hlen += 76 + sizeof(icmphdr_t);
645 * If we don't have enough data in the mblk or we haven't yet copied
646 * enough (above), then copy some more.
649 if (!pullupmsg(m, (int)hlen)) {
650 cmn_err(CE_NOTE, "pullupmsg failed\n");
651 frstats[out].fr_pull[1]++;
654 frstats[out].fr_pull[0]++;
655 ip = (ip_t *)ALIGN32(m->b_rptr);
661 err = fr_check(ip, iphlen, qif->qf_ill, out, qif, mp);
665 * Copy back the ip header data if it was changed, we haven't yet
666 * freed the message and we aren't going to drop the packet.
667 * BUT only do this if there were no changes to the buffer, else
668 * we can't be sure that the ip pointer is still correct!
674 __iplen = (u_short)ip->ip_len,
675 __ipoff = (u_short)ip->ip_off;
677 ip->ip_len = htons(__iplen);
678 ip->ip_off = htons(__ipoff);
682 "IP Filter: *mp %p mt %p %s\n", *mp, mt,
683 "mblk changed, cannot revert ip_len, ip_off");
693 int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
696 if (fr_running <= 0) {
702 READ_ENTER(&ipf_solaris);
704 if (fr_running <= 0) {
705 RWLOCK_EXIT(&ipf_solaris);
710 READ_ENTER(&ipfs_mutex);
711 if (!(qif = qif_from_queue(q))) {
712 for (qif = qif_head; qif; qif = qif->qf_next)
713 if (&qif->qf_rqinit == q->q_qinfo && qif->qf_rqinfo &&
714 qif->qf_rqinfo->qi_putp) {
715 pnext = qif->qf_rqinfo->qi_putp;
716 frstats[0].fr_notip++;
717 RWLOCK_EXIT(&ipfs_mutex);
723 RWLOCK_EXIT(&ipf_solaris);
724 /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
725 return (*pnext)(q, mb);
727 RWLOCK_EXIT(&ipfs_mutex);
734 "IP Filter: dropped: fr_qin(%x,%x): type %x qif %x",
735 q, mb, MTYPE(mb), qif);
737 "IP Filter: info %x next %x ptr %x fsrv %x bsrv %x\n",
738 q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
740 cmn_err(CE_CONT, "IP Filter: info: putp %x srvp %x info %x\n",
741 q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
748 frstats[0].fr_drop++;
749 RWLOCK_EXIT(&ipf_solaris);
755 bcopy((char *)qif, (char *)&qf, sizeof(qf));
758 pnext = qif->qf_rqinfo->qi_putp;
760 if (datamsg(type) || (type == M_BREAK))
761 err = fr_precheck(&mb, q, qif, 0);
763 RWLOCK_EXIT(&ipfs_mutex);
764 RWLOCK_EXIT(&ipf_solaris);
766 if ((err == 0) && (mb != NULL)) {
768 return (*pnext)(q, mb);
770 cmn_err(CE_WARN, "IP Filter: inp NULL: qif %x q %x info %x",
785 int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
788 if (fr_running <= 0) {
794 READ_ENTER(&ipf_solaris);
796 if (fr_running <= 0) {
797 RWLOCK_EXIT(&ipf_solaris);
802 READ_ENTER(&ipfs_mutex);
803 if (!(qif = qif_from_queue(q))) {
804 for (qif = qif_head; qif; qif = qif->qf_next)
805 if (&qif->qf_wqinit == q->q_qinfo && qif->qf_wqinfo &&
806 qif->qf_wqinfo->qi_putp) {
807 pnext = qif->qf_wqinfo->qi_putp;
808 RWLOCK_EXIT(&ipfs_mutex);
809 frstats[1].fr_notip++;
815 /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
816 RWLOCK_EXIT(&ipf_solaris);
817 return (*pnext)(q, mb);
819 RWLOCK_EXIT(&ipfs_mutex);
826 "IP Filter: dropped: fr_qout(%x,%x): type %x: qif %x",
827 q, mb, MTYPE(mb), qif);
829 "IP Filter: info %x next %x ptr %x fsrv %x bsrv %x\n",
830 q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
832 cmn_err(CE_CONT, "IP Filter: info: putp %x srvp %x info %x\n",
833 q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
842 "IP Filter: nfsrv: info %x next %x ptr %x\n",
843 q->q_nfsrv->q_qinfo, q->q_nfsrv->q_next,
847 "IP Filter: nbsrv: info %x next %x ptr %x\n",
848 q->q_nbsrv->q_qinfo, q->q_nbsrv->q_next,
850 frstats[1].fr_drop++;
851 RWLOCK_EXIT(&ipf_solaris);
857 bcopy((char *)qif, (char *)&qf, sizeof(qf));
860 pnext = qif->qf_wqinfo->qi_putp;
862 if (datamsg(type) || (type == M_BREAK))
863 err = fr_precheck(&mb, q, qif, 1);
865 RWLOCK_EXIT(&ipfs_mutex);
866 RWLOCK_EXIT(&ipf_solaris);
868 if ((err == 0) && (mb != NULL)) {
870 return (*pnext)(q, mb);
872 cmn_err(CE_WARN, "IP Filter: outp NULL: qif %x %s q %x info %x",
873 qif, qif->qf_name, q, q->q_qinfo);
883 void ipf_synctimeout(arg)
886 READ_ENTER(&ipf_solaris);
888 WRITE_ENTER(&ipfs_mutex);
890 RWLOCK_EXIT(&ipfs_mutex);
891 RWLOCK_EXIT(&ipf_solaris);
894 static int ipf_ip_qin(q, mb)
901 if (fr_running <= 0) {
907 if (MTYPE(mb) != M_IOCTL)
908 return (*ipf_ip_inp)(q, mb);
910 READ_ENTER(&ipf_solaris);
911 if (fr_running <= 0) {
912 RWLOCK_EXIT(&ipf_solaris);
917 ioc = (struct iocblk *)mb->b_rptr;
919 switch (ioc->ioc_cmd) {
925 cmn_err(CE_NOTE, "IP Filter: ipf_ip_qin() M_IOCTL type=0x%x\n", ioc->ioc_cmd);
927 ret = (*ipf_ip_inp)(q, mb);
929 WRITE_ENTER(&ipfs_mutex);
930 if (synctimeoutid == 0) {
931 synctimeoutid = timeout(ipf_synctimeout,
933 drv_usectohz(1000000) /*1 sec*/
937 RWLOCK_EXIT(&ipfs_mutex);
940 ret = (*ipf_ip_inp)(q, mb);
942 RWLOCK_EXIT(&ipf_solaris);
946 static int ipdrvattcnt = 0;
947 extern struct streamtab ipinfo;
949 void solipdrvattach()
952 cmn_err(CE_NOTE, "IP Filter: solipdrvattach() %d ipinfo=0x%lx\n",
953 ipdrvattcnt, &ipinfo);
956 if (++ipdrvattcnt == 1) {
957 if (ipf_ip_inp == NULL) {
958 ipf_ip_inp = ipinfo.st_wrinit->qi_putp;
959 ipinfo.st_wrinit->qi_putp = ipf_ip_qin;
967 cmn_err(CE_NOTE, "IP Filter: solipdrvdetach() %d ipinfo=0x%lx\n",
968 ipdrvattcnt, &ipinfo);
971 WRITE_ENTER(&ipfs_mutex);
972 if (--ipdrvattcnt <= 0) {
973 if (ipf_ip_inp && (ipinfo.st_wrinit->qi_putp == ipf_ip_qin)) {
974 ipinfo.st_wrinit->qi_putp = ipf_ip_inp;
978 untimeout(synctimeoutid);
982 RWLOCK_EXIT(&ipfs_mutex);
987 * attach the packet filter to each interface that is defined as having an
988 * IP address associated with it and save some of the info. for that struct
989 * so we're not out of date as soon as the ill disappears - but we must sync
1001 for (il = ill_g_head; il; il = il->ill_next) {
1003 if (!in || !il->ill_wq)
1006 out = il->ill_wq->q_next;
1008 WRITE_ENTER(&ipfs_mutex);
1010 * Look for entry already setup for this device
1012 for (qif = qif_head; qif; qif = qif->qf_next)
1013 if (qif->qf_iptr == in->q_ptr &&
1014 qif->qf_optr == out->q_ptr)
1017 RWLOCK_EXIT(&ipfs_mutex);
1022 "IP Filter: il %x ipt %x opt %x ipu %x opu %x i %x/%x",
1023 il, in->q_ptr, out->q_ptr, in->q_qinfo->qi_putp,
1024 out->q_qinfo->qi_putp, out->q_qinfo, in->q_qinfo);
1026 KMALLOC(qif, qif_t *);
1029 "IP Filter: malloc(%d) for qif_t failed\n",
1031 RWLOCK_EXIT(&ipfs_mutex);
1035 if (in->q_qinfo->qi_putp == fr_qin) {
1036 for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
1037 if (&qf2->qf_rqinit == in->q_qinfo) {
1038 qif->qf_rqinfo = qf2->qf_rqinfo;
1044 "IP Filter: rq:%s put %x qi %x",
1045 il->ill_name, in->q_qinfo->qi_putp,
1048 RWLOCK_EXIT(&ipfs_mutex);
1053 qif->qf_rqinfo = in->q_qinfo;
1055 if (out->q_qinfo->qi_putp == fr_qout) {
1056 for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
1057 if (&qf2->qf_wqinit == out->q_qinfo) {
1058 qif->qf_wqinfo = qf2->qf_wqinfo;
1064 "IP Filter: wq:%s put %x qi %x",
1065 il->ill_name, out->q_qinfo->qi_putp,
1068 RWLOCK_EXIT(&ipfs_mutex);
1073 qif->qf_wqinfo = out->q_qinfo;
1078 qif->qf_iptr = in->q_ptr;
1079 qif->qf_optr = out->q_ptr;
1080 qif->qf_hl = il->ill_hdr_length;
1081 strncpy(qif->qf_name, il->ill_name, sizeof(qif->qf_name));
1082 qif->qf_name[sizeof(qif->qf_name) - 1] = '\0';
1084 qif->qf_next = qif_head;
1088 * Activate any rules directly associated with this interface
1090 WRITE_ENTER(&ipf_mutex);
1091 for (f = ipfilter[0][fr_active]; f; f = f->fr_next) {
1092 if ((f->fr_ifa == (struct ifnet *)-1)) {
1093 len = strlen(f->fr_ifname) + 1;
1095 (len == (size_t)il->ill_name_length) &&
1096 !strncmp(il->ill_name, f->fr_ifname, len))
1100 for (f = ipfilter[1][fr_active]; f; f = f->fr_next) {
1101 if ((f->fr_ifa == (struct ifnet *)-1)) {
1102 len = strlen(f->fr_ifname) + 1;
1104 (len == (size_t)il->ill_name_length) &&
1105 !strncmp(il->ill_name, f->fr_ifname, len))
1109 RWLOCK_EXIT(&ipf_mutex);
1110 WRITE_ENTER(&ipf_nat);
1111 for (np = nat_list; np; np = np->in_next) {
1112 if ((np->in_ifp == (struct ifnet *)-1)) {
1113 len = strlen(np->in_ifname) + 1;
1115 (len == (size_t)il->ill_name_length) &&
1116 !strncmp(il->ill_name, np->in_ifname, len))
1120 RWLOCK_EXIT(&ipf_nat);
1122 bcopy((caddr_t)qif->qf_rqinfo, (caddr_t)&qif->qf_rqinit,
1123 sizeof(struct qinit));
1124 qif->qf_rqinit.qi_putp = fr_qin;
1127 "IP Filter: solattach: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1128 in, in->q_qinfo, &qif->qf_rqinit
1131 in->q_qinfo = &qif->qf_rqinit;
1133 bcopy((caddr_t)qif->qf_wqinfo, (caddr_t)&qif->qf_wqinit,
1134 sizeof(struct qinit));
1135 qif->qf_wqinit.qi_putp = fr_qout;
1138 "IP Filter: solattach: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1139 out, out->q_qinfo, &qif->qf_wqinit
1142 out->q_qinfo = &qif->qf_wqinit;
1144 RWLOCK_EXIT(&ipfs_mutex);
1145 cmn_err(CE_CONT, "IP Filter: attach to [%s,%d]\n",
1146 qif->qf_name, il->ill_ppa);
1149 cmn_err(CE_CONT, "IP Filter: not attached to any interfaces\n");
1155 * look for bad consistancies between the list of interfaces the filter knows
1156 * about and those which are currently configured.
1160 register struct frentry *f;
1161 register ipnat_t *np;
1162 register qif_t *qif, **qp;
1166 WRITE_ENTER(&ipfs_mutex);
1167 for (qp = &qif_head; (qif = *qp); ) {
1168 for (il = ill_g_head; il; il = il->ill_next)
1169 if ((qif->qf_ill == il) &&
1170 !strcmp(qif->qf_name, il->ill_name)) {
1171 mblk_t *m = il->ill_hdr_mp;
1173 qif->qf_hl = il->ill_hdr_length;
1174 if (m && qif->qf_hl != (m->b_wptr - m->b_rptr))
1176 "IP Filter: ILL Header Length Mismatch\n");
1183 cmn_err(CE_CONT, "IP Filter: detaching [%s]\n", qif->qf_name);
1187 * Disable any rules directly associated with this interface
1189 WRITE_ENTER(&ipf_nat);
1190 for (np = nat_list; np; np = np->in_next)
1191 if (np->in_ifp == (void *)qif->qf_ill)
1192 np->in_ifp = (struct ifnet *)-1;
1193 RWLOCK_EXIT(&ipf_nat);
1194 WRITE_ENTER(&ipf_mutex);
1195 for (f = ipfilter[0][fr_active]; f; f = f->fr_next)
1196 if (f->fr_ifa == (void *)qif->qf_ill)
1197 f->fr_ifa = (struct ifnet *)-1;
1198 for (f = ipfilter[1][fr_active]; f; f = f->fr_next)
1199 if (f->fr_ifa == (void *)qif->qf_ill)
1200 f->fr_ifa = (struct ifnet *)-1;
1204 * As well as the ill disappearing when a device is unplumb'd,
1205 * it also appears that the associated queue structures also
1206 * disappear - at least in the case of ppp, which is the most
1207 * volatile here. Thanks to Greg for finding this problem.
1210 * Restore q_qinfo pointers in interface queues
1217 "IP Filter: ipfsync: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1218 in, in->q_qinfo, qif->qf_rqinfo
1221 in->q_qinfo = qif->qf_rqinfo;
1226 "IP Filter: ipfsync: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1227 out, out->q_qinfo, qif->qf_wqinfo
1230 out->q_qinfo = qif->qf_wqinfo;
1233 RWLOCK_EXIT(&ipf_mutex);
1237 RWLOCK_EXIT(&ipfs_mutex);
1241 * Resync. any NAT `connections' using this interface and its IP #.
1243 for (il = ill_g_head; il; il = il->ill_next)
1244 ip_natsync((void *)il);
1250 * unhook the IP filter from all defined interfaces with IP addresses
1258 WRITE_ENTER(&ipfs_mutex);
1260 * Make two passes, first get rid of all the unknown devices, next
1261 * unlink known devices.
1263 for (qp = &qif_head; (qif = *qp); ) {
1264 for (il = ill_g_head; il; il = il->ill_next)
1265 if (qif->qf_ill == il)
1271 cmn_err(CE_CONT, "IP Filter: removing [%s]\n", qif->qf_name);
1276 while ((qif = qif_head)) {
1277 qif_head = qif->qf_next;
1278 for (il = ill_g_head; il; il = il->ill_next)
1279 if (qif->qf_ill == il)
1284 cmn_err(CE_CONT, "IP Filter: detaching [%s,%d]\n",
1285 qif->qf_name, il->ill_ppa);
1289 "IP Filter: soldetach: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1290 in, in->q_qinfo, qif->qf_rqinfo);
1292 in->q_qinfo = qif->qf_rqinfo;
1295 * and the write queue...
1299 "IP Filter: soldetach: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1300 out, out->q_qinfo, qif->qf_wqinfo);
1302 out->q_qinfo = qif->qf_wqinfo;
1306 RWLOCK_EXIT(&ipfs_mutex);
1315 printf("ire: ll_hdr_mp %p rfq %p stq %p src_addr %x max_frag %d\n",
1316 ire->ire_ll_hdr_mp, ire->ire_rfq, ire->ire_stq,
1317 ire->ire_src_addr, ire->ire_max_frag);
1318 printf("ire: mask %x addr %x gateway_addr %x type %d\n",
1319 ire->ire_mask, ire->ire_addr, ire->ire_gateway_addr,
1321 printf("ire: ll_hdr_length %d ll_hdr_saved_mp %p\n",
1322 ire->ire_ll_hdr_length, ire->ire_ll_hdr_saved_mp);
1327 int ipfr_fastroute(qf, ip, mb, mpp, fin, fdp)
1334 ire_t *ir, *dir, *gw;
1344 u_short __iplen, __ipoff;
1347 * If this is a duplicate mblk then we want ip to point at that
1348 * data, not the original, if and only if it is already pointing at
1349 * the current mblk data.
1351 if (ip == (ip_t *)qf->qf_m->b_rptr && qf->qf_m != mb)
1352 ip = (ip_t *)mb->b_rptr;
1355 * If there is another M_PROTO, we don't want it
1358 (*mpp)->b_cont = NULL;
1359 (*mpp)->b_prev = NULL;
1363 ir = (ire_t *)fdp->fd_ifp;
1365 if (fdp->fd_ip.s_addr)
1368 dst = fin->fin_fi.fi_dst;
1372 dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, &gw, NULL,
1373 MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|
1374 MATCH_IRE_RECURSIVE);
1376 dir = ire_lookup(dst.s_addr);
1379 if (!dir->ire_ll_hdr_mp || !dir->ire_ll_hdr_length)
1386 ifp = ire_to_ill(ir);
1389 * In case we're here due to "to <if>" being used with
1390 * "keep state", check that we're going in the correct
1393 if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
1394 (fin->fin_rev != 0) && (fdp == &fr->fr_tif))
1397 fin->fin_ifp == ifp;
1398 if (fin->fin_out == 0) {
1399 fin->fin_fr = ipacct[1][fr_active];
1400 if ((fin->fin_fr != NULL) &&
1401 (fr_scanlist(FR_NOMATCH, ip, fin, mb)&FR_ACCOUNT)){
1402 ATOMIC_INC(frstats[1].fr_acct);
1405 (void) fr_checkstate(ip, fin);
1406 (void) ip_natout(ip, fin);
1409 __iplen = (u_short)ip->ip_len,
1410 __ipoff = (u_short)ip->ip_off;
1412 ip->ip_len = htons(__iplen);
1413 ip->ip_off = htons(__ipoff);
1416 if ((mp = dir->ire_ll_hdr_mp)) {
1417 hlen = dir->ire_ll_hdr_length;
1420 if (hlen && (s - mb->b_datap->db_base) >= hlen) {
1422 mb->b_rptr = (u_char *)s;
1423 bcopy((char *)mp->b_rptr, (char *)s, hlen);
1437 else if (ir->ire_rfq)
1438 q = WR(ir->ire_rfq);
1441 RWLOCK_EXIT(&ipfs_mutex);
1442 RWLOCK_EXIT(&ipf_solaris);
1444 READ_ENTER(&ipf_solaris);
1445 READ_ENTER(&ipfs_mutex);
1458 void copyout_mblk(m, off, len, buf)
1463 u_char *s, *bp = (u_char *)buf;
1464 size_t mlen, olen, clen;
1466 for (; m && len; m = m->b_cont) {
1467 if (MTYPE(m) != M_DATA)
1470 mlen = m->b_wptr - s;
1471 olen = MIN(off, mlen);
1472 if ((olen == mlen) || (olen < off)) {
1480 clen = MIN(mlen, len);
1488 void copyin_mblk(m, off, len, buf)
1493 u_char *s, *bp = (u_char *)buf;
1494 size_t mlen, olen, clen;
1496 for (; m && len; m = m->b_cont) {
1497 if (MTYPE(m) != M_DATA)
1500 mlen = m->b_wptr - s;
1501 olen = MIN(off, mlen);
1502 if ((olen == mlen) || (olen < off)) {
1510 clen = MIN(mlen, len);