aboutsummaryrefslogtreecommitdiff
path: root/contrib/ipfilter/solaris.c
diff options
context:
space:
mode:
authorGuido van Rooij <guido@FreeBSD.org>1999-11-08 20:51:23 +0000
committerGuido van Rooij <guido@FreeBSD.org>1999-11-08 20:51:23 +0000
commitc9bff7ba93205e0745fa8a309db3789ba1562f24 (patch)
treedbbb879c93cb0348e4c4fd6a3ef24f80198ce5a1 /contrib/ipfilter/solaris.c
parent9b632708fe7d7ae0badd09f08d11857ca24400f7 (diff)
downloadsrc-c9bff7ba93205e0745fa8a309db3789ba1562f24.tar.gz
src-c9bff7ba93205e0745fa8a309db3789ba1562f24.zip
Import of ipfilter 3.3.3 in anticipation of its revival.
More to come in the next days.
Notes
Notes: svn path=/vendor/ipfilter/dist/; revision=53024
Diffstat (limited to 'contrib/ipfilter/solaris.c')
-rw-r--r--contrib/ipfilter/solaris.c704
1 files changed, 463 insertions, 241 deletions
diff --git a/contrib/ipfilter/solaris.c b/contrib/ipfilter/solaris.c
index fe2a243744ac..b1cb19b2d297 100644
--- a/contrib/ipfilter/solaris.c
+++ b/contrib/ipfilter/solaris.c
@@ -1,12 +1,12 @@
/*
- * Copyright (C) 1993-1997 by Darren Reed.
+ * Copyright (C) 1993-1998 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.2.22.2.4 1998/02/28 02:35:21 darrenr Exp $";
+#pragma ident "@(#)$Id: solaris.c,v 2.1.2.5 1999/10/15 13:49:44 darrenr Exp $";
#include <sys/systm.h>
#include <sys/types.h>
@@ -27,6 +27,9 @@
#include <sys/autoconf.h>
#include <sys/byteorder.h>
#include <sys/socket.h>
+#include <sys/dlpi.h>
+#include <sys/stropts.h>
+#include <sys/sockio.h>
#include <net/if.h>
#include <net/af.h>
#include <net/route.h>
@@ -46,6 +49,7 @@
#include "ip_fil.h"
#include "ip_nat.h"
+
char _depends_on[] = "drv/ip";
@@ -56,13 +60,14 @@ void solattach __P((void));
int soldetach __P((void));
extern struct filterstats frstats[];
-extern kmutex_t ipf_mutex, ipfs_mutex, ipf_nat;
+extern KRWLOCK_T ipf_mutex, ipfs_mutex, ipf_nat, ipf_solaris;
+extern kmutex_t ipf_rw;
+extern int fr_running;
extern int fr_flags;
extern ipnat_t *nat_list;
static qif_t *qif_head = NULL;
-
static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
void *, void **));
static int ipf_probe __P((dev_info_t *));
@@ -71,9 +76,22 @@ static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
static qif_t *qif_from_queue __P((queue_t *));
static void fr_donotip __P((int, qif_t *, queue_t *, mblk_t *,
- mblk_t *, ip_t *, int));
+ mblk_t *, ip_t *, size_t));
static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH,
NULL };
+static int (*ipf_ip_inp) __P((queue_t *, mblk_t *)) = NULL;
+
+
+#if SOLARIS2 >= 7
+extern void ipfr_slowtimer __P((void *));
+timeout_id_t ipfr_timer_id;
+static timeout_id_t synctimeoutid = 0;
+#else
+extern void ipfr_slowtimer __P((void));
+int ipfr_timer_id;
+static int synctimeoutid = 0;
+#endif
+
#ifdef IPFDEBUG
void printire __P((ire_t *));
#endif
@@ -127,46 +145,54 @@ static dev_info_t *ipf_dev_info = NULL;
int _init()
{
-#ifdef IPFDEBUG
- int ipfinst = mod_install(&modlink1);
+ int ipfinst;
+ if (fr_running < 0)
+ return -1;
+ ipfinst = mod_install(&modlink1);
+#ifdef IPFDEBUG
cmn_err(CE_NOTE, "IP Filter: _init() = %d\n", ipfinst);
- return ipfinst;
-#else
- return mod_install(&modlink1);
#endif
+ return ipfinst;
}
int _fini(void)
{
-#ifdef IPFDEBUG
- int ipfinst = mod_remove(&modlink1);
+ int ipfinst;
+ if (fr_running < 0)
+ return -1;
+ ipfinst = mod_remove(&modlink1);
+#ifdef IPFDEBUG
cmn_err(CE_NOTE, "IP Filter: _fini() = %d\n", ipfinst);
- return ipfinst;
-#else
- return mod_remove(&modlink1);
#endif
+ return ipfinst;
}
int _info(modinfop)
struct modinfo *modinfop;
{
+ int ipfinst;
+
+ if (fr_running < 0)
+ return -1;
+ ipfinst = mod_info(&modlink1, modinfop);
#ifdef IPFDEBUG
- int ipfinst = mod_info(&modlink1, modinfop);
cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x\n", modinfop, ipfinst);
- return ipfinst;
-#else
- return mod_info(&modlink1, modinfop);
#endif
+ if (fr_running > 0)
+ ipfsync();
+ return ipfinst;
}
static int ipf_probe(dip)
dev_info_t *dip;
{
+ if (fr_running < 0)
+ return DDI_PROBE_FAILURE;
#ifdef IPFDEBUG
cmn_err(CE_NOTE, "IP Filter: ipf_probe(%x)", dip);
#endif
@@ -197,6 +223,8 @@ ddi_attach_cmd_t cmd;
#endif
switch (cmd) {
case DDI_ATTACH:
+ if (fr_running < 0)
+ break;
#ifdef IPFDEBUG
instance = ddi_get_instance(dip);
@@ -227,13 +255,26 @@ ddi_attach_cmd_t cmd;
/*
* Initialize mutex's
*/
- iplattach();
+ if (iplattach() == -1)
+ goto attach_failed;
+ /*
+ * Lock people out while we set things up.
+ */
+ WRITE_ENTER(&ipf_solaris);
solattach();
solipdrvattach();
- cmn_err(CE_CONT, "IP Filter: attaching complete.\n");
- return (DDI_SUCCESS);
+ RWLOCK_EXIT(&ipf_solaris);
+ cmn_err(CE_CONT, "%s, attaching complete.\n", ipfilter_version);
+ sync();
+ if (fr_running == 0)
+ fr_running = 1;
+ if (ipfr_timer_id == 0)
+ ipfr_timer_id = timeout(ipfr_slowtimer, NULL,
+ drv_usectohz(500000));
+ if (fr_running == 1)
+ return DDI_SUCCESS;
default:
- return (DDI_FAILURE);
+ return DDI_FAILURE;
}
attach_failed:
@@ -243,7 +284,7 @@ attach_failed:
* away any stuff we allocated above.
*/
(void) ipf_detach(dip, DDI_DETACH);
- return (DDI_FAILURE);
+ return DDI_FAILURE;
}
@@ -251,13 +292,35 @@ static int ipf_detach(dip, cmd)
dev_info_t *dip;
ddi_detach_cmd_t cmd;
{
- int instance;
+ int i;
#ifdef IPFDEBUG
cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
#endif
switch (cmd) {
case DDI_DETACH:
+ if (fr_running <= 0)
+ break;
+ /*
+ * Make sure we're the only one's modifying things. With
+ * this lock others should just fall out of the loop.
+ */
+ mutex_enter(&ipf_rw);
+ if (ipfr_timer_id != 0) {
+ untimeout(ipfr_timer_id);
+ ipfr_timer_id = 0;
+ }
+ mutex_exit(&ipf_rw);
+ WRITE_ENTER(&ipf_solaris);
+ mutex_enter(&ipf_rw);
+ if (fr_running <= 0) {
+ mutex_exit(&ipf_rw);
+ return DDI_FAILURE;
+ }
+ fr_running = -1;
+ mutex_exit(&ipf_rw);
+ /* NOTE: ipf_solaris rwlock is released in ipldetach */
+
/*
* Undo what we did in ipf_attach, freeing resources
* and removing things we installed. The system
@@ -265,10 +328,14 @@ ddi_detach_cmd_t cmd;
* node in any other entry points at this time.
*/
ddi_prop_remove_all(dip);
- instance = ddi_get_instance(dip);
+ i = ddi_get_instance(dip);
ddi_remove_minor_node(dip, NULL);
sync();
- solipdrvdetach();
+ i = solipdrvdetach();
+ if (i > 0) {
+ cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
+ return DDI_FAILURE;
+ }
if (!soldetach()) {
cmn_err(CE_CONT, "IP Filter: detached\n");
return (DDI_SUCCESS);
@@ -276,6 +343,7 @@ ddi_detach_cmd_t cmd;
default:
return (DDI_FAILURE);
}
+ return DDI_FAILURE;
}
@@ -284,10 +352,13 @@ dev_info_t *dip;
ddi_info_cmd_t infocmd;
void *arg, **result;
{
- int error = DDI_FAILURE;
+ int error;
+ if (fr_running <= 0)
+ return DDI_FAILURE;
+ error = DDI_FAILURE;
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x)", dip, infocmd);
+ cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg);
#endif
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
@@ -331,7 +402,7 @@ qif_t *qif;
queue_t *q;
mblk_t *m, *mt;
ip_t *ip;
-int off;
+size_t off;
{
u_char *s, outb[256], *t;
int i;
@@ -344,32 +415,35 @@ int off;
if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA))
m = m->b_cont;
- printf("!IP %s:%d %p %p %p %d %p %p %p %d %d %p\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) {
+ printf("!IP %s:%d %d %p %p %p %d %p/%d %p/%d %p %d %d %p\n",
+ qif ? qif->qf_name : "?", out, qif->qf_hl, q,
+ q ? q->q_ptr : NULL, q ? q->q_qinfo : NULL,
+ mt->b_wptr - mt->b_rptr, m, MTYPE(m), mt, MTYPE(mt), m->b_rptr,
+ m->b_wptr - m->b_rptr, off, ip);
+ printf("%02x%02x%02x%02x\n", *s, *(s+1), *(s+2), *(s+3));
+ while (m != mt) {
i = 0;
t = outb;
s = mt->b_rptr;
- sprintf(t, "%d:", MTYPE(mt));
- t += strlen(t);
+ sprintf((char *)t, "%d:", MTYPE(mt));
+ t += strlen((char *)t);
for (; (i < 100) && (s < mt->b_wptr); i++) {
- sprintf(t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
+ sprintf((char *)t, "%02x%s", *s++,
+ ((i & 3) == 3) ? " " : "");
t += ((i & 3) == 3) ? 3 : 2;
}
*t++ = '\n';
*t = '\0';
printf("%s", outb);
+ mt = mt->b_cont;
}
i = 0;
t = outb;
s = m->b_rptr;
- sprintf(t, "%d:", MTYPE(m));
- t += strlen(t);
+ sprintf((char *)t, "%d:", MTYPE(m));
+ t += strlen((char *)t);
for (; (i < 100) && (s < m->b_wptr); i++) {
- sprintf(t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
+ sprintf((char *)t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
t += ((i & 3) == 3) ? 3 : 2;
}
*t++ = '\n';
@@ -382,7 +456,7 @@ int off;
* 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!
+ * done yet (for incoming packets) - dangerous!
*/
static int fr_precheck(mp, q, qif, out)
mblk_t **mp;
@@ -390,10 +464,11 @@ queue_t *q;
qif_t *qif;
int out;
{
- u_long lbuf[48];
- mblk_t *m, *mt = *mp;
+ register mblk_t *m, *mt = *mp;
register ip_t *ip;
- int iphlen, hlen, len, err, mlen, off, synced = 0;
+ size_t hlen, len, off, mlen, iphlen;
+ int err, synced = 0;
+ u_char *bp;
#ifndef sparc
u_short __iplen, __ipoff;
#endif
@@ -407,14 +482,43 @@ tryagain:
off = (out) ? qif->qf_hl : 0;
/*
+ * If the message protocol block indicates that there isn't a data
+ * block following it, just return back.
+ */
+ bp = (u_char *)ALIGN32(mt->b_rptr);
+ if (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO) {
+ dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp;
+ if (dl->dl_primitive != DL_UNITDATA_IND &&
+ dl->dl_primitive != DL_UNITDATA_REQ) {
+ frstats[out].fr_notdata++;
+ return 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)
+ if (!m) {
+ frstats[out].fr_nodata++;
return 0; /* No data blocks */
+ }
+
+ /*
+ * This is a complete kludge to try and work around some bizarre
+ * packets which drop through into fr_donotip.
+ */
+ if ((mt != m) && (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO)) {
+ dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp;
+ if ((dl->dl_primitive == DL_UNITDATA_IND) &&
+ (dl->dl_group_address == 1))
+ if (((*((u_char *)m->b_rptr) == 0x0) &&
+ ((*((u_char *)m->b_rptr + 2) == 0x45))))
+ off += 2;
+ }
ip = (ip_t *)(m->b_rptr + off); /* MMM */
@@ -424,31 +528,58 @@ tryagain:
*/
while ((u_char *)ip >= m->b_wptr) {
len = (u_char *)ip - m->b_wptr;
- if (!(m = m->b_cont))
+ m = m->b_cont;
+ if (m == NULL)
return 0; /* not enough data for IP */
ip = (ip_t *)(m->b_rptr + len);
}
- if ((off = (u_char *)ip - m->b_rptr))
+ off = (u_char *)ip - m->b_rptr;
+ if (off != 0)
m->b_rptr = (u_char *)ip;
mlen = msgdsize(m);
+ len = m->b_wptr - m->b_rptr;
+ if (m->b_wptr < m->b_rptr) {
+ cmn_err(CE_NOTE, "IP Filter: Bad packet: wptr %p < rptr %p",
+ m->b_wptr, m->b_rptr);
+ frstats[out].fr_bad++;
+ return -1;
+ }
/*
- * 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.
+ * Ok, the IP header isn't on a 32bit aligned address so junk it.
*/
- if (!OK_32PTR(ip)) {
- len = MIN(mlen, sizeof(ip_t));
- copyout_mblk(m, 0, len, (char *)lbuf);
+ if (((u_int)ip & 0x3) || (len < sizeof(*ip))) {
+ /*
+ * We have link layer header and IP header in the same mbuf,
+ * problem being that a pullup without adjusting b_rptr will
+ * bring us back here again as it's likely that the start of
+ * the databuffer (b_datab->db_base) is already aligned. Hmm,
+ * should we pull it all up (length of -1 to pullupmsg) if we
+ * can, now ?
+ */
+fixalign:
+ if (off == (u_char *)ip - m->b_rptr) {
+ m->b_rptr += off;
+ off = 0;
+ }
+ if (!pullupmsg(m, sizeof(ip_t) + off)) {
+ cmn_err(CE_NOTE, "pullupmsg failed\n");
+ frstats[out].fr_pull[1]++;
+ return -1;
+ }
frstats[out].fr_pull[0]++;
- ip = (ip_t *)lbuf;
- } else
- len = m->b_wptr - (u_char *)ip;
+ synced = 1;
+ off = 0;
+ goto tryagain;
+ }
if (ip->ip_v != IPVERSION) {
m->b_rptr -= off;
if (!synced) {
synced = 1;
+ RWLOCK_EXIT(&ipfs_mutex);
ipfsync();
+ READ_ENTER(&ipfs_mutex);
goto tryagain;
}
fr_donotip(out, qif, q, m, mt, ip, off);
@@ -456,13 +587,41 @@ tryagain:
return (fr_flags & FF_BLOCKNONIP) ? -1 : 0;
}
+#ifndef sparc
+ __iplen = (u_short)ip->ip_len,
+ __ipoff = (u_short)ip->ip_off;
+
+ ip->ip_len = ntohs(__iplen);
+ ip->ip_off = ntohs(__ipoff);
+#endif
+
hlen = iphlen = ip->ip_hl << 2;
+ 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
+ */
+ cmn_err(CE_NOTE,
+ "IP Filter: Bad packet: iphlen %u ip_len %u mlen %u",
+ iphlen, ip->ip_len, mlen);
+#ifndef sparc
+ __iplen = (u_short)ip->ip_len,
+ __ipoff = (u_short)ip->ip_off;
+
+ ip->ip_len = htons(__iplen);
+ ip->ip_off = htons(__ipoff);
+#endif
+ m->b_rptr -= off;
+ frstats[out].fr_bad++;
+ return -1;
+ }
+
/*
* Make hlen the total size of the IP header plus TCP/UDP/ICMP header
* (if it is one of these three).
*/
- if (!(ntohs((u_short)ip->ip_off) & 0x1fff))
+ if ((ip->ip_off & IP_OFFMASK) == 0)
switch (ip->ip_p)
{
case IPPROTO_TCP :
@@ -478,62 +637,51 @@ tryagain:
default :
break;
}
+
+ if (hlen > mlen)
+ hlen = mlen;
+
/*
* 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, len, (char *)lbuf);
+ if (!pullupmsg(m, (int)hlen)) {
+ cmn_err(CE_NOTE, "pullupmsg failed\n");
+ frstats[out].fr_pull[1]++;
+ return -1;
+ }
frstats[out].fr_pull[0]++;
- ip = (ip_t *)lbuf;
+ ip = (ip_t *)ALIGN32(m->b_rptr);
}
-
-#ifndef sparc
- __iplen = (u_short)ip->ip_len,
- __ipoff = (u_short)ip->ip_off;
-
- ip->ip_len = htons(__iplen);
- ip->ip_off = htons(__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_q = q;
qif->qf_off = off;
qif->qf_len = len;
err = fr_check(ip, iphlen, qif->qf_ill, out, qif, mp);
+ if (err == 2)
+ goto fixalign;
/*
* 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.
+ * BUT only do this if there were no changes to the buffer, else
+ * we can't be sure that the ip pointer is still correct!
*/
+ if (*mp != NULL) {
+ if (*mp == mt) {
+ m->b_rptr -= off;
#ifndef sparc
- if (*mp) {
- __iplen = (u_short)ip->ip_len,
- __ipoff = (u_short)ip->ip_off;
+ __iplen = (u_short)ip->ip_len,
+ __ipoff = (u_short)ip->ip_off;
- ip->ip_len = htons(__iplen);
- ip->ip_off = htons(__ipoff);
- }
+ ip->ip_len = htons(__iplen);
+ ip->ip_off = htons(__ipoff);
#endif
- if (err == -2) {
- if (*mp && (ip == (ip_t *)lbuf)) {
- copyin_mblk(m, 0, len, (char *)lbuf);
- frstats[out].fr_pull[1]++;
- }
- err = 0;
+ } else
+ cmn_err(CE_NOTE,
+ "IP Filter: *mp %p mt %p %s\n", *mp, mt,
+ "mblk changed, cannot revert ip_len, ip_off");
}
- m->b_rptr -= off;
return err;
}
@@ -542,27 +690,41 @@ int fr_qin(q, mb)
queue_t *q;
mblk_t *mb;
{
- int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0;
- qif_t qfb, *qif;
+ int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
+ qif_t qf, *qif;
+ if (fr_running <= 0) {
+ mb->b_prev = NULL;
+ freemsg(mb);
+ return 0;
+ }
+
+ READ_ENTER(&ipf_solaris);
again:
- mutex_enter(&ipfs_mutex);
- while (!(qif = qif_from_queue(q))) {
+ if (fr_running <= 0) {
+ RWLOCK_EXIT(&ipf_solaris);
+ mb->b_prev = NULL;
+ freemsg(mb);
+ return 0;
+ }
+ READ_ENTER(&ipfs_mutex);
+ if (!(qif = qif_from_queue(q))) {
for (qif = qif_head; qif; qif = qif->qf_next)
if (&qif->qf_rqinit == q->q_qinfo && qif->qf_rqinfo &&
qif->qf_rqinfo->qi_putp) {
pnext = qif->qf_rqinfo->qi_putp;
- mutex_exit(&ipfs_mutex);
frstats[0].fr_notip++;
+ RWLOCK_EXIT(&ipfs_mutex);
if (!synced) {
ipfsync();
synced = 1;
goto again;
}
+ RWLOCK_EXIT(&ipf_solaris);
/* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
return (*pnext)(q, mb);
}
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
if (!synced) {
ipfsync();
synced = 1;
@@ -584,31 +746,32 @@ again:
#endif
);
frstats[0].fr_drop++;
+ RWLOCK_EXIT(&ipf_solaris);
+ mb->b_prev = NULL;
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_rqinfo->qi_putp;
+ bcopy((char *)qif, (char *)&qf, sizeof(qf));
+ qif = &qf;
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;
- }
+ pnext = qif->qf_rqinfo->qi_putp;
- if (mb) {
+ if (datamsg(type) || (type == M_BREAK))
+ err = fr_precheck(&mb, q, qif, 0);
+
+ RWLOCK_EXIT(&ipfs_mutex);
+ RWLOCK_EXIT(&ipf_solaris);
+
+ if ((err == 0) && (mb != NULL)) {
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);
+ cmn_err(CE_WARN, "IP Filter: inp NULL: qif %x q %x info %x",
+ qif, q, q->q_qinfo);
+ }
+ if (mb) {
+ mb->b_prev = NULL;
freemsg(mb);
}
return 0;
@@ -619,17 +782,30 @@ int fr_qout(q, mb)
queue_t *q;
mblk_t *mb;
{
- int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0;
- qif_t qfb, *qif;
+ int (*pnext) __P((queue_t *, mblk_t *)), type, synced = 0, err = 0;
+ qif_t qf, *qif;
+ if (fr_running <= 0) {
+ mb->b_prev = NULL;
+ freemsg(mb);
+ return 0;
+ }
+
+ READ_ENTER(&ipf_solaris);
again:
- mutex_enter(&ipfs_mutex);
+ if (fr_running <= 0) {
+ RWLOCK_EXIT(&ipf_solaris);
+ mb->b_prev = NULL;
+ freemsg(mb);
+ return 0;
+ }
+ READ_ENTER(&ipfs_mutex);
if (!(qif = qif_from_queue(q))) {
for (qif = qif_head; qif; qif = qif->qf_next)
if (&qif->qf_wqinit == q->q_qinfo && qif->qf_wqinfo &&
qif->qf_wqinfo->qi_putp) {
pnext = qif->qf_wqinfo->qi_putp;
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
frstats[1].fr_notip++;
if (!synced) {
ipfsync();
@@ -637,9 +813,10 @@ again:
goto again;
}
/* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
+ RWLOCK_EXIT(&ipf_solaris);
return (*pnext)(q, mb);
}
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
if (!synced) {
ipfsync();
synced = 1;
@@ -671,63 +848,73 @@ again:
q->q_nbsrv->q_qinfo, q->q_nbsrv->q_next,
q->q_nbsrv->q_ptr);
frstats[1].fr_drop++;
+ RWLOCK_EXIT(&ipf_solaris);
+ mb->b_prev = NULL;
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_wqinfo->qi_putp;
+ bcopy((char *)qif, (char *)&qf, sizeof(qf));
+ qif = &qf;
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;
- }
+ pnext = qif->qf_wqinfo->qi_putp;
- if (mb) {
+ if (datamsg(type) || (type == M_BREAK))
+ err = fr_precheck(&mb, q, qif, 1);
+
+ RWLOCK_EXIT(&ipfs_mutex);
+ RWLOCK_EXIT(&ipf_solaris);
+
+ if ((err == 0) && (mb != NULL)) {
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);
+ }
+ if (mb) {
+ mb->b_prev = NULL;
freemsg(mb);
}
return 0;
}
-static int (*ipf_ip_inp) __P((queue_t *, mblk_t *)) = NULL;
-
-#include <sys/stropts.h>
-#include <sys/sockio.h>
-
-static int synctimeoutid = 0;
void ipf_synctimeout(arg)
-caddr_t arg;
+void *arg;
{
+ READ_ENTER(&ipf_solaris);
ipfsync();
- mutex_enter(&ipfs_mutex);
+ WRITE_ENTER(&ipfs_mutex);
synctimeoutid = 0;
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
+ RWLOCK_EXIT(&ipf_solaris);
}
-static int ipf_ip_qin(q, mp)
+static int ipf_ip_qin(q, mb)
queue_t *q;
-mblk_t *mp;
+mblk_t *mb;
{
struct iocblk *ioc;
int ret;
+
+ if (fr_running <= 0) {
+ mb->b_prev = NULL;
+ freemsg(mb);
+ return 0;
+ }
- if (mp->b_datap->db_type != M_IOCTL)
- return (*ipf_ip_inp)(q, mp);
+ if (MTYPE(mb) != M_IOCTL)
+ return (*ipf_ip_inp)(q, mb);
- ioc = (struct iocblk *)mp->b_rptr;
+ READ_ENTER(&ipf_solaris);
+ if (fr_running <= 0) {
+ RWLOCK_EXIT(&ipf_solaris);
+ mb->b_prev = NULL;
+ freemsg(mb);
+ return 0;
+ }
+ ioc = (struct iocblk *)mb->b_rptr;
switch (ioc->ioc_cmd) {
case I_LINK:
@@ -737,23 +924,23 @@ mblk_t *mp;
#ifdef IPFDEBUG
cmn_err(CE_NOTE, "IP Filter: ipf_ip_qin() M_IOCTL type=0x%x\n", ioc->ioc_cmd);
#endif
- ret = (*ipf_ip_inp)(q, mp);
+ ret = (*ipf_ip_inp)(q, mb);
- mutex_enter(&ipfs_mutex);
+ WRITE_ENTER(&ipfs_mutex);
if (synctimeoutid == 0) {
- synctimeoutid = timeout(
- ipf_synctimeout,
+ synctimeoutid = timeout(ipf_synctimeout,
NULL,
drv_usectohz(1000000) /*1 sec*/
);
- mutex_exit(&ipfs_mutex);
- } else
- mutex_exit(&ipfs_mutex);
+ }
- return ret;
+ RWLOCK_EXIT(&ipfs_mutex);
+ break;
default:
- return (*ipf_ip_inp)(q, mp);
+ ret = (*ipf_ip_inp)(q, mb);
}
+ RWLOCK_EXIT(&ipf_solaris);
+ return ret;
}
static int ipdrvattcnt = 0;
@@ -762,7 +949,8 @@ extern struct streamtab ipinfo;
void solipdrvattach()
{
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: solipdrvattach() ipinfo=0x%lx\n", &ipinfo);
+ cmn_err(CE_NOTE, "IP Filter: solipdrvattach() %d ipinfo=0x%lx\n",
+ ipdrvattcnt, &ipinfo);
#endif
if (++ipdrvattcnt == 1) {
@@ -776,38 +964,39 @@ void solipdrvattach()
int solipdrvdetach()
{
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: solipdrvdetach() ipinfo=0x%lx\n", &ipinfo);
+ cmn_err(CE_NOTE, "IP Filter: solipdrvdetach() %d ipinfo=0x%lx\n",
+ ipdrvattcnt, &ipinfo);
#endif
+ WRITE_ENTER(&ipfs_mutex);
if (--ipdrvattcnt <= 0) {
if (ipf_ip_inp && (ipinfo.st_wrinit->qi_putp == ipf_ip_qin)) {
ipinfo.st_wrinit->qi_putp = ipf_ip_inp;
ipf_ip_inp = NULL;
}
- mutex_enter(&ipfs_mutex);
if (synctimeoutid) {
- synctimeoutid = 0;
- mutex_exit(&ipfs_mutex);
untimeout(synctimeoutid);
- } else
- mutex_exit(&ipfs_mutex);
+ synctimeoutid = 0;
+ }
}
+ RWLOCK_EXIT(&ipfs_mutex);
+ return ipdrvattcnt;
}
/*
* 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
+ * so we're not out of date as soon as the ill disappears - but we must sync
* to be correct!
*/
void solattach()
{
queue_t *in, *out;
- qif_t *qif, *qf2;
- ill_t *il;
struct frentry *f;
+ qif_t *qif, *qf2;
ipnat_t *np;
- int len;
+ size_t len;
+ ill_t *il;
for (il = ill_g_head; il; il = il->ill_next) {
in = il->ill_rq;
@@ -816,7 +1005,7 @@ void solattach()
out = il->ill_wq->q_next;
- mutex_enter(&ipfs_mutex);
+ WRITE_ENTER(&ipfs_mutex);
/*
* Look for entry already setup for this device
*/
@@ -825,7 +1014,7 @@ void solattach()
qif->qf_optr == out->q_ptr)
break;
if (qif) {
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
continue;
}
#ifdef IPFDEBUG
@@ -834,11 +1023,12 @@ void solattach()
il, in->q_ptr, out->q_ptr, in->q_qinfo->qi_putp,
out->q_qinfo->qi_putp, out->q_qinfo, in->q_qinfo);
#endif
- KMALLOC(qif, qif_t *, sizeof(*qif));
+ KMALLOC(qif, qif_t *);
if (!qif) {
cmn_err(CE_NOTE,
"IP Filter: malloc(%d) for qif_t failed\n",
sizeof(qif_t));
+ RWLOCK_EXIT(&ipfs_mutex);
continue;
}
@@ -855,7 +1045,7 @@ void solattach()
il->ill_name, in->q_qinfo->qi_putp,
in->q_qinfo);
#endif
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
KFREE(qif);
continue;
}
@@ -875,7 +1065,7 @@ void solattach()
il->ill_name, out->q_qinfo->qi_putp,
out->q_qinfo);
#endif
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
KFREE(qif);
continue;
}
@@ -883,6 +1073,8 @@ void solattach()
qif->qf_wqinfo = out->q_qinfo;
qif->qf_ill = il;
+ qif->qf_in = in;
+ qif->qf_out = out;
qif->qf_iptr = in->q_ptr;
qif->qf_optr = out->q_ptr;
qif->qf_hl = il->ill_hdr_length;
@@ -895,34 +1087,37 @@ void solattach()
/*
* Activate any rules directly associated with this interface
*/
- mutex_enter(&ipf_mutex);
+ WRITE_ENTER(&ipf_mutex);
for (f = ipfilter[0][fr_active]; f; f = f->fr_next) {
if ((f->fr_ifa == (struct ifnet *)-1)) {
- len = strlen(f->fr_ifname)+1; /* includes \0 */
- if (len && (len == il->ill_name_length) &&
+ len = strlen(f->fr_ifname) + 1;
+ if ((len != 0) &&
+ (len == (size_t)il->ill_name_length) &&
!strncmp(il->ill_name, f->fr_ifname, len))
f->fr_ifa = il;
}
}
for (f = ipfilter[1][fr_active]; f; f = f->fr_next) {
if ((f->fr_ifa == (struct ifnet *)-1)) {
- len = strlen(f->fr_ifname)+1; /* includes \0 */
- if (len && (len == il->ill_name_length) &&
+ len = strlen(f->fr_ifname) + 1;
+ if ((len != 0) &&
+ (len == (size_t)il->ill_name_length) &&
!strncmp(il->ill_name, f->fr_ifname, len))
f->fr_ifa = il;
}
}
- mutex_exit(&ipf_mutex);
- mutex_enter(&ipf_nat);
+ RWLOCK_EXIT(&ipf_mutex);
+ WRITE_ENTER(&ipf_nat);
for (np = nat_list; np; np = np->in_next) {
if ((np->in_ifp == (struct ifnet *)-1)) {
- len = strlen(np->in_ifname)+1; /* includes \0 */
- if (len && (len == il->ill_name_length) &&
+ len = strlen(np->in_ifname) + 1;
+ if ((len != 0) &&
+ (len == (size_t)il->ill_name_length) &&
!strncmp(il->ill_name, np->in_ifname, len))
np->in_ifp = il;
}
}
- mutex_exit(&ipf_nat);
+ RWLOCK_EXIT(&ipf_nat);
bcopy((caddr_t)qif->qf_rqinfo, (caddr_t)&qif->qf_rqinit,
sizeof(struct qinit));
@@ -946,7 +1141,7 @@ void solattach()
#endif
out->q_qinfo = &qif->qf_wqinit;
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
cmn_err(CE_CONT, "IP Filter: attach to [%s,%d]\n",
qif->qf_name, il->ill_ppa);
}
@@ -968,7 +1163,7 @@ int ipfsync()
register ill_t *il;
queue_t *in, *out;
- mutex_enter(&ipfs_mutex);
+ WRITE_ENTER(&ipfs_mutex);
for (qp = &qif_head; (qif = *qp); ) {
for (il = ill_g_head; il; il = il->ill_next)
if ((qif->qf_ill == il) &&
@@ -991,12 +1186,12 @@ int ipfsync()
/*
* Disable any rules directly associated with this interface
*/
- mutex_enter(&ipf_nat);
+ WRITE_ENTER(&ipf_nat);
for (np = nat_list; np; np = np->in_next)
if (np->in_ifp == (void *)qif->qf_ill)
np->in_ifp = (struct ifnet *)-1;
- mutex_exit(&ipf_nat);
- mutex_enter(&ipf_mutex);
+ RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&ipf_mutex);
for (f = ipfilter[0][fr_active]; f; f = f->fr_next)
if (f->fr_ifa == (void *)qif->qf_ill)
f->fr_ifa = (struct ifnet *)-1;
@@ -1004,39 +1199,42 @@ int ipfsync()
if (f->fr_ifa == (void *)qif->qf_ill)
f->fr_ifa = (struct ifnet *)-1;
+#if 0 /* XXX */
+ /*
+ * As well as the ill disappearing when a device is unplumb'd,
+ * it also appears that the associated queue structures also
+ * disappear - at least in the case of ppp, which is the most
+ * volatile here. Thanks to Greg for finding this problem.
+ */
/*
* Restore q_qinfo pointers in interface queues
*/
- il = qif->qf_ill;
- in = il->ill_rq;
- out = NULL;
- if (in && il->ill_wq) {
- out = il->ill_wq->q_next;
- }
+ out = qif->qf_out;
+ in = qif->qf_in;
if (in) {
-#ifdef IPFDEBUG
+# ifdef IPFDEBUG
cmn_err(CE_NOTE,
"IP Filter: ipfsync: in queue(%lx)->q_qinfo FROM %lx TO %lx",
in, in->q_qinfo, qif->qf_rqinfo
);
-#endif
+# endif
in->q_qinfo = qif->qf_rqinfo;
}
if (out) {
-#ifdef IPFDEBUG
+# ifdef IPFDEBUG
cmn_err(CE_NOTE,
"IP Filter: ipfsync: out queue(%lx)->q_qinfo FROM %lx TO %lx",
out, out->q_qinfo, qif->qf_wqinfo
);
-#endif
+# endif
out->q_qinfo = qif->qf_wqinfo;
}
- mutex_exit(&ipf_mutex);
-
+#endif /* XXX */
+ RWLOCK_EXIT(&ipf_mutex);
KFREE(qif);
qif = *qp;
}
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
solattach();
/*
@@ -1054,10 +1252,10 @@ int ipfsync()
int soldetach()
{
queue_t *in, *out;
- qif_t *qif, *qf2, **qp;
+ qif_t *qif, **qp;
ill_t *il;
- mutex_enter(&ipfs_mutex);
+ WRITE_ENTER(&ipfs_mutex);
/*
* Make two passes, first get rid of all the unknown devices, next
* unlink known devices.
@@ -1081,8 +1279,8 @@ int soldetach()
if (qif->qf_ill == il)
break;
if (il) {
- in = il->ill_rq;
- out = il->ill_wq->q_next;
+ in = qif->qf_in;
+ out = qif->qf_out;
cmn_err(CE_CONT, "IP Filter: detaching [%s,%d]\n",
qif->qf_name, il->ill_ppa);
@@ -1105,7 +1303,7 @@ int soldetach()
}
KFREE(qif);
}
- mutex_exit(&ipfs_mutex);
+ RWLOCK_EXIT(&ipfs_mutex);
return ipldetach();
}
@@ -1133,16 +1331,18 @@ mblk_t *mb, **mpp;
fr_info_t *fin;
frdest_t *fdp;
{
- mblk_t *mp = NULL;
+ ire_t *ir, *dir, *gw;
struct in_addr dst;
- ire_t *ir, *dir;
- int hlen = 0;
- u_char *s;
queue_t *q = NULL;
+ mblk_t *mp = NULL;
+ size_t hlen = 0;
+ frentry_t *fr;
+ void *ifp;
+ u_char *s;
#ifndef sparc
u_short __iplen, __ipoff;
-
+#endif
/*
* 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
@@ -1150,29 +1350,13 @@ frdest_t *fdp;
*/
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, qf->qf_len, (char *)ip);
- 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;
+ (*mpp)->b_prev = NULL;
freemsg(*mpp);
}
@@ -1184,8 +1368,10 @@ frdest_t *fdp;
dst = fin->fin_fi.fi_dst;
#if SOLARIS2 > 5
- dir = ire_route_lookup(dst.s_addr, 0, 0, 0, NULL, NULL, NULL,
- MATCH_IRE_DSTONLY);
+ gw = NULL;
+ dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, &gw, NULL,
+ MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|
+ MATCH_IRE_RECURSIVE);
#else
dir = ire_lookup(dst.s_addr);
#endif
@@ -1197,11 +1383,40 @@ frdest_t *fdp;
ir = dir;
if (ir && dir) {
+ ifp = ire_to_ill(ir);
+ fr = fin->fin_fr;
+ /*
+ * In case we're here due to "to <if>" being used with
+ * "keep state", check that we're going in the correct
+ * direction.
+ */
+ if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
+ (fin->fin_rev != 0) && (fdp == &fr->fr_tif))
+ return -1;
+
+ fin->fin_ifp == ifp;
+ if (fin->fin_out == 0) {
+ fin->fin_fr = ipacct[1][fr_active];
+ if ((fin->fin_fr != NULL) &&
+ (fr_scanlist(FR_NOMATCH, ip, fin, mb)&FR_ACCOUNT)){
+ ATOMIC_INC(frstats[1].fr_acct);
+ }
+ fin->fin_fr = NULL;
+ (void) fr_checkstate(ip, fin);
+ (void) ip_natout(ip, fin);
+ }
+#ifndef sparc
+ __iplen = (u_short)ip->ip_len,
+ __ipoff = (u_short)ip->ip_off;
+
+ ip->ip_len = htons(__iplen);
+ ip->ip_off = htons(__ipoff);
+#endif
+
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;
@@ -1222,30 +1437,37 @@ frdest_t *fdp;
else if (ir->ire_rfq)
q = WR(ir->ire_rfq);
if (q) {
+ mb->b_prev = NULL;
+ RWLOCK_EXIT(&ipfs_mutex);
+ RWLOCK_EXIT(&ipf_solaris);
putnext(q, mb);
+ READ_ENTER(&ipf_solaris);
+ READ_ENTER(&ipfs_mutex);
ipl_frouteok[0]++;
return 0;
}
}
bad_fastroute:
- ipl_frouteok[0]++;
+ mb->b_prev = NULL;
+ freemsg(mb);
+ ipl_frouteok[1]++;
return -1;
}
void copyout_mblk(m, off, len, buf)
mblk_t *m;
-int off, len;
+size_t off, len;
char *buf;
{
- char *s, *bp = buf;
- int mlen, olen, clen;
+ u_char *s, *bp = (u_char *)buf;
+ size_t 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;
+ mlen = m->b_wptr - s;
olen = MIN(off, mlen);
if ((olen == mlen) || (olen < off)) {
off -= olen;
@@ -1265,17 +1487,17 @@ char *buf;
void copyin_mblk(m, off, len, buf)
mblk_t *m;
-int off, len;
+size_t off, len;
char *buf;
{
- char *s, *bp = buf;
- int mlen, olen, clen;
+ u_char *s, *bp = (u_char *)buf;
+ size_t 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;
+ mlen = m->b_wptr - s;
olen = MIN(off, mlen);
if ((olen == mlen) || (olen < off)) {
off -= olen;