2 * Copyright (C) 1993-2002 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
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 $"
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <sys/errno.h>
15 #include <sys/modctl.h>
19 #include <sys/cmn_err.h>
22 #include <sys/dditypes.h>
23 #include <sys/stream.h>
25 #include <sys/autoconf.h>
26 #include <sys/byteorder.h>
27 #include <sys/socket.h>
29 #include <sys/stropts.h>
30 #include <sys/sockio.h>
33 # include <net/if_types.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>
47 #include <sys/sunddi.h>
48 #include "ip_compat.h"
55 char _depends_on[] = "drv/ip";
58 void solipdrvattach __P((void));
59 int solipdrvdetach __P((void));
61 void solattach __P((void));
62 int soldetach __P((void));
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;
70 extern ipnat_t *nat_list;
72 static qif_t *qif_head = NULL;
73 static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
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,
84 static int (*ipf_ip_inp) __P((queue_t *, mblk_t *)) = NULL;
88 extern void ipfr_slowtimer __P((void *));
89 timeout_id_t ipfr_timer_id;
90 static timeout_id_t synctimeoutid = 0;
92 extern void ipfr_slowtimer __P((void));
94 static int synctimeoutid = 0;
97 int ipf_debug_verbose = 0;
99 /* #undef IPFDEBUG 1 */
100 /* #undef IPFDEBUG_VERBOSE 1 */
102 void printire __P((ire_t *));
104 #define isdigit(x) ((x) >= '0' && (x) <= '9')
106 static int fr_precheck __P((mblk_t **, queue_t *, qif_t *, int));
109 static struct cb_ops ipf_cb_ops = {
112 nodev, /* strategy */
117 iplioctl, /* ioctl */
132 static struct dev_ops ipf_ops = {
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 };
151 static size_t hdrsizes[57][2] = {
154 { IFT_1822, 14 }, /* 14 for ire0 ?? */
159 { IFT_ISO88023, 14 },
172 { IFT_ISDNBASIC, 0 },
173 { IFT_ISDNPRIMARY, 0 },
174 { IFT_PTPSERIAL, 0 },
188 { IFT_ARCNETPLUS, 0 },
193 { IFT_ISO88022LLC, 0 },
194 { IFT_LOCALTALK, 0 },
196 { IFT_FRELAYDCE, 0 },
202 { IFT_SONETPATH, 0 },
205 { IFT_PROPVIRTUAL, 0 },
208 #endif /* SOLARIS2 >= 6 */
210 static dev_info_t *ipf_dev_info = NULL;
217 ipfinst = mod_install(&modlink1);
220 cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
230 ipfinst = mod_remove(&modlink1);
233 cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
240 struct modinfo *modinfop;
244 ipfinst = mod_info(&modlink1, modinfop);
247 cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x",
256 static int ipf_probe(dip)
260 return DDI_PROBE_FAILURE;
263 cmn_err(CE_NOTE, "IP Filter: ipf_probe(%x)", dip);
265 return DDI_PROBE_SUCCESS;
269 static int ipf_identify(dip)
274 cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip);
276 if (strcmp(ddi_get_name(dip), "ipf") == 0)
277 return (DDI_IDENTIFIED);
278 return (DDI_NOT_IDENTIFIED);
282 static void ipf_ire_walk(ire, arg)
288 if ((ire->ire_type == IRE_CACHE) &&
290 (ire->ire_ipif != NULL) &&
291 (ire->ire_ipif->ipif_ill == qif->qf_ill)
293 (ire_to_ill(ire) == qif->qf_ill)
297 mblk_t *m = ire->ire_fp_mp;
299 mblk_t *m = ire->ire_ll_hdr_mp;
302 qif->qf_hl = m->b_wptr - m->b_rptr;
307 static int ipf_attach(dip, cmd)
309 ddi_attach_cmd_t cmd;
315 cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd);
322 instance = ddi_get_instance(dip);
325 cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance);
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);
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);
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);
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);
352 if (iplattach() == -1)
355 * Lock people out while we set things up.
357 WRITE_ENTER(&ipf_solaris);
360 RWLOCK_EXIT(&ipf_solaris);
361 cmn_err(CE_CONT, "%s, attaching complete.\n",
366 if (ipfr_timer_id == 0)
367 ipfr_timer_id = timeout(ipfr_slowtimer, NULL,
368 drv_usectohz(500000));
374 if (ipfr_timer_id == 0)
375 ipfr_timer_id = timeout(ipfr_slowtimer, NULL,
376 drv_usectohz(500000));
384 cmn_err(CE_NOTE, "IP Filter: failed to attach\n");
386 * Use our own detach routine to toss
387 * away any stuff we allocated above.
389 (void) ipf_detach(dip, DDI_DETACH);
394 static int ipf_detach(dip, cmd)
396 ddi_detach_cmd_t cmd;
402 cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
409 * Make sure we're the only one's modifying things. With
410 * this lock others should just fall out of the loop.
412 mutex_enter(&ipf_rw);
413 if (ipfr_timer_id != 0) {
414 untimeout(ipfr_timer_id);
418 WRITE_ENTER(&ipf_solaris);
419 mutex_enter(&ipf_rw);
420 if (fr_running <= 0) {
426 /* NOTE: ipf_solaris rwlock is released in ipldetach */
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.
434 ddi_prop_remove_all(dip);
435 i = ddi_get_instance(dip);
436 ddi_remove_minor_node(dip, NULL);
438 i = solipdrvdetach();
440 cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
444 cmn_err(CE_CONT, "%s detached\n", ipfilter_version);
445 return (DDI_SUCCESS);
449 case DDI_PM_SUSPEND :
450 if (ipfr_timer_id != 0) {
451 untimeout(ipfr_timer_id);
455 untimeout(synctimeoutid);
461 return (DDI_FAILURE);
467 static int ipf_getinfo(dip, infocmd, arg, result)
469 ddi_info_cmd_t infocmd;
479 cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)",
483 case DDI_INFO_DEVT2DEVINFO:
484 *result = ipf_dev_info;
487 case DDI_INFO_DEVT2INSTANCE:
488 *result = (void *)getminor((dev_t) arg);
498 * find the filter structure setup for this queue
500 static qif_t *qif_from_queue(q)
505 for (qif = qif_head; qif; qif = qif->qf_next)
506 if ((qif->qf_iptr == q->q_ptr) || (qif->qf_optr == q->q_ptr))
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.
518 void fr_donotip(out, qif, q, m, mt, ip, off)
526 u_char *s, outb[256], *t;
533 s = ip ? (u_char *)ip : outb;
534 if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA))
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));
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;
556 cmn_err(CE_CONT, "%s", outb);
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;
570 cmn_err(CE_CONT, "%s", outb);
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!
580 static int fr_precheck(mp, q, qif, out)
586 register mblk_t *m, *mt = *mp;
588 size_t hlen, len, off, off2, mlen, iphlen, plen, woff;
589 int err, synced = 0, sap, p, realigned = 0, multi = 0;
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
606 off = (out) ? qif->qf_hl : 0;
609 * If the message protocol block indicates that there isn't a data
610 * block following it, just return back.
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;
619 * This is a complete kludge to try and work around
620 * some bizarre packets which drop through into
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);
629 } else if (dl->dl_primitive != DL_UNITDATA_REQ) {
631 if ((ip->ip_v == IPVERSION) &&
632 (ip->ip_hl == (sizeof(*ip) >> 2)) &&
633 (ntohs(ip->ip_len) == mt->b_wptr - mt->b_rptr)) {
637 frstats[out].fr_notdata++;
644 * Find the first data block, count the data blocks in this chain and
645 * the total amount of data.
648 for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont)
649 off = 0; /* Any non-M_DATA cancels the offset */
652 frstats[out].fr_nodata++;
653 return 0; /* No data blocks */
656 ip = (ip_t *)(m->b_rptr + off); /* MMM */
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
662 while ((u_char *)ip >= m->b_wptr) {
663 len = (u_char *)ip - m->b_wptr;
666 return 0; /* not enough data for IP */
667 ip = (ip_t *)(m->b_rptr + len);
669 off = (u_char *)ip - m->b_rptr;
671 m->b_rptr = (u_char *)ip;
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++;
682 sap = qif->qf_ill->ill_sap;
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];
698 else if (sap == IP6_DL_SAP) {
701 hlen = sizeof(ip6_t);
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];
708 return -1; /* Jumbo gram */
709 plen += sizeof(*ip6);
719 * Ok, the IP header isn't on a 32bit aligned address so junk it.
721 if (((u_long)ip & 0x3) || (plen > mlen) || (len < hlen) ||
728 * Junk using pullupmsg - it's next to useless.
740 frstats[out].fr_notip++;
741 return (fr_flags & FF_BLOCKNONIP) ? -1 : 0;
747 off2 = (size_t)((u_long)ip & 0x3);
751 m2 = allocb(len + off2, BPRI_HI);
753 frstats[out].fr_pull[1]++;
758 if (m->b_rptr != (u_char *)ip)
760 m2->b_wptr = m2->b_rptr + len;
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);
771 if (mt != m && mt->b_cont == m && !off) {
773 * check if the buffer we're changing is chained in-
774 * between other buffers and unlink/relink as required.
776 (void) unlinkb(mt); /* should return 'm' */
793 frstats[out].fr_pull[0]++;
799 if (((sap == 0) && (ip->ip_v != IP_VERSION))
801 || ((sap == IP6_DL_SAP) && ((ip6->ip6_vfc >> 4) != 6))
810 if (sap == IP6_DL_SAP) {
811 ip6->ip6_plen = plen - sizeof(*ip6);
814 __ipoff = (u_short)ip->ip_off;
817 ip->ip_off = ntohs(__ipoff);
823 iphlen = ip->ip_hl << 2;
825 else if (sap == IP6_DL_SAP)
826 iphlen = sizeof(ip6_t);
831 (sap == IP6_DL_SAP) && (mlen < plen)) ||
834 ((iphlen < hlen) || (iphlen > plen) || (mlen < plen)))) {
836 * Bad IP packet or not enough data/data length mismatches
840 if (sap == IP6_DL_SAP) {
841 ip6->ip6_plen = htons(plen - sizeof(*ip6));
844 __ipoff = (u_short)ip->ip_off;
846 ip->ip_len = htons(plen);
847 ip->ip_off = htons(__ipoff);
853 frstats[out].fr_bad++;
858 * Make hlen the total size of the IP header plus TCP/UDP/ICMP header
859 * (if it is one of these three).
864 else if (sap == IP6_DL_SAP)
867 if ((sap == IP6_DL_SAP) || ((ip->ip_off & IP_OFFMASK) == 0))
869 if ((ip->ip_off & IP_OFFMASK) == 0)
874 hlen += sizeof(tcphdr_t);
877 hlen += sizeof(udphdr_t);
880 /* 76 bytes is enough for a complete ICMP error. */
881 hlen += 76 + sizeof(icmphdr_t);
890 } else if (m->b_wptr - m->b_rptr > plen) {
891 woff = m->b_wptr - m->b_rptr - plen;
896 * If we don't have enough data in the mblk or we haven't yet copied
897 * enough (above), then copy some more.
900 if (!pullupmsg(m, (int)hlen)) {
901 cmn_err(CE_NOTE, "pullupmsg failed");
902 frstats[out].fr_pull[1]++;
905 frstats[out].fr_pull[0]++;
906 ip = (ip_t *)ALIGN32(m->b_rptr);
912 err = fr_check(ip, iphlen, qif->qf_ill, out, qif, mp);
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!
928 if (sap == IP6_DL_SAP) {
929 ip6->ip6_plen = htons(plen - sizeof(*ip6));
932 __ipoff = (u_short)ip->ip_off;
934 * plen is useless because of NAT.
936 ip->ip_len = htons(ip->ip_len);
937 ip->ip_off = htons(__ipoff);
944 "!IP Filter: *mp %p mt %p %s", *mp, mt,
945 "mblk changed, cannot revert ip_len, ip_off");
952 * Only called for M_IOCACK messages
954 void fr_qif_update(qif, mp)
962 iocp = (struct iocblk *)mp->b_rptr;
963 if (mp->b_cont && (iocp->ioc_cmd == DL_IOC_HDR_INFO)) {
965 if (MTYPE(mp) == M_PROTO && mp->b_cont) {
967 if (MTYPE(mp) == M_DATA) {
968 qif->qf_hl = mp->b_wptr - mp->b_rptr;
979 int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
982 #ifdef IPFDEBUG_VERBOSE
983 if (ipf_debug_verbose)
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,
991 * IPFilter is still in the packet path but not enabled. Drop whatever
992 * it is that has come through.
994 if (fr_running <= 0) {
1003 * If a mblk has more than one reference, make a copy, filter that and
1004 * free a reference to the original.
1006 if (mb->b_datap->db_ref > 1) {
1011 frstats[0].fr_drop++;
1019 frstats[0].fr_copy++;
1022 READ_ENTER(&ipf_solaris);
1024 if (fr_running <= 0) {
1027 RWLOCK_EXIT(&ipf_solaris);
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);
1043 RWLOCK_EXIT(&ipf_solaris);
1044 /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
1045 return (*pnext)(q, mb);
1047 RWLOCK_EXIT(&ipfs_mutex);
1054 "!IP Filter: dropped: fr_qin(%x,%x): type %x qif %x",
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,
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,
1063 q->q_qinfo->qi_infop
1068 frstats[0].fr_drop++;
1071 RWLOCK_EXIT(&ipf_solaris);
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);
1083 RWLOCK_EXIT(&ipfs_mutex);
1085 if ((err == 0) && (mb != NULL)) {
1087 RWLOCK_EXIT(&ipf_solaris);
1088 return (*pnext)(q, mb);
1092 "!IP Filter: inp NULL: qif %x %s q %x info %x",
1093 qif, qf.qf_name, q, q->q_qinfo);
1102 frstats[0].fr_notip++;
1103 if (!(fr_flags & FF_BLOCKNONIP) && (pnext != NULL)) {
1104 RWLOCK_EXIT(&ipf_solaris);
1105 return (*pnext)(q, mb);
1114 RWLOCK_EXIT(&ipf_solaris);
1123 int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
1126 #ifdef IPFDEBUG_VERBOSE
1127 if (ipf_debug_verbose)
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,
1134 if (fr_running <= 0) {
1143 if ((!dohwcksum || mb->b_ick_flag != ICK_VALID) &&
1144 (mb->b_datap->db_ref > 1))
1146 if (mb->b_datap->db_ref > 1)
1153 frstats[1].fr_drop++;
1161 frstats[1].fr_copy++;
1164 READ_ENTER(&ipf_solaris);
1166 if (fr_running <= 0) {
1169 RWLOCK_EXIT(&ipf_solaris);
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++;
1185 /* fr_donotip(1, NULL, q, mb, mb, NULL, 0); */
1186 RWLOCK_EXIT(&ipf_solaris);
1187 return (*pnext)(q, mb);
1189 RWLOCK_EXIT(&ipfs_mutex);
1196 "!IP Filter: dropped: fr_qout(%x,%x): type %x: qif %x",
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,
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,
1205 q->q_qinfo->qi_infop
1212 "!IP Filter: nfsrv: info %x next %x ptr %x\n",
1213 q->q_nfsrv->q_qinfo, q->q_nfsrv->q_next,
1217 "!IP Filter: nbsrv: info %x next %x ptr %x\n",
1218 q->q_nbsrv->q_qinfo, q->q_nbsrv->q_next,
1220 frstats[1].fr_drop++;
1223 RWLOCK_EXIT(&ipf_solaris);
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);
1235 RWLOCK_EXIT(&ipfs_mutex);
1237 if ((err == 0) && (mb != NULL)) {
1239 RWLOCK_EXIT(&ipf_solaris);
1240 return (*pnext)(q, mb);
1244 "!IP Filter: outp NULL: qif %x %s q %x info %x",
1245 qif, qf.qf_name, q, q->q_qinfo);
1254 frstats[1].fr_notip++;
1255 if (!(fr_flags & FF_BLOCKNONIP) && (pnext != NULL)) {
1256 RWLOCK_EXIT(&ipf_solaris);
1257 return (*pnext)(q, mb);
1265 RWLOCK_EXIT(&ipf_solaris);
1270 void ipf_synctimeout(arg)
1275 READ_ENTER(&ipf_solaris);
1277 WRITE_ENTER(&ipfs_mutex);
1279 RWLOCK_EXIT(&ipfs_mutex);
1280 RWLOCK_EXIT(&ipf_solaris);
1284 static int ipf_ip_qin(q, mb)
1291 if (fr_running <= 0) {
1297 if (MTYPE(mb) != M_IOCTL)
1298 return (*ipf_ip_inp)(q, mb);
1300 READ_ENTER(&ipf_solaris);
1301 if (fr_running <= 0) {
1302 RWLOCK_EXIT(&ipf_solaris);
1307 ioc = (struct iocblk *)mb->b_rptr;
1309 switch (ioc->ioc_cmd)
1311 case DL_IOC_HDR_INFO:
1312 fr_qif_update(qif_from_queue(q), mb);
1321 "IP Filter: ipf_ip_qin() M_IOCTL type=0x%x",
1324 WRITE_ENTER(&ipfs_mutex);
1325 if (synctimeoutid == 0) {
1326 synctimeoutid = timeout(ipf_synctimeout,
1328 drv_usectohz(1000000) /*1 sec*/
1331 RWLOCK_EXIT(&ipfs_mutex);
1336 RWLOCK_EXIT(&ipf_solaris);
1337 return (*ipf_ip_inp)(q, mb);
1340 static int ipdrvattcnt = 0;
1341 extern struct streamtab ipinfo;
1343 void solipdrvattach()
1347 cmn_err(CE_NOTE, "IP Filter: solipdrvattach() %d ipinfo=0x%lx",
1348 ipdrvattcnt, &ipinfo);
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;
1359 int solipdrvdetach()
1363 cmn_err(CE_NOTE, "IP Filter: solipdrvdetach() %d ipinfo=0x%lx",
1364 ipdrvattcnt, &ipinfo);
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;
1373 if (synctimeoutid) {
1374 untimeout(synctimeoutid);
1378 RWLOCK_EXIT(&ipfs_mutex);
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
1397 for (il = ill_g_head; il; il = il->ill_next) {
1399 if (!in || !il->ill_wq)
1402 out = il->ill_wq->q_next;
1404 WRITE_ENTER(&ipfs_mutex);
1406 * Look for entry already setup for this device
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)
1413 RWLOCK_EXIT(&ipfs_mutex);
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);
1423 KMALLOC(qif, qif_t *);
1426 "IP Filter: malloc(%d) for qif_t failed",
1428 RWLOCK_EXIT(&ipfs_mutex);
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;
1442 "IP Filter: rq:%s put %x qi %x",
1443 il->ill_name, in->q_qinfo->qi_putp,
1446 RWLOCK_EXIT(&ipfs_mutex);
1451 qif->qf_rqinfo = in->q_qinfo;
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;
1463 "IP Filter: wq:%s put %x qi %x",
1464 il->ill_name, out->q_qinfo->qi_putp,
1467 RWLOCK_EXIT(&ipfs_mutex);
1472 qif->qf_wqinfo = out->q_qinfo;
1477 qif->qf_iptr = in->q_ptr;
1478 qif->qf_optr = out->q_ptr;
1480 qif->qf_hl = il->ill_hdr_length;
1487 qif->qf_sap = il->ill_sap;
1490 * Can't seem to lookup a route for the IP address on the
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;
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];
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");
1511 /* DREADFUL VLAN HACK - JUST HERE TO CHECK IT WORKS */
1513 if (qif->qf_hl == 0 && il->ill_type != IFT_OTHER)
1515 "Unknown layer 2 header size for %s type %d",
1516 il->ill_name, il->ill_type);
1520 * XXX Awful hack for PPP; fix when PPP/snoop fixed.
1522 if (il->ill_type == IFT_ETHER && !il->ill_bcast_addr_length)
1525 strncpy(qif->qf_name, il->ill_name, sizeof(qif->qf_name));
1526 qif->qf_name[sizeof(qif->qf_name) - 1] = '\0';
1528 qif->qf_next = qif_head;
1532 * Activate any rules directly associated with this interface
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;
1539 (len == (size_t)il->ill_name_length) &&
1540 !strncmp(il->ill_name, f->fr_ifname, len))
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;
1548 (len == (size_t)il->ill_name_length) &&
1549 !strncmp(il->ill_name, f->fr_ifname, len))
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;
1558 (len == (size_t)il->ill_name_length) &&
1559 !strncmp(il->ill_name, f->fr_ifname, len))
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;
1567 (len == (size_t)il->ill_name_length) &&
1568 !strncmp(il->ill_name, f->fr_ifname, len))
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;
1579 (len == (size_t)il->ill_name_length) &&
1580 !strncmp(il->ill_name, np->in_ifname, len))
1584 RWLOCK_EXIT(&ipf_nat);
1586 bcopy((caddr_t)qif->qf_rqinfo, (caddr_t)&qif->qf_rqinit,
1587 sizeof(struct qinit));
1588 qif->qf_rqinit.qi_putp = fr_qin;
1592 "IP Filter: solattach: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1593 in, in->q_qinfo, &qif->qf_rqinit);
1595 in->q_qinfo = &qif->qf_rqinit;
1597 bcopy((caddr_t)qif->qf_wqinfo, (caddr_t)&qif->qf_wqinit,
1598 sizeof(struct qinit));
1599 qif->qf_wqinit.qi_putp = fr_qout;
1603 "IP Filter: solattach: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1604 out, out->q_qinfo, &qif->qf_wqinit);
1606 out->q_qinfo = &qif->qf_wqinit;
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,
1613 il->ill_isv6 ? "IPv6" : "IPv4"
1620 cmn_err(CE_CONT, "IP Filter: not attached to any interfaces\n");
1626 * look for bad consistancies between the list of interfaces the filter knows
1627 * about and those which are currently configured.
1631 register struct frentry *f;
1632 register ipnat_t *np;
1633 register qif_t *qif, **qp;
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)) {
1643 mblk_t *m = il->ill_hdr_mp;
1645 qif->qf_hl = il->ill_hdr_length;
1646 if (m && qif->qf_hl != (m->b_wptr - m->b_rptr))
1648 "IP Filter: ILL Header Length Mismatch\n");
1656 cmn_err(CE_CONT, "IP Filter: detaching [%s] - %s\n",
1659 (qif->qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4"
1667 * Disable any rules directly associated with this interface
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;
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;
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.
1698 * Restore q_qinfo pointers in interface queues
1706 "IP Filter: ipfsync: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1707 in, in->q_qinfo, qif->qf_rqinfo);
1709 in->q_qinfo = qif->qf_rqinfo;
1715 "IP Filter: ipfsync: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1716 out, out->q_qinfo, qif->qf_wqinfo);
1718 out->q_qinfo = qif->qf_wqinfo;
1721 RWLOCK_EXIT(&ipf_mutex);
1725 RWLOCK_EXIT(&ipfs_mutex);
1730 * Resync. any NAT `connections' using this interface and its IP #.
1732 for (il = ill_g_head; il; il = il->ill_next) {
1733 ip_natsync((void *)il);
1734 ip_statesync((void *)il);
1741 * unhook the IP filter from all defined interfaces with IP addresses
1749 WRITE_ENTER(&ipfs_mutex);
1751 * Make two passes, first get rid of all the unknown devices, next
1752 * unlink known devices.
1754 for (qp = &qif_head; (qif = *qp); ) {
1755 for (il = ill_g_head; il; il = il->ill_next)
1756 if (qif->qf_ill == il)
1762 cmn_err(CE_CONT, "IP Filter: removing [%s]\n", qif->qf_name);
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)
1775 cmn_err(CE_CONT, "IP Filter: detaching [%s,%d] - %s\n",
1776 qif->qf_name, il->ill_ppa,
1778 (qif->qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4"
1787 "IP Filter: soldetach: in queue(%lx)->q_qinfo FROM %lx TO %lx",
1788 in, in->q_qinfo, qif->qf_rqinfo);
1790 in->q_qinfo = qif->qf_rqinfo;
1793 * and the write queue...
1798 "IP Filter: soldetach: out queue(%lx)->q_qinfo FROM %lx TO %lx",
1799 out, out->q_qinfo, qif->qf_wqinfo);
1801 out->q_qinfo = qif->qf_wqinfo;
1805 RWLOCK_EXIT(&ipfs_mutex);
1816 printf("ire: ll_hdr_mp %p rfq %p stq %p src_addr %x max_frag %d\n",
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,
1827 printf("ire: ll_hdr_length %d ll_hdr_saved_mp %p\n",
1828 ire->ire_ll_hdr_length,
1832 ire->ire_ll_hdr_saved_mp
1839 int ipfr_fastroute(ip, mb, mpp, fin, fdp)
1846 ip6_t *ip6 = (ip6_t *)ip;
1848 ire_t *ir, *dir, *gw;
1861 u_short __iplen, __ipoff;
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.
1870 if ((ip == (ip_t *)qf->qf_m->b_rptr) && (qf->qf_m != mb))
1871 ip = (ip_t *)mb->b_rptr;
1874 * If there is another M_PROTO, we don't want it
1879 mp = (*mpp)->b_cont;
1880 (*mpp)->b_cont = NULL;
1881 (*mpp)->b_prev = NULL;
1890 ipif = ifp->ill_ipif;
1894 ir = ire_ctable_lookup(ipif->ipif_local_addr, 0, IRE_LOCAL,
1895 NULL, NULL, MATCH_IRE_TYPE);
1897 ir = ire_lookup_myaddr(ipif->ipif_local_addr);
1902 fd.fd_ifp = (struct ifnet *)ir;
1903 fd.fd_ip = ip->ip_dst;
1907 ir = (ire_t *)fdp->fd_ifp;
1909 if (fdp->fd_ip.s_addr)
1912 dst.s_addr = fin->fin_fi.fi_daddr;
1916 if (fin->fin_v == 4) {
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);
1923 else if (fin->fin_v == 6) {
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);
1931 dir = ire_lookup(dst.s_addr);
1935 if (!dir->ire_ll_hdr_mp || !dir->ire_ll_hdr_length)
1939 if (!dir->ire_fp_mp || !dir->ire_dlureq_mp)
1947 ifp = ire_to_ill(ir);
1953 * In case we're here due to "to <if>" being used with
1954 * "keep state", check that we're going in the correct
1957 if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
1958 (fin->fin_rev != 0) && (fdp == &fr->fr_tif))
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);
1969 if (!fr || !(fr->fr_flags & FR_RETMASK))
1970 (void) fr_checkstate(ip, fin);
1971 (void) ip_natout(ip, fin);
1974 if (fin->fin_v == 4) {
1975 __iplen = (u_short)ip->ip_len,
1976 __ipoff = (u_short)ip->ip_off;
1978 ip->ip_len = htons(__iplen);
1979 ip->ip_off = htons(__ipoff);
1984 mp = dir->ire_ll_hdr_mp;
1985 hlen = dir->ire_ll_hdr_length;
1987 mp = dir->ire_fp_mp;
1988 hlen = mp ? mp->b_wptr - mp->b_rptr : 0;
1989 mp = dir->ire_dlureq_mp;
1996 ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC) ||
1998 (hlen && (s - mb->b_datap->db_base) >= hlen)) {
2000 mb->b_rptr = (u_char *)s;
2001 bcopy((char *)mp->b_rptr, (char *)s, hlen);
2016 else if (ir->ire_rfq)
2017 q = WR(ir->ire_rfq);
2021 RWLOCK_EXIT(&ipfs_mutex);
2022 RWLOCK_EXIT(&ipf_solaris);
2024 if ((p == IPPROTO_TCP) && dohwcksum &&
2025 (ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {
2029 tcp = (tcphdr_t *)((char *)ip + fin->fin_hlen);
2030 t = ip->ip_src.s_addr;
2031 t += ip->ip_dst.s_addr;
2033 t = (t & 0xffff) + (t >> 16);
2034 tcp->th_sum = t & 0xffff;
2038 READ_ENTER(&ipf_solaris);
2039 READ_ENTER(&ipfs_mutex);
2054 void copyout_mblk(m, off, len, buf)
2059 u_char *s, *bp = (u_char *)buf;
2060 size_t mlen, olen, clen;
2062 for (; m && len; m = m->b_cont) {
2063 if (MTYPE(m) != M_DATA)
2066 mlen = m->b_wptr - s;
2067 olen = MIN(off, mlen);
2068 if ((olen == mlen) || (olen < off)) {
2076 clen = MIN(mlen, len);
2084 void copyin_mblk(m, off, len, buf)
2089 u_char *s, *bp = (u_char *)buf;
2090 size_t mlen, olen, clen;
2092 for (; m && len; m = m->b_cont) {
2093 if (MTYPE(m) != M_DATA)
2096 mlen = m->b_wptr - s;
2097 olen = MIN(off, mlen);
2098 if ((olen == mlen) || (olen < off)) {
2106 clen = MIN(mlen, len);
2114 int fr_verifysrc(ipa, ifp)
2118 ire_t *ir, *dir, *gw;
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);
2125 dir = ire_lookup(ipa.s_addr);
2130 return (ire_to_ill(dir) == ifp);