summaryrefslogtreecommitdiffstats
path: root/contrib/ipfilter/solaris.c
diff options
context:
space:
mode:
authordarrenr <darrenr@FreeBSD.org>1997-02-09 22:50:16 +0000
committerdarrenr <darrenr@FreeBSD.org>1997-02-09 22:50:16 +0000
commitcb8d46a179f2d30ac1cd0a01eb156e1a4c08d717 (patch)
tree93c7db298b1fd70f9e27663b3fd527da063d0008 /contrib/ipfilter/solaris.c
downloadFreeBSD-src-cb8d46a179f2d30ac1cd0a01eb156e1a4c08d717.zip
FreeBSD-src-cb8d46a179f2d30ac1cd0a01eb156e1a4c08d717.tar.gz
Import IP Filter v3.1.7 into FreeBSD tree
Diffstat (limited to 'contrib/ipfilter/solaris.c')
-rw-r--r--contrib/ipfilter/solaris.c1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/contrib/ipfilter/solaris.c b/contrib/ipfilter/solaris.c
new file mode 100644
index 0000000..73db28f
--- /dev/null
+++ b/contrib/ipfilter/solaris.c
@@ -0,0 +1,1018 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+/* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/
+#pragma ident "$Id: solaris.c,v 2.0.1.4 1997/02/08 06:38:30 darrenr Exp $";
+
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/modctl.h>
+#include <sys/open.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/cred.h>
+#include <sys/dditypes.h>
+#include <sys/stream.h>
+#include <sys/poll.h>
+#include <sys/autoconf.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/af.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include "ipl.h"
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <inet/ip_ire.h>
+
+char _depends_on[] = "drv/ip";
+
+extern int iplopen(), iplclose(), iplread(), iplioctl();
+extern int iplattach(), ipldetach();
+extern void copyout_mblk(), copyin_mblk();
+
+int solattach(), soldetach();
+
+extern struct filterstats frstats[];
+extern kmutex_t ipl_mutex, ipf_mutex, ipfs_mutex;
+extern int fr_flags;
+
+static qif_t *qif_head = NULL;
+
+static int ipl_getinfo(), ipl_probe(), ipl_identify(), ipl_attach();
+static int ipl_detach();
+
+static struct cb_ops ipl_cb_ops = {
+ iplopen,
+ iplclose,
+ nodev, /* strategy */ nodev, /* print */
+ nodev, /* dump */
+ iplread,
+ nodev, /* write */
+ iplioctl, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* poll */
+ ddi_prop_op,
+ NULL,
+ D_MTSAFE
+};
+
+static struct dev_ops ipl_ops = {
+ DEVO_REV,
+ 0,
+ ipl_getinfo,
+ ipl_identify,
+ ipl_probe,
+ ipl_attach,
+ ipl_detach,
+ nodev, /* reset */
+ &ipl_cb_ops,
+ (struct bus_ops *)0
+};
+
+extern struct mod_ops mod_driverops;
+static struct modldrv iplmod = {
+ &mod_driverops, IPL_VERSION, &ipl_ops };
+static struct modlinkage modlink1 = { MODREV_1, &iplmod, 0 };
+
+
+static dev_info_t *ipf_dev_info = NULL;
+
+
+int _init()
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipf_init()");
+#endif
+ return mod_install(&modlink1);
+}
+
+
+int _fini(void)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipf_fini()");
+#endif
+ return mod_remove(&modlink1);
+}
+
+
+int _info(struct modinfo *modinfop)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipf_info(%x)", modinfop);
+#endif
+ return mod_info(&modlink1, modinfop);
+}
+
+
+static int ipl_probe(dev_info_t *dip)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_probe(%x)", dip);
+#endif
+ return DDI_PROBE_SUCCESS;
+}
+
+
+static int ipl_identify(dev_info_t *dip)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_identify(%x)", dip);
+#endif
+ if (strcmp(ddi_get_name(dip), "ipf") == 0)
+ return (DDI_IDENTIFIED);
+ return (DDI_NOT_IDENTIFIED);
+}
+
+
+static int ipl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int instance;
+
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_attach(%x,%x)", dip, cmd);
+#endif
+ switch (cmd) {
+ case DDI_ATTACH:
+ instance = ddi_get_instance(dip);
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: attach ipf instace %d", instance);
+#endif
+ if (ddi_create_minor_node(dip, "ipf", S_IFCHR, instance,
+ DDI_PSEUDO, 0) == DDI_FAILURE) {
+ ddi_remove_minor_node(dip, NULL);
+ goto attach_failed;
+ }
+ ipf_dev_info = dip;
+ sync();
+ /*
+ * Initialize mutex's
+ */
+ iplattach();
+ solattach();
+ cmn_err(CE_CONT, "IP Filter: attaching complete.\n");
+ return (DDI_SUCCESS);
+ default:
+ return (DDI_FAILURE);
+ }
+
+attach_failed:
+ /*
+ * Use our own detach routine to toss
+ * away any stuff we allocated above.
+ */
+ (void) ipl_detach(dip, DDI_DETACH);
+ return (DDI_FAILURE);
+}
+
+
+static int ipl_detach(dip, cmd)
+dev_info_t *dip;
+ddi_detach_cmd_t cmd;
+{
+ int instance;
+
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_detach(%x,%x)", dip, cmd);
+#endif
+ switch (cmd) {
+ case DDI_DETACH:
+ /*
+ * Undo what we did in ipl_attach, freeing resources
+ * and removing things we installed. The system
+ * framework guarantees we are not active with this devinfo
+ * node in any other entry points at this time.
+ */
+ ddi_prop_remove_all(dip);
+ instance = ddi_get_instance(dip);
+ ddi_remove_minor_node(dip, NULL);
+ sync();
+ if (!soldetach()) {
+ cmn_err(CE_CONT, "IP Filter: detached\n");
+ return (DDI_SUCCESS);
+ }
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+
+static int ipl_getinfo(dip, infocmd, arg, result)
+dev_info_t *dip;
+ddi_info_cmd_t infocmd;
+void *arg, **result;
+{
+ int error = DDI_FAILURE;
+
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_getinfo(%x,%x)", dip, infocmd);
+#endif
+ switch (infocmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = ipf_dev_info;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)getminor((dev_t) arg);
+ error = DDI_SUCCESS;
+ break;
+ default:
+ break;
+ }
+ return (error);
+}
+
+/*
+ * find the filter structure setup for this queue
+ */
+qif_t *qif_from_queue(q)
+queue_t *q;
+{
+ qif_t *qif;
+
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if ((qif->qf_iptr == q->q_ptr) || (qif->qf_optr == q->q_ptr))
+ break;
+ return qif;
+}
+
+
+/*
+ * OK, this is pretty scrappy code, but then it's essentially just here for
+ * debug purposes and that's it. Packets should not normally come through
+ * here, and if they do, well, we would like to see as much information as
+ * possible about them and what they claim to hold.
+ */
+void fr_donotip(out, qif, q, m, mt, ip, off)
+int out;
+qif_t *qif;
+queue_t *q;
+mblk_t *m, *mt;
+ip_t *ip;
+int off;
+{
+ u_char *s, outb[256], *t;
+ int i;
+
+ outb[0] = '\0';
+ outb[1] = '\0';
+ outb[2] = '\0';
+ outb[3] = '\0';
+ s = ip ? (u_char *)ip : outb;
+ if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA))
+ m = m->b_cont;
+
+ printf("!IP %s:%d %x %x %x %d %x %x %x %d %d %x\n%02x%02x%02x%02x\n",
+ qif ? qif->qf_name : "?", out, q, q ? q->q_ptr : NULL,
+ q ? q->q_qinfo : NULL, mt->b_wptr - mt->b_rptr, m, mt,
+ m->b_rptr, m->b_wptr - m->b_rptr, off, ip,
+ *s, *(s+1), *(s+2), *(s+3));
+ if (m != mt) {
+ i = 0;
+ t = outb;
+ s = mt->b_rptr;
+ sprintf(t, "%d:", MTYPE(mt));
+ t += strlen(t);
+ for (; (i < 100) && (s < mt->b_wptr); i++) {
+ sprintf(t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
+ t += ((i & 3) == 3) ? 3 : 2;
+ }
+ *t++ = '\n';
+ *t = '\0';
+ printf("%s", outb);
+ }
+ i = 0;
+ t = outb;
+ s = m->b_rptr;
+ sprintf(t, "%d:", MTYPE(m));
+ t += strlen(t);
+ for (; (i < 100) && (s < m->b_wptr); i++) {
+ sprintf(t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
+ t += ((i & 3) == 3) ? 3 : 2;
+ }
+ *t++ = '\n';
+ *t = '\0';
+ printf("%s", outb);
+}
+
+
+/*
+ * find the first data mblk, if present, in the chain we're processing. Also
+ * make a few sanity checks to try prevent the filter from causing a panic -
+ * none of the nice IP sanity checks (including checksumming) should have been
+ * done yet - dangerous!
+ */
+int fr_precheck(mp, q, qif, out)
+mblk_t **mp;
+queue_t *q;
+qif_t *qif;
+int out;
+{
+ u_long lbuf[48];
+ mblk_t *m, *mp1, *mt = *mp;
+ register ip_t *ip;
+ int iphlen, hlen, len, err, mlen, off, synced = 0;
+#ifndef sparc
+ u_short __iplen, __ipoff;
+#endif
+tryagain:
+ /*
+ * If there is only M_DATA for a packet going out, then any header
+ * information (which would otherwise appear in an M_PROTO mblk before
+ * the M_DATA) is prepended before the IP header. We need to set the
+ * offset to account for this. - see MMM
+ */
+ off = (out) ? qif->qf_hl : 0;
+
+ /*
+ * Find the first data block, count the data blocks in this chain and
+ * the total amount of data.
+ */
+ for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont)
+ off = 0; /* Any non-M_DATA cancels the offset */
+
+ if (!m)
+ return 0; /* No data blocks */
+
+ ip = (ip_t *)(m->b_rptr + off); /* MMM */
+
+ /*
+ * We might have a 1st data block which is really M_PROTO, i.e. it is
+ * only big enough for the link layer header
+ */
+ while ((u_char *)ip >= m->b_wptr) {
+ len = (u_char *)ip - m->b_wptr;
+ if (!(m = m->b_cont))
+ return 0; /* not enough data for IP */
+ ip = (ip_t *)(m->b_rptr + len);
+ }
+ if ((off = (u_char *)ip - m->b_rptr))
+ m->b_rptr = (u_char *)ip;
+ mlen = msgdsize(m);
+
+ /*
+ * Ok, the IP header isn't on a 32bit aligned address. To get around
+ * this, we copy the data to an aligned buffer and work with that.
+ */
+ if (!OK_32PTR(ip)) {
+ len = MIN(mlen, sizeof(ip_t));
+ copyout_mblk(m, 0, lbuf, len);
+ frstats[out].fr_pull[0]++;
+ ip = (ip_t *)lbuf;
+ } else
+ len = m->b_wptr - (u_char *)ip;
+
+ if (ip->ip_v != IPVERSION) {
+ m->b_rptr -= off;
+ if (!synced) {
+ synced = 1;
+ ipfsync();
+ goto tryagain;
+ }
+ fr_donotip(out, qif, q, m, mt, ip, off);
+ frstats[out].fr_notip++;
+ return (fr_flags & FF_BLOCKNONIP) ? -1 : 0;
+ }
+
+ hlen = iphlen = ip->ip_hl << 2;
+
+ /*
+ * Make hlen the total size of the IP header plus TCP/UDP/ICMP header
+ * (if it is one of these three).
+ */
+ if (!(ip->ip_off & 0x1fff))
+ switch (ip->ip_p)
+ {
+ case IPPROTO_TCP :
+ hlen += sizeof(tcphdr_t);
+ break;
+ case IPPROTO_UDP :
+ hlen += sizeof(udphdr_t);
+ break;
+ case IPPROTO_ICMP :
+ hlen += sizeof(icmphdr_t);
+ break;
+ default :
+ break;
+ }
+ /*
+ * If we don't have enough data in the mblk or we haven't yet copied
+ * enough (above), then copy some more.
+ */
+ if ((hlen > len)) {
+ len = MIN(hlen, sizeof(lbuf));
+ len = MIN(mlen, len);
+ copyout_mblk(m, 0, lbuf, len);
+ frstats[out].fr_pull[0]++;
+ ip = (ip_t *)lbuf;
+ }
+
+#ifndef sparc
+ __iplen = ip->ip_len;
+ ip->ip_len = ntohs(__iplen);
+ __ipoff = ip->ip_off;
+ ip->ip_off = ntohs(__ipoff);
+#endif
+
+ if ((iphlen < sizeof(ip_t)) || (iphlen > (u_short)ip->ip_len) ||
+ (mlen < (u_short)ip->ip_len)) {
+ /*
+ * Bad IP packet or not enough data/data length mismatches
+ */
+ m->b_rptr -= off;
+ frstats[out].fr_bad++;
+ return -1;
+ }
+
+ qif->qf_m = m;
+ qif->qf_len = len;
+ err = fr_check(ip, iphlen, qif->qf_ill, out, qif, q, mp);
+ /*
+ * Copy back the ip header data if it was changed, we haven't yet
+ * freed the message and we aren't going to drop the packet.
+ */
+#ifndef sparc
+ if (*mp) {
+ ip->ip_len = __iplen;
+ ip->ip_off = __ipoff;
+ }
+#endif
+ if (err == 1) {
+ if (*mp && (ip == (ip_t *)lbuf)) {
+ copyin_mblk(m, 0, lbuf, len);
+ frstats[out].fr_pull[1]++;
+ }
+ err = 0;
+ }
+ m->b_rptr -= off;
+ return err;
+}
+
+
+int fr_qin(q, mb)
+queue_t *q;
+mblk_t *mb;
+{
+ int (*pnext)(), type, synced = 0;
+ qif_t qfb, *qif;
+
+again:
+ mutex_enter(&ipfs_mutex);
+ while (!(qif = qif_from_queue(q))) {
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if (qif->qf_rqinfo == q->q_qinfo && qif->qf_inp) {
+ pnext = qif->qf_inp;
+ mutex_exit(&ipfs_mutex);
+ frstats[0].fr_notip++;
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
+ return (*pnext)(q, mb);
+ }
+ mutex_exit(&ipfs_mutex);
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ cmn_err(CE_WARN,
+ "IP Filter: dropped: fr_qin(%x,%x): type %x qif %x",
+ q, mb, MTYPE(mb), qif);
+ cmn_err(CE_CONT, "info %x next %x ptr %x fsrv %x bsrv %x\n",
+ q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
+ q->q_nbsrv);
+ cmn_err(CE_CONT, "IP Filter: info: putp %x srvp %x info %x\n",
+ q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
+ q->q_qinfo->qi_infop);
+ frstats[0].fr_drop++;
+ freemsg(mb);
+ return 0;
+ }
+ /*
+ * So we can be more re-entrant.
+ */
+ bcopy((char *)qif, (char *)&qfb, sizeof(*qif));
+ mutex_exit(&ipfs_mutex);
+ qif = &qfb;
+ pnext = qif->qf_inp;
+
+ type = MTYPE(mb);
+ if (type == M_DATA || type == M_PROTO || type == M_PCPROTO)
+ if (fr_precheck(&mb, q, qif, 0)) {
+ if (mb)
+ freemsg(mb);
+ return 0;
+ }
+
+ if (mb) {
+ if (pnext)
+ return (*pnext)(q, mb);
+
+ cmn_err(CE_WARN, "IP Filter: inp NULL: qif %x %s q %x info %x",
+ qif, qif->qf_name, q, q->q_qinfo);
+ freemsg(mb);
+ }
+ return 0;
+}
+
+
+int fr_qout(q, mb)
+queue_t *q;
+mblk_t *mb;
+{
+ int (*pnext)(), type, synced = 0;
+ qif_t qfb, *qif;
+
+again:
+ mutex_enter(&ipfs_mutex);
+ if (!(qif = qif_from_queue(q))) {
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if (qif->qf_wqinfo == q->q_qinfo && qif->qf_outp) {
+ pnext = qif->qf_outp;
+ mutex_exit(&ipfs_mutex);
+ frstats[1].fr_notip++;
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
+ return (*pnext)(q, mb);
+ }
+ mutex_exit(&ipfs_mutex);
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ cmn_err(CE_WARN,
+ "IP Filter: dropped: fr_qout(%x,%x): type %x: qif %x",
+ q, mb, MTYPE(mb), qif);
+ cmn_err(CE_CONT, "info %x next %x ptr %x fsrv %x bsrv %x\n",
+ q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
+ q->q_nbsrv);
+ cmn_err(CE_CONT, "IP Filter: info: putp %x srvp %x info %x\n",
+ q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
+ q->q_qinfo->qi_infop);
+ if (q->q_nfsrv)
+ cmn_err(CE_CONT, "nfsrv: info %x next %x ptr %x\n",
+ q->q_nfsrv->q_qinfo, q->q_nfsrv->q_next,
+ q->q_nfsrv->q_ptr);
+ if (q->q_nbsrv)
+ cmn_err(CE_CONT, "nbsrv: info %x next %x ptr %x\n",
+ q->q_nbsrv->q_qinfo, q->q_nbsrv->q_next,
+ q->q_nbsrv->q_ptr);
+ frstats[1].fr_drop++;
+ freemsg(mb);
+ return 0;
+ }
+ /*
+ * So we can be more re-entrant.
+ */
+ bcopy((char *)qif, (char *)&qfb, sizeof(*qif));
+ mutex_exit(&ipfs_mutex);
+ qif = &qfb;
+ pnext = qif->qf_outp;
+
+ type = MTYPE(mb);
+ if (type == M_DATA || type == M_PROTO || type == M_PCPROTO)
+ if (fr_precheck(&mb, q, qif, 1)) {
+ if (mb)
+ freemsg(mb);
+ return 0;
+ }
+
+ if (mb) {
+ if (pnext)
+ return (*pnext)(q, mb);
+
+ cmn_err(CE_WARN, "IP Filter: outp NULL: qif %x %s q %x info %x",
+ qif, qif->qf_name, q, q->q_qinfo);
+ freemsg(mb);
+ }
+ return 0;
+}
+
+
+/*
+ * attach the packet filter to each interface that is defined as having an
+ * IP address associated with it and save some of the info. for that struct
+ * so we're not out of date as soon as te ill disappears - but we must sync
+ * to be correct!
+ */
+int solattach()
+{
+ queue_t *in, *out;
+ qif_t *qif, *qf2;
+ ill_t *il;
+
+ for (il = ill_g_head; il; il = il->ill_next) {
+ in = il->ill_rq;
+ if (!in || !il->ill_wq)
+ continue;
+
+ out = il->ill_wq->q_next;
+
+ mutex_enter(&ipfs_mutex);
+ /*
+ * Look for entry already setup for this device
+ */
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if (qif->qf_iptr == in->q_ptr &&
+ qif->qf_optr == out->q_ptr)
+ break;
+ if (qif) {
+ mutex_exit(&ipfs_mutex);
+ continue;
+ }
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE,
+ "IP Filter: il %x ipt %x opt %x ipu %x opu %x i %x/%x",
+ il, in->q_ptr, out->q_ptr, in->q_qinfo->qi_putp,
+ out->q_qinfo->qi_putp, out->q_qinfo, in->q_qinfo);
+#endif
+ qif = (qif_t *)KMALLOC(sizeof(*qif));
+
+ if (in->q_qinfo->qi_putp == fr_qin) {
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_rqinfo == in->q_qinfo) {
+ qif->qf_inp = qf2->qf_inp;
+ break;
+ }
+ if (!qf2) {
+#ifdef IPFDEBUG
+ cmn_err(CE_WARN,
+ "IP Filter: rq:%s put %x qi %x",
+ il->ill_name, in->q_qinfo->qi_putp,
+ in->q_qinfo);
+#endif
+ mutex_exit(&ipfs_mutex);
+ KFREE(qif);
+ continue;
+ }
+ } else
+ qif->qf_inp = in->q_qinfo->qi_putp;
+
+ if (out->q_qinfo->qi_putp == fr_qout) {
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_wqinfo == out->q_qinfo) {
+ qif->qf_outp = qf2->qf_outp;
+ break;
+ }
+ if (!qf2) {
+#ifdef IPFDEBUG
+ cmn_err(CE_WARN,
+ "IP Filter: wq:%s put %x qi %x",
+ il->ill_name, out->q_qinfo->qi_putp,
+ out->q_qinfo);
+#endif
+ mutex_exit(&ipfs_mutex);
+ KFREE(qif);
+ continue;
+ }
+ } else
+ qif->qf_outp = out->q_qinfo->qi_putp;
+
+ qif->qf_ill = il;
+ qif->qf_iptr = in->q_ptr;
+ qif->qf_optr = out->q_ptr;
+ qif->qf_hl = il->ill_hdr_length;
+ strncpy(qif->qf_name, il->ill_name, sizeof(qif->qf_name));
+ qif->qf_name[sizeof(qif->qf_name) - 1] = '\0';
+ qif->qf_wqinfo = out->q_qinfo;
+ qif->qf_rqinfo = in->q_qinfo;
+
+ qif->qf_next = qif_head;
+ qif_head = qif;
+ in->q_qinfo->qi_putp = fr_qin;
+ out->q_qinfo->qi_putp = fr_qout;
+ mutex_exit(&ipfs_mutex);
+ cmn_err(CE_CONT, "IP Filter: attach to [%s,%d]\n",
+ qif->qf_name, il->ill_ppa);
+ }
+ if (!qif_head) {
+ cmn_err(CE_CONT, "IP Filter: not attached to any interfaces\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * look for bad consistancies between the list of interfaces the filter knows
+ * about and those which are currently configured.
+ */
+int ipfsync()
+{
+ register struct frentry *f, **fp;
+ register qif_t *qif, **qp;
+ register ill_t *il;
+
+ mutex_enter(&ipfs_mutex);
+ for (qp = &qif_head; (qif = *qp); ) {
+ for (il = ill_g_head; il; il = il->ill_next)
+ if ((qif->qf_ill == il) &&
+ !strcmp(qif->qf_name, il->ill_name)) {
+ mblk_t *m = il->ill_hdr_mp;
+
+ qif->qf_hl = il->ill_hdr_length;
+ if (m && qif->qf_hl != (m->b_wptr - m->b_rptr))
+ printf("ILL Header Length Mismatch\n");
+ break;
+ }
+ if (il) {
+ qp = &qif->qf_next;
+ continue;
+ }
+ cmn_err(CE_CONT, "IP Filter: detaching [%s]\n", qif->qf_name);
+ *qp = qif->qf_next;
+
+ /*
+ * Delete any rules directly associated with this interface
+ */
+ mutex_enter(&ipf_mutex);
+ for (fp = &ipfilter[0][0]; (f = *fp); )
+ if ((void *)f->fr_ifa == (void *)qif->qf_ill) {
+ *fp = f->fr_next;
+ KFREE(f);
+ } else
+ fp = &f->fr_next;
+ for (fp = &ipfilter[1][0]; (f = *fp); )
+ if ((void *)f->fr_ifa == (void *)qif->qf_ill) {
+ *fp = f->fr_next;
+ KFREE(f);
+ } else
+ fp = &f->fr_next;
+ mutex_exit(&ipf_mutex);
+
+ KFREE(qif);
+ qif = *qp;
+ }
+ mutex_exit(&ipfs_mutex);
+ return solattach();
+}
+
+
+/*
+ * unhook the IP filter from all defined interfaces with IP addresses
+ */
+int soldetach()
+{
+ queue_t *in, *out;
+ qif_t *qif, *qf2, **qp;
+ ill_t *il;
+
+ mutex_enter(&ipfs_mutex);
+ /*
+ * Make two passes, first get rid of all the unknown devices, next
+ * unlink known devices.
+ */
+ for (qp = &qif_head; (qif = *qp); ) {
+ for (il = ill_g_head; il; il = il->ill_next)
+ if (qif->qf_ill == il)
+ break;
+ if (il) {
+ qp = &qif->qf_next;
+ continue;
+ }
+ cmn_err(CE_CONT, "IP Filter: removing [%s]\n", qif->qf_name);
+ *qp = qif->qf_next;
+ KFREE(qif);
+ }
+
+ while ((qif = qif_head)) {
+ qif_head = qif->qf_next;
+ for (il = ill_g_head; il; il = il->ill_next)
+ if (qif->qf_ill == il)
+ break;
+ if (il) {
+ in = il->ill_rq;
+ out = il->ill_wq->q_next;
+ printf("IP Filter: detaching [%s,%d]\n", qif->qf_name,
+ il->ill_ppa);
+ in->q_qinfo->qi_putp = qif->qf_inp;
+ /*
+ * and change back if something is still interested
+ * in filtering (read side) on this interface.
+ */
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_rqinfo == in->q_qinfo) {
+ in->q_qinfo->qi_putp = fr_qin;
+ break;
+ }
+ /*
+ * and the write queue...
+ */
+ out->q_qinfo->qi_putp = qif->qf_outp;
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_wqinfo == out->q_qinfo) {
+ out->q_qinfo->qi_putp = fr_qout;
+ break;
+ }
+
+ }
+ KFREE(qif);
+ }
+ mutex_exit(&ipfs_mutex);
+ return ipldetach();
+}
+
+
+printire(ire)
+ire_t *ire;
+{
+ printf("ire: ll_hdr_mp %x rfq %x stq %x src_addr %x max_frag %d\n",
+ ire->ire_ll_hdr_mp, ire->ire_rfq, ire->ire_stq,
+ ire->ire_src_addr, ire->ire_max_frag);
+ printf("ire: mask %x addr %x gateway_addr %x type %d\n",
+ ire->ire_mask, ire->ire_addr, ire->ire_gateway_addr,
+ ire->ire_type);
+ printf("ire: ll_hdr_length %d ll_hdr_saved_mp %x\n",
+ ire->ire_ll_hdr_length, ire->ire_ll_hdr_saved_mp);
+}
+
+
+int ipfr_fastroute(qf, ip, mb, mpp, fin, fdp)
+qif_t *qf;
+ip_t *ip;
+mblk_t *mb, **mpp;
+fr_info_t *fin;
+frdest_t *fdp;
+{
+ mblk_t *mp = NULL;
+ struct in_addr dst;
+ ire_t *ir, *dir;
+ int hlen = 0;
+ u_char *s;
+ queue_t *q = NULL;
+
+#ifndef sparc
+ u_short __iplen, __ipoff;
+
+ /*
+ * If this is a duplicate mblk then we want ip to point at that
+ * data, not the original, if and only if it is already pointing at
+ * the current mblk data.
+ */
+ if (ip == (ip_t *)qf->qf_m->b_rptr && qf->qf_m != mb)
+ ip = (ip_t *)mb->b_rptr;
+ /*
+ * In fr_precheck(), we modify ip_len and ip_off in an aligned data
+ * area. However, we only need to change it back if we didn't copy
+ * the IP header data out.
+ */
+
+ __iplen = (u_short)ip->ip_len,
+ __ipoff = (u_short)ip->ip_off;
+
+ ip->ip_len = htons(__iplen);
+ ip->ip_off = htons(__ipoff);
+#endif
+
+ if (ip != (ip_t *)mb->b_rptr) {
+ copyin_mblk(mb, 0, ip, qf->qf_len);
+ frstats[fin->fin_out].fr_pull[1]++;
+ }
+
+ /*
+ * If there is another M_PROTO, we don't want it
+ */
+ if (*mpp != mb) {
+ (*mpp)->b_cont = NULL;
+ freemsg(*mpp);
+ }
+
+ ir = (ire_t *)fdp->fd_ifp;
+
+ if (fdp->fd_ip.s_addr)
+ dst = fdp->fd_ip;
+ else
+ dst = fin->fin_fi.fi_dst;
+
+ if (dir = ire_lookup(dst.s_addr))
+ if (!dir->ire_ll_hdr_mp || !dir->ire_ll_hdr_length)
+ dir = NULL;
+
+ if (!ir)
+ ir = dir;
+
+ if (ir && dir) {
+ if ((mp = dir->ire_ll_hdr_mp)) {
+ hlen = dir->ire_ll_hdr_length;
+
+ s = mb->b_rptr;
+
+ if (hlen && (s - mb->b_datap->db_base) >= hlen) {
+ s -= hlen;
+ mb->b_rptr = (u_char *)s;
+ bcopy((char *)mp->b_rptr, (char *)s, hlen);
+ } else {
+ mblk_t *mp2;
+
+ mp2 = copyb(mp);
+ if (!mp2)
+ goto bad_fastroute;
+ mp2->b_cont = mb;
+ mb = mp2;
+ }
+ }
+
+ if (ir->ire_stq)
+ q = ir->ire_stq;
+ else if (ir->ire_rfq)
+ q = WR(ir->ire_rfq);
+ if (q) {
+ putnext(q, mb);
+ return 0;
+ }
+ }
+bad_fastroute:
+ return -1;
+}
+
+
+void copyout_mblk(m, off, buf, len)
+mblk_t *m;
+int off, len;
+char *buf;
+{
+ char *s, *bp = buf;
+ int mlen, olen, clen;
+
+ for (; m && len; m = m->b_cont) {
+ if (MTYPE(m) != M_DATA)
+ continue;
+ s = m->b_rptr;
+ mlen = (char *)m->b_wptr - s;
+ olen = MIN(off, mlen);
+ if ((olen == mlen) || (olen < off)) {
+ off -= olen;
+ continue;
+ } else if (olen) {
+ off -= olen;
+ s += olen;
+ mlen -= olen;
+ }
+ clen = MIN(mlen, len);
+ bcopy(s, bp, clen);
+ len -= clen;
+ bp += clen;
+ }
+}
+
+
+void copyin_mblk(m, off, buf, len)
+mblk_t *m;
+int off, len;
+char *buf;
+{
+ char *s, *bp = buf;
+ int mlen, olen, clen;
+
+ for (; m && len; m = m->b_cont) {
+ if (MTYPE(m) != M_DATA)
+ continue;
+ s = m->b_rptr;
+ mlen = (char *)m->b_wptr - s;
+ olen = MIN(off, mlen);
+ if ((olen == mlen) || (olen < off)) {
+ off -= olen;
+ continue;
+ } else if (olen) {
+ off -= olen;
+ s += olen;
+ mlen -= olen;
+ }
+ clen = MIN(mlen, len);
+ bcopy(bp, s, clen);
+ len -= clen;
+ bp += clen;
+ }
+}
OpenPOWER on IntegriCloud