/*
* ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
*
- * Copyright (c) 1994 The Australian National University.
- * All rights reserved.
+ * Copyright (c) 1994 Paul Mackerras. All rights reserved.
*
- * Permission to use, copy, modify, and distribute this software and its
- * documentation is hereby granted, provided that the above copyright
- * notice appears in all copies. This software is provided without any
- * warranty, express or implied. The Australian National University
- * makes no representations about the suitability of this software for
- * any purpose.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
*
- * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
- * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
- * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
*
- * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
- * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
- * OR MODIFICATIONS.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
- * $Id: ppp.c,v 1.1 2000/04/18 23:51:28 masputra Exp $
+ * 3. The name(s) of the authors of this software must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Paul Mackerras
+ * <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
#include <netinet/in.h> /* leave this outside of PRIOQ for htons */
-#ifdef __STDC__
-#define __P(x) x
-#else
-#define __P(x) ()
-#endif
-
/*
* The IP module may use this SAP value for IP packets.
*/
static upperstr_t *ppas = NULL;
#ifdef SVR4
-static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
-static int pppclose __P((queue_t *, int, cred_t *));
+static int pppopen(queue_t *, dev_t *, int, int, cred_t *);
+static int pppclose(queue_t *, int, cred_t *);
#else
-static int pppopen __P((queue_t *, int, int, int));
-static int pppclose __P((queue_t *, int));
+static int pppopen(queue_t *, int, int, int);
+static int pppclose(queue_t *, int);
#endif /* SVR4 */
-static int pppurput __P((queue_t *, mblk_t *));
-static int pppuwput __P((queue_t *, mblk_t *));
-static int pppursrv __P((queue_t *));
-static int pppuwsrv __P((queue_t *));
-static int ppplrput __P((queue_t *, mblk_t *));
-static int ppplwput __P((queue_t *, mblk_t *));
-static int ppplrsrv __P((queue_t *));
-static int ppplwsrv __P((queue_t *));
+static int pppurput(queue_t *, mblk_t *);
+static int pppuwput(queue_t *, mblk_t *);
+static int pppursrv(queue_t *);
+static int pppuwsrv(queue_t *);
+static int ppplrput(queue_t *, mblk_t *);
+static int ppplwput(queue_t *, mblk_t *);
+static int ppplrsrv(queue_t *);
+static int ppplwsrv(queue_t *);
+#ifndef NO_DLPI
+static void dlpi_request(queue_t *, mblk_t *, upperstr_t *);
+static void dlpi_error(queue_t *, upperstr_t *, int, int, int);
+static void dlpi_ok(queue_t *, int);
+#endif
+static int send_data(mblk_t *, upperstr_t *);
+static void new_ppa(queue_t *, mblk_t *);
+static void attach_ppa(queue_t *, mblk_t *);
#ifndef NO_DLPI
-static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));
-static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int));
-static void dlpi_ok __P((queue_t *, int));
+static void detach_ppa(queue_t *, mblk_t *);
#endif
-static int send_data __P((mblk_t *, upperstr_t *));
-static void new_ppa __P((queue_t *, mblk_t *));
-static void attach_ppa __P((queue_t *, mblk_t *));
-static void detach_ppa __P((queue_t *, mblk_t *));
-static void detach_lower __P((queue_t *, mblk_t *));
-static void debug_dump __P((queue_t *, mblk_t *));
-static upperstr_t *find_dest __P((upperstr_t *, int));
+static void detach_lower(queue_t *, mblk_t *);
+static void debug_dump(queue_t *, mblk_t *);
+static upperstr_t *find_dest(upperstr_t *, int);
#if defined(SOL2)
-static upperstr_t *find_promisc __P((upperstr_t *, int));
-static mblk_t *prepend_ether __P((upperstr_t *, mblk_t *, int));
-static mblk_t *prepend_udind __P((upperstr_t *, mblk_t *, int));
-static void promisc_sendup __P((upperstr_t *, mblk_t *, int, int));
+static upperstr_t *find_promisc(upperstr_t *, int);
+static mblk_t *prepend_ether(upperstr_t *, mblk_t *, int);
+static mblk_t *prepend_udind(upperstr_t *, mblk_t *, int);
+static void promisc_sendup(upperstr_t *, mblk_t *, int, int);
#endif /* defined(SOL2) */
-static int putctl2 __P((queue_t *, int, int, int));
-static int putctl4 __P((queue_t *, int, int, int));
-static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+static int putctl2(queue_t *, int, int, int);
+static int putctl4(queue_t *, int, int, int);
+static int pass_packet(upperstr_t *ppa, mblk_t *mp, int outbound);
#ifdef FILTER_PACKETS
-static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+static int ip_hard_filter(upperstr_t *ppa, mblk_t *mp, int outbound);
#endif /* FILTER_PACKETS */
#define PPP_ID 0xb1a6
break;
}
#ifdef NO_DLPI
+ /* pass_packet frees the packet on returning 0 */
if ((us->flags & US_CONTROL) == 0 && !pass_packet(us, mp, 1))
break;
#endif
- if (!send_data(mp, us))
- putq(q, mp);
+ if (!send_data(mp, us) && !putq(q, mp))
+ freemsg(mp);
break;
case M_IOCTL:
#endif
iop->ioc_count = 0;
qwriter(q, mp, detach_lower, PERIM_OUTER);
+ /* mp is now gone */
error = -1;
break;
iop->ioc_count = sizeof(int);
mq->b_wptr = mq->b_rptr + sizeof(int);
qwriter(q, mp, new_ppa, PERIM_OUTER);
+ /* mp is now gone */
error = -1;
break;
us->ppa = ppa;
iop->ioc_count = 0;
qwriter(q, mp, attach_ppa, PERIM_OUTER);
+ /* mp is now gone */
error = -1;
break;
}
n = *(int *)mp->b_cont->b_rptr;
if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
- qwriter(q, NULL, debug_dump, PERIM_OUTER);
- iop->ioc_count = 0;
+ qwriter(q, mp, debug_dump, PERIM_OUTER);
+ /* mp is now gone */
error = -1;
} else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
DPRINT1("ppp/%d: debug log enabled\n", us->mn);
if (us->ppa == 0 || us->ppa->lowerq == 0)
break;
putnext(us->ppa->lowerq, mp);
+ /* mp is now gone */
error = -1;
}
break;
((union DL_primitives *)mq->b_rptr)->dl_primitive = DL_INFO_REQ;
mq->b_wptr = mq->b_rptr + sizeof(dl_info_req_t);
dlpi_request(q, mq, us);
- error = 0;
+ /* mp is now gone */
+ error = -1;
break;
case SIOCGIFNETMASK:
mp->b_rptr[1] = PPP_UI;
mp->b_rptr[2] = us->sap >> 8;
mp->b_rptr[3] = us->sap;
+ /* pass_packet frees the packet on returning 0 */
if (pass_packet(us, mp, 1)) {
- if (!send_data(mp, us))
- putq(q, mp);
+ if (!send_data(mp, us) && !putq(q, mp))
+ freemsg(mp);
}
return;
#endif
default:
- cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
+ if (us->flags & US_DBGLOG)
+ DPRINT1("ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
/* fall through */
badprim:
dlpi_error(q, us, d->dl_primitive, DL_BADPRIM, 0);
}
#endif /* NO_DLPI */
+/*
+ * If return value is 0, then the packet has already been freed.
+ */
static int
pass_packet(us, mp, outbound)
upperstr_t *us;
#ifndef NO_DLPI
dlpi_ok(q, DL_ATTACH_REQ);
#endif
+ freemsg(mp);
}
}
+#ifndef NO_DLPI
static void
detach_ppa(q, mp)
queue_t *q;
}
us->next = 0;
us->ppa = 0;
-#ifndef NO_DLPI
us->state = DL_UNATTACHED;
dlpi_ok(q, DL_DETACH_REQ);
-#endif
+ freemsg(mp);
}
+#endif
/*
* We call this with qwriter in order to give the upper queue procedures
putnext(ppa->q, mp);
break;
- default:
- if (mp->b_datap->db_type == M_DATA) {
- len = msgdsize(mp);
- if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
- PULLUP(mp, PPP_HDRLEN);
- if (mp == 0) {
- DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len);
- break;
- }
+ case M_DATA:
+ len = msgdsize(mp);
+ if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
+ PULLUP(mp, PPP_HDRLEN);
+ if (mp == 0) {
+ DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len);
+ break;
}
- MT_ENTER(&ppa->stats_lock);
- ppa->stats.ppp_ipackets++;
- ppa->stats.ppp_ibytes += len;
+ }
+ MT_ENTER(&ppa->stats_lock);
+ ppa->stats.ppp_ipackets++;
+ ppa->stats.ppp_ibytes += len;
#ifdef INCR_IPACKETS
- INCR_IPACKETS(ppa);
+ INCR_IPACKETS(ppa);
#endif
- MT_EXIT(&ppa->stats_lock);
+ MT_EXIT(&ppa->stats_lock);
- proto = PPP_PROTOCOL(mp->b_rptr);
+ proto = PPP_PROTOCOL(mp->b_rptr);
#if defined(SOL2)
- /*
- * Should there be any promiscuous stream(s), send the data
- * up for each promiscuous stream that we recognize.
- */
- promisc_sendup(ppa, mp, proto, 1);
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ promisc_sendup(ppa, mp, proto, 1);
#endif /* defined(SOL2) */
- if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
- /*
- * A data packet for some network protocol.
- * Queue it on the upper stream for that protocol.
- * XXX could we just putnext it? (would require thought)
- * The rblocked flag is there to ensure that we keep
- * messages in order for each network protocol.
- */
- if (!pass_packet(us, mp, 0))
- break;
- if (!us->rblocked && !canput(us->q))
- us->rblocked = 1;
- if (!us->rblocked)
- putq(us->q, mp);
- else
- putq(q, mp);
+ if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
+ /*
+ * A data packet for some network protocol.
+ * Queue it on the upper stream for that protocol.
+ * XXX could we just putnext it? (would require thought)
+ * The rblocked flag is there to ensure that we keep
+ * messages in order for each network protocol.
+ */
+ /* pass_packet frees the packet on returning 0 */
+ if (!pass_packet(us, mp, 0))
break;
- }
+ if (!us->rblocked && !canput(us->q))
+ us->rblocked = 1;
+ if (!putq(us->rblocked ? q : us->q, mp))
+ freemsg(mp);
+ break;
}
+
+ /* FALLTHROUGH */
+
+ default:
/*
* A control frame, a frame for an unknown protocol,
* or some other message type.
*/
if (queclass(mp) == QPCTL || canputnext(ppa->q))
putnext(ppa->q, mp);
- else
- putq(q, mp);
+ else if (!putq(q, mp))
+ freemsg(mp);
break;
}
if (proto < 0x8000 && (as = find_dest(us, proto)) != 0) {
if (!canput(as->q))
break;
- putq(as->q, mp);
+ if (!putq(as->q, mp))
+ freemsg(mp);
} else {
if (!canputnext(q))
break;
if (canputnext(prus->q)) {
if (prus->flags & US_RAWDATA) {
dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
- putnext(prus->q, dup_dup_mp);
} else {
dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
- putnext(prus->q, dup_dup_mp);
}
+ if (dup_dup_mp == 0)
+ continue;
+ putnext(prus->q, dup_dup_mp);
} else {
DPRINT("ppp_urput: data to promisc q dropped\n");
freemsg(dup_dup_mp);
if (canputnext(prus->q)) {
if (prus->flags & US_RAWDATA) {
dup_mp = prepend_ether(prus, dup_mp, proto);
- putnext(prus->q, dup_mp);
} else {
dup_mp = prepend_udind(prus, dup_mp, proto);
- putnext(prus->q, dup_mp);
}
+ if (dup_mp != 0)
+ putnext(prus->q, dup_mp);
} else {
DPRINT("ppp_urput: data to promisc q dropped\n");
freemsg(dup_mp);
* rather than blocking, to avoid the possibility of deadlock.
*/
if (!TRYLOCK_LOWER_R) {
- putq(q, mp);
+ if (!putq(q, mp))
+ freemsg(mp);
return 0;
}
*/
if (queclass(mp) == QPCTL || (qsize(q) == 0 && canput(uq)))
put(uq, mp);
- else
- putq(q, mp);
+ else if (!putq(q, mp))
+ freemsg(mp);
UNLOCK_LOWER;
return 0;
};
+/*
+ * Packet has already been freed if return value is 0.
+ */
static int
ip_hard_filter(us, mp, outbound)
upperstr_t *us;
us->mn, pft->proto, pft->port);
/* Discard if not connected, or if not pass_with_link_up */
/* else, if link is up let go by, but don't update time */
- return pft->ok_if_link_up? -1: 0;
+ if (pft->ok_if_link_up)
+ return -1;
+ freemsg(mp);
+ return 0;
}
break;
} /* end switch (proto) */