xref: /onnv-gate/usr/src/uts/common/io/ppp/sppp/sppp.c (revision 9751:8e29565352fc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * sppp.c - Solaris STREAMS PPP multiplexing pseudo-driver
30Sstevel@tonic-gate  *
4*9751Sjames.d.carlson@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
50Sstevel@tonic-gate  * Use is subject to license terms.
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
80Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
90Sstevel@tonic-gate  * notice appears in all copies.
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
120Sstevel@tonic-gate  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
130Sstevel@tonic-gate  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
140Sstevel@tonic-gate  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
150Sstevel@tonic-gate  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
160Sstevel@tonic-gate  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
190Sstevel@tonic-gate  * All rights reserved.
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
220Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
230Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
240Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
250Sstevel@tonic-gate  * makes no representations about the suitability of this software for
260Sstevel@tonic-gate  * any purpose.
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
290Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
300Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
310Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
320Sstevel@tonic-gate  * OF SUCH DAMAGE.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
350Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
360Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
370Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
380Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
390Sstevel@tonic-gate  * OR MODIFICATIONS.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * This driver is derived from the original SVR4 STREAMS PPP driver
420Sstevel@tonic-gate  * originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * Adi Masputra <adi.masputra@sun.com> rewrote and restructured the code
450Sstevel@tonic-gate  * for improved performance and scalability.
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	RCSID	"$Id: sppp.c,v 1.0 2000/05/08 01:10:12 masputra Exp $"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <sys/types.h>
510Sstevel@tonic-gate #include <sys/debug.h>
520Sstevel@tonic-gate #include <sys/param.h>
530Sstevel@tonic-gate #include <sys/stat.h>
540Sstevel@tonic-gate #include <sys/stream.h>
550Sstevel@tonic-gate #include <sys/stropts.h>
560Sstevel@tonic-gate #include <sys/sysmacros.h>
570Sstevel@tonic-gate #include <sys/errno.h>
580Sstevel@tonic-gate #include <sys/time.h>
590Sstevel@tonic-gate #include <sys/cmn_err.h>
600Sstevel@tonic-gate #include <sys/kmem.h>
610Sstevel@tonic-gate #include <sys/conf.h>
620Sstevel@tonic-gate #include <sys/dlpi.h>
630Sstevel@tonic-gate #include <sys/ddi.h>
640Sstevel@tonic-gate #include <sys/kstat.h>
650Sstevel@tonic-gate #include <sys/strsun.h>
660Sstevel@tonic-gate #include <sys/ethernet.h>
670Sstevel@tonic-gate #include <sys/policy.h>
68*9751Sjames.d.carlson@sun.com #include <sys/zone.h>
690Sstevel@tonic-gate #include <net/ppp_defs.h>
700Sstevel@tonic-gate #include <net/pppio.h>
710Sstevel@tonic-gate #include "sppp.h"
720Sstevel@tonic-gate #include "s_common.h"
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * This is used to tag official Solaris sources.  Please do not define
760Sstevel@tonic-gate  * "INTERNAL_BUILD" when building this software outside of Sun Microsystems.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate #ifdef INTERNAL_BUILD
790Sstevel@tonic-gate /* MODINFO is limited to 32 characters. */
805640Scarlsonj const char sppp_module_description[] = "PPP 4.0 mux";
810Sstevel@tonic-gate #else /* INTERNAL_BUILD */
827656SSherry.Moore@Sun.COM const char sppp_module_description[] = "ANU PPP mux";
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /* LINTED */
850Sstevel@tonic-gate static const char buildtime[] = "Built " __DATE__ " at " __TIME__
860Sstevel@tonic-gate #ifdef DEBUG
870Sstevel@tonic-gate " DEBUG"
880Sstevel@tonic-gate #endif
890Sstevel@tonic-gate "\n";
900Sstevel@tonic-gate #endif /* INTERNAL_BUILD */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static void	sppp_inner_ioctl(queue_t *, mblk_t *);
930Sstevel@tonic-gate static void	sppp_outer_ioctl(queue_t *, mblk_t *);
940Sstevel@tonic-gate static queue_t	*sppp_send(queue_t *, mblk_t **, spppstr_t *);
950Sstevel@tonic-gate static queue_t	*sppp_recv(queue_t *, mblk_t **, spppstr_t *);
960Sstevel@tonic-gate static void	sppp_recv_nondata(queue_t *, mblk_t *, spppstr_t *);
970Sstevel@tonic-gate static queue_t	*sppp_outpkt(queue_t *, mblk_t **, int, spppstr_t *);
980Sstevel@tonic-gate static spppstr_t *sppp_inpkt(queue_t *, mblk_t *, spppstr_t *);
990Sstevel@tonic-gate static int	sppp_kstat_update(kstat_t *, int);
1000Sstevel@tonic-gate static void 	sppp_release_pkts(sppa_t *, uint16_t);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * sps_list contains the list of active per-stream instance state structures
1040Sstevel@tonic-gate  * ordered on the minor device number (see sppp.h for details). All streams
1050Sstevel@tonic-gate  * opened to this driver are threaded together in this list.
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate static spppstr_t *sps_list = NULL;
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * ppa_list contains the list of active per-attachment instance state
1100Sstevel@tonic-gate  * structures ordered on the ppa id number (see sppp.h for details). All of
1110Sstevel@tonic-gate  * the ppa structures created once per PPPIO_NEWPPA ioctl are threaded together
1120Sstevel@tonic-gate  * in this list. There is exactly one ppa structure for a given PPP interface,
1130Sstevel@tonic-gate  * and multiple sps streams (upper streams) may share a ppa by performing
1140Sstevel@tonic-gate  * an attachment explicitly (PPPIO_ATTACH) or implicitly (DL_ATTACH_REQ).
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate static sppa_t *ppa_list = NULL;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate static const char *kstats_names[] = { SPPP_KSTATS_NAMES };
1190Sstevel@tonic-gate static const char *kstats64_names[] = { SPPP_KSTATS64_NAMES };
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * map proto (which is an IANA defined ppp network protocol) to
1230Sstevel@tonic-gate  * a bit position indicated by NP_* in ppa_npflag
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate static uint32_t
sppp_ppp2np(uint16_t proto)1260Sstevel@tonic-gate sppp_ppp2np(uint16_t proto)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate 	switch (proto) {
1290Sstevel@tonic-gate 	case PPP_IP:
1300Sstevel@tonic-gate 		return (NP_IP);
1310Sstevel@tonic-gate 	case PPP_IPV6:
1320Sstevel@tonic-gate 		return (NP_IPV6);
1330Sstevel@tonic-gate 	default:
1340Sstevel@tonic-gate 		return (0);
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * sppp_open()
1400Sstevel@tonic-gate  *
1410Sstevel@tonic-gate  * MT-Perimeters:
1420Sstevel@tonic-gate  *    exclusive inner, exclusive outer.
1430Sstevel@tonic-gate  *
1440Sstevel@tonic-gate  * Description:
1450Sstevel@tonic-gate  *    Common open procedure for module.
1460Sstevel@tonic-gate  */
1470Sstevel@tonic-gate /* ARGSUSED */
1480Sstevel@tonic-gate int
sppp_open(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)1490Sstevel@tonic-gate sppp_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	spppstr_t	*sps;
1520Sstevel@tonic-gate 	spppstr_t	**nextmn;
1530Sstevel@tonic-gate 	minor_t		mn;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	ASSERT(q != NULL && devp != NULL);
1560Sstevel@tonic-gate 	ASSERT(sflag != MODOPEN);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	if (q->q_ptr != NULL) {
1590Sstevel@tonic-gate 		return (0);		/* already open */
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 	if (sflag != CLONEOPEN) {
1620Sstevel@tonic-gate 		return (OPENFAIL);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 	/*
1650Sstevel@tonic-gate 	 * The sps list is sorted using the minor number as the key. The
1660Sstevel@tonic-gate 	 * following code walks the list to find the lowest valued minor
1670Sstevel@tonic-gate 	 * number available to be used.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	mn = 0;
1700Sstevel@tonic-gate 	for (nextmn = &sps_list; (sps = *nextmn) != NULL;
1710Sstevel@tonic-gate 	    nextmn = &sps->sps_nextmn) {
1720Sstevel@tonic-gate 		if (sps->sps_mn_id != mn) {
1730Sstevel@tonic-gate 			break;
1740Sstevel@tonic-gate 		}
1750Sstevel@tonic-gate 		++mn;
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 	sps = (spppstr_t *)kmem_zalloc(sizeof (spppstr_t), KM_SLEEP);
1780Sstevel@tonic-gate 	ASSERT(sps != NULL);		/* KM_SLEEP must never return NULL */
1790Sstevel@tonic-gate 	sps->sps_nextmn = *nextmn;	/* insert stream in global list */
1800Sstevel@tonic-gate 	*nextmn = sps;
1810Sstevel@tonic-gate 	sps->sps_mn_id = mn;		/* save minor id for this stream */
1820Sstevel@tonic-gate 	sps->sps_rq = q;		/* save read queue pointer */
1830Sstevel@tonic-gate 	sps->sps_sap = -1;		/* no sap bound to stream */
1840Sstevel@tonic-gate 	sps->sps_dlstate = DL_UNATTACHED; /* dlpi state is unattached */
1850Sstevel@tonic-gate 	sps->sps_npmode = NPMODE_DROP;	/* drop all packets initially */
186*9751Sjames.d.carlson@sun.com 	sps->sps_zoneid = crgetzoneid(credp);
1870Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = (caddr_t)sps;
1880Sstevel@tonic-gate 	/*
1890Sstevel@tonic-gate 	 * We explicitly disable the automatic queue scheduling for the
1900Sstevel@tonic-gate 	 * write-side to obtain complete control over queuing during transmit.
1910Sstevel@tonic-gate 	 * Packets will be queued at the upper write queue and the service
1920Sstevel@tonic-gate 	 * routine will not be called until it gets scheduled by having the
1930Sstevel@tonic-gate 	 * lower write service routine call the qenable(WR(uq)) for all streams
1940Sstevel@tonic-gate 	 * attached to the same ppa instance.
1950Sstevel@tonic-gate 	 */
1960Sstevel@tonic-gate 	noenable(WR(q));
1970Sstevel@tonic-gate 	*devp = makedevice(getmajor(*devp), mn);
1980Sstevel@tonic-gate 	qprocson(q);
1990Sstevel@tonic-gate 	return (0);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * Free storage used by a PPA.  This is not called until the last PPA
2040Sstevel@tonic-gate  * user closes his connection or reattaches to a different PPA.
2050Sstevel@tonic-gate  */
2060Sstevel@tonic-gate static void
sppp_free_ppa(sppa_t * ppa)2070Sstevel@tonic-gate sppp_free_ppa(sppa_t *ppa)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	sppa_t **nextppa;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	ASSERT(ppa->ppa_refcnt == 1);
2120Sstevel@tonic-gate 	if (ppa->ppa_kstats != NULL) {
2130Sstevel@tonic-gate 		kstat_delete(ppa->ppa_kstats);
2140Sstevel@tonic-gate 		ppa->ppa_kstats = NULL;
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 	mutex_destroy(&ppa->ppa_sta_lock);
2170Sstevel@tonic-gate 	mutex_destroy(&ppa->ppa_npmutex);
2180Sstevel@tonic-gate 	rw_destroy(&ppa->ppa_sib_lock);
2190Sstevel@tonic-gate 	nextppa = &ppa_list;
2200Sstevel@tonic-gate 	while (*nextppa != NULL) {
2210Sstevel@tonic-gate 		if (*nextppa == ppa) {
2220Sstevel@tonic-gate 			*nextppa = ppa->ppa_nextppa;
2230Sstevel@tonic-gate 			break;
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 		nextppa = &(*nextppa)->ppa_nextppa;
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 	kmem_free(ppa, sizeof (*ppa));
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate  * Create a new PPA.  Caller must be exclusive on outer perimeter.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate sppa_t *
sppp_create_ppa(uint32_t ppa_id,zoneid_t zoneid)234*9751Sjames.d.carlson@sun.com sppp_create_ppa(uint32_t ppa_id, zoneid_t zoneid)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	sppa_t *ppa;
2370Sstevel@tonic-gate 	sppa_t *curppa;
2380Sstevel@tonic-gate 	sppa_t **availppa;
2390Sstevel@tonic-gate 	char unit[32];		/* Unit name */
2400Sstevel@tonic-gate 	const char **cpp;
2410Sstevel@tonic-gate 	kstat_t *ksp;
2420Sstevel@tonic-gate 	kstat_named_t *knt;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	/*
2450Sstevel@tonic-gate 	 * NOTE: unit *must* be named for the driver
2460Sstevel@tonic-gate 	 * name plus the ppa number so that netstat
2470Sstevel@tonic-gate 	 * can find the statistics.
2480Sstevel@tonic-gate 	 */
2495640Scarlsonj 	(void) sprintf(unit, "%s" "%d", PPP_DRV_NAME, ppa_id);
2500Sstevel@tonic-gate 	/*
2510Sstevel@tonic-gate 	 * Make sure we can allocate a buffer to
2520Sstevel@tonic-gate 	 * contain the ppa to be sent upstream, as
2530Sstevel@tonic-gate 	 * well as the actual ppa structure and its
2540Sstevel@tonic-gate 	 * associated kstat structure.
2550Sstevel@tonic-gate 	 */
2560Sstevel@tonic-gate 	ppa = (sppa_t *)kmem_zalloc(sizeof (sppa_t),
2570Sstevel@tonic-gate 	    KM_NOSLEEP);
2580Sstevel@tonic-gate 	ksp = kstat_create(PPP_DRV_NAME, ppa_id, unit, "net", KSTAT_TYPE_NAMED,
2590Sstevel@tonic-gate 	    sizeof (sppp_kstats_t) / sizeof (kstat_named_t), 0);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if (ppa == NULL || ksp == NULL) {
2620Sstevel@tonic-gate 		if (ppa != NULL) {
2630Sstevel@tonic-gate 			kmem_free(ppa, sizeof (sppa_t));
2640Sstevel@tonic-gate 		}
2650Sstevel@tonic-gate 		if (ksp != NULL) {
2660Sstevel@tonic-gate 			kstat_delete(ksp);
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate 		return (NULL);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 	ppa->ppa_kstats = ksp;		/* chain kstat structure */
2710Sstevel@tonic-gate 	ppa->ppa_ppa_id = ppa_id;	/* record ppa id */
272*9751Sjames.d.carlson@sun.com 	ppa->ppa_zoneid = zoneid;	/* zone that owns this PPA */
2730Sstevel@tonic-gate 	ppa->ppa_mtu = PPP_MAXMTU;	/* 65535-(PPP_HDRLEN+PPP_FCSLEN) */
2740Sstevel@tonic-gate 	ppa->ppa_mru = PPP_MAXMRU;	/* 65000 */
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	mutex_init(&ppa->ppa_sta_lock, NULL, MUTEX_DRIVER, NULL);
2770Sstevel@tonic-gate 	mutex_init(&ppa->ppa_npmutex, NULL, MUTEX_DRIVER, NULL);
2780Sstevel@tonic-gate 	rw_init(&ppa->ppa_sib_lock, NULL, RW_DRIVER, NULL);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * Prepare and install kstat counters.  Note that for netstat
2820Sstevel@tonic-gate 	 * -i to work, there needs to be "ipackets", "opackets",
2830Sstevel@tonic-gate 	 * "ierrors", and "oerrors" kstat named variables.
2840Sstevel@tonic-gate 	 */
2850Sstevel@tonic-gate 	knt = (kstat_named_t *)ksp->ks_data;
2860Sstevel@tonic-gate 	for (cpp = kstats_names; cpp < kstats_names + Dim(kstats_names);
2870Sstevel@tonic-gate 	    cpp++) {
2882951Selowe 		kstat_named_init(knt, *cpp, KSTAT_DATA_UINT32);
2890Sstevel@tonic-gate 		knt++;
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 	for (cpp = kstats64_names; cpp < kstats64_names + Dim(kstats64_names);
2920Sstevel@tonic-gate 	    cpp++) {
2932951Selowe 		kstat_named_init(knt, *cpp, KSTAT_DATA_UINT64);
2940Sstevel@tonic-gate 		knt++;
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 	ksp->ks_update = sppp_kstat_update;
2970Sstevel@tonic-gate 	ksp->ks_private = (void *)ppa;
2980Sstevel@tonic-gate 	kstat_install(ksp);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	/* link to the next ppa and insert into global list */
3010Sstevel@tonic-gate 	availppa = &ppa_list;
3020Sstevel@tonic-gate 	while ((curppa = *availppa) != NULL) {
3030Sstevel@tonic-gate 		if (ppa_id < curppa->ppa_ppa_id)
3040Sstevel@tonic-gate 			break;
3050Sstevel@tonic-gate 		availppa = &curppa->ppa_nextppa;
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 	ppa->ppa_nextppa = *availppa;
3080Sstevel@tonic-gate 	*availppa = ppa;
3090Sstevel@tonic-gate 	return (ppa);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate /*
3130Sstevel@tonic-gate  * sppp_close()
3140Sstevel@tonic-gate  *
3150Sstevel@tonic-gate  * MT-Perimeters:
3160Sstevel@tonic-gate  *    exclusive inner, exclusive outer.
3170Sstevel@tonic-gate  *
3180Sstevel@tonic-gate  * Description:
3190Sstevel@tonic-gate  *    Common close procedure for module.
3200Sstevel@tonic-gate  */
3210Sstevel@tonic-gate int
sppp_close(queue_t * q)3220Sstevel@tonic-gate sppp_close(queue_t *q)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	spppstr_t	*sps;
3250Sstevel@tonic-gate 	spppstr_t	**nextmn;
3260Sstevel@tonic-gate 	spppstr_t	*sib;
3270Sstevel@tonic-gate 	sppa_t		*ppa;
3280Sstevel@tonic-gate 	mblk_t		*mp;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
3310Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
3320Sstevel@tonic-gate 	qprocsoff(q);
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	ppa = sps->sps_ppa;
3350Sstevel@tonic-gate 	if (ppa == NULL) {
3360Sstevel@tonic-gate 		ASSERT(!IS_SPS_CONTROL(sps));
3370Sstevel@tonic-gate 		goto close_unattached;
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 	if (IS_SPS_CONTROL(sps)) {
3400Sstevel@tonic-gate 		uint32_t	cnt = 0;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		ASSERT(ppa != NULL);
3430Sstevel@tonic-gate 		ASSERT(ppa->ppa_ctl == sps);
3440Sstevel@tonic-gate 		ppa->ppa_ctl = NULL;
3450Sstevel@tonic-gate 		/*
3460Sstevel@tonic-gate 		 * STREAMS framework always issues I_UNLINK prior to close,
3470Sstevel@tonic-gate 		 * since we only allow I_LINK under the control stream.
3480Sstevel@tonic-gate 		 * A given ppa structure has at most one lower stream pointed
3490Sstevel@tonic-gate 		 * by the ppa_lower_wq field, because we only allow a single
3500Sstevel@tonic-gate 		 * linkage (I_LINK) to be done on the control stream.
3510Sstevel@tonic-gate 		 */
3520Sstevel@tonic-gate 		ASSERT(ppa->ppa_lower_wq == NULL);
3530Sstevel@tonic-gate 		/*
3540Sstevel@tonic-gate 		 * Walk through all of sibling streams attached to this ppa,
3550Sstevel@tonic-gate 		 * and remove all references to this ppa. We have exclusive
3560Sstevel@tonic-gate 		 * access for the entire driver here, so there's no need
3570Sstevel@tonic-gate 		 * to hold ppa_sib_lock.
3580Sstevel@tonic-gate 		 */
3590Sstevel@tonic-gate 		cnt++;
3600Sstevel@tonic-gate 		sib = ppa->ppa_streams;
3610Sstevel@tonic-gate 		while (sib != NULL) {
3620Sstevel@tonic-gate 			ASSERT(ppa == sib->sps_ppa);
3630Sstevel@tonic-gate 			sib->sps_npmode = NPMODE_DROP;
3640Sstevel@tonic-gate 			sib->sps_flags &= ~(SPS_PIOATTACH | SPS_CACHED);
3650Sstevel@tonic-gate 			/*
3660Sstevel@tonic-gate 			 * There should be a preallocated hangup
3670Sstevel@tonic-gate 			 * message here.  Fetch it and send it up to
3680Sstevel@tonic-gate 			 * the stream head.  This will cause IP to
3690Sstevel@tonic-gate 			 * mark the interface as "down."
3700Sstevel@tonic-gate 			 */
3710Sstevel@tonic-gate 			if ((mp = sib->sps_hangup) != NULL) {
3720Sstevel@tonic-gate 				sib->sps_hangup = NULL;
3730Sstevel@tonic-gate 				/*
3740Sstevel@tonic-gate 				 * M_HANGUP works with IP, but snoop
3750Sstevel@tonic-gate 				 * is lame and requires M_ERROR.  Send
3760Sstevel@tonic-gate 				 * up a clean error code instead.
3770Sstevel@tonic-gate 				 *
3780Sstevel@tonic-gate 				 * XXX if snoop is fixed, fix this, too.
3790Sstevel@tonic-gate 				 */
3800Sstevel@tonic-gate 				MTYPE(mp) = M_ERROR;
3810Sstevel@tonic-gate 				*mp->b_wptr++ = ENXIO;
3820Sstevel@tonic-gate 				putnext(sib->sps_rq, mp);
3830Sstevel@tonic-gate 			}
3840Sstevel@tonic-gate 			qenable(WR(sib->sps_rq));
3850Sstevel@tonic-gate 			cnt++;
3860Sstevel@tonic-gate 			sib = sib->sps_nextsib;
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 		ASSERT(ppa->ppa_refcnt == cnt);
3890Sstevel@tonic-gate 	} else {
3900Sstevel@tonic-gate 		ASSERT(ppa->ppa_streams != NULL);
3910Sstevel@tonic-gate 		ASSERT(ppa->ppa_ctl != sps);
3920Sstevel@tonic-gate 		mp = NULL;
3930Sstevel@tonic-gate 		if (sps->sps_sap == PPP_IP) {
3940Sstevel@tonic-gate 			ppa->ppa_ip_cache = NULL;
3950Sstevel@tonic-gate 			mp = create_lsmsg(PPP_LINKSTAT_IPV4_UNBOUND);
3960Sstevel@tonic-gate 		} else if (sps->sps_sap == PPP_IPV6) {
3970Sstevel@tonic-gate 			ppa->ppa_ip6_cache = NULL;
3980Sstevel@tonic-gate 			mp = create_lsmsg(PPP_LINKSTAT_IPV6_UNBOUND);
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 		/* Tell the daemon the bad news. */
4010Sstevel@tonic-gate 		if (mp != NULL && ppa->ppa_ctl != NULL &&
4020Sstevel@tonic-gate 		    (sps->sps_npmode == NPMODE_PASS ||
4030Sstevel@tonic-gate 		    sps->sps_npmode == NPMODE_QUEUE)) {
4040Sstevel@tonic-gate 			putnext(ppa->ppa_ctl->sps_rq, mp);
4050Sstevel@tonic-gate 		} else {
4060Sstevel@tonic-gate 			freemsg(mp);
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 		/*
4090Sstevel@tonic-gate 		 * Walk through all of sibling streams attached to the
4100Sstevel@tonic-gate 		 * same ppa, and remove this stream from the sibling
4110Sstevel@tonic-gate 		 * streams list. We have exclusive access for the
4120Sstevel@tonic-gate 		 * entire driver here, so there's no need to hold
4130Sstevel@tonic-gate 		 * ppa_sib_lock.
4140Sstevel@tonic-gate 		 */
4150Sstevel@tonic-gate 		sib = ppa->ppa_streams;
4160Sstevel@tonic-gate 		if (sib == sps) {
4170Sstevel@tonic-gate 			ppa->ppa_streams = sps->sps_nextsib;
4180Sstevel@tonic-gate 		} else {
4190Sstevel@tonic-gate 			while (sib->sps_nextsib != NULL) {
4200Sstevel@tonic-gate 				if (sib->sps_nextsib == sps) {
4210Sstevel@tonic-gate 					sib->sps_nextsib = sps->sps_nextsib;
4220Sstevel@tonic-gate 					break;
4230Sstevel@tonic-gate 				}
4240Sstevel@tonic-gate 				sib = sib->sps_nextsib;
4250Sstevel@tonic-gate 			}
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 		sps->sps_nextsib = NULL;
4280Sstevel@tonic-gate 		freemsg(sps->sps_hangup);
4290Sstevel@tonic-gate 		sps->sps_hangup = NULL;
4300Sstevel@tonic-gate 		/*
4310Sstevel@tonic-gate 		 * Check if this is a promiscous stream. If the SPS_PROMISC bit
4320Sstevel@tonic-gate 		 * is still set, it means that the stream is closed without
4330Sstevel@tonic-gate 		 * ever having issued DL_DETACH_REQ or DL_PROMISCOFF_REQ.
4340Sstevel@tonic-gate 		 * In this case, we simply decrement the promiscous counter,
4350Sstevel@tonic-gate 		 * and it's safe to do it without holding ppa_sib_lock since
4360Sstevel@tonic-gate 		 * we're exclusive (inner and outer) at this point.
4370Sstevel@tonic-gate 		 */
4380Sstevel@tonic-gate 		if (IS_SPS_PROMISC(sps)) {
4390Sstevel@tonic-gate 			ASSERT(ppa->ppa_promicnt > 0);
4400Sstevel@tonic-gate 			ppa->ppa_promicnt--;
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 	/* If we're the only one left, then delete now. */
4440Sstevel@tonic-gate 	if (ppa->ppa_refcnt <= 1)
4450Sstevel@tonic-gate 		sppp_free_ppa(ppa);
4460Sstevel@tonic-gate 	else
4470Sstevel@tonic-gate 		ppa->ppa_refcnt--;
4480Sstevel@tonic-gate close_unattached:
4490Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
4500Sstevel@tonic-gate 	for (nextmn = &sps_list; *nextmn != NULL;
4510Sstevel@tonic-gate 	    nextmn = &(*nextmn)->sps_nextmn) {
4520Sstevel@tonic-gate 		if (*nextmn == sps) {
4530Sstevel@tonic-gate 			*nextmn = sps->sps_nextmn;
4540Sstevel@tonic-gate 			break;
4550Sstevel@tonic-gate 		}
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 	kmem_free(sps, sizeof (spppstr_t));
4580Sstevel@tonic-gate 	return (0);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate static void
sppp_ioctl(struct queue * q,mblk_t * mp)4620Sstevel@tonic-gate sppp_ioctl(struct queue *q, mblk_t *mp)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	spppstr_t	*sps;
4650Sstevel@tonic-gate 	spppstr_t	*nextsib;
4660Sstevel@tonic-gate 	sppa_t		*ppa;
4670Sstevel@tonic-gate 	struct iocblk	*iop;
4680Sstevel@tonic-gate 	mblk_t		*nmp;
4690Sstevel@tonic-gate 	enum NPmode	npmode;
4700Sstevel@tonic-gate 	struct ppp_idle	*pip;
4710Sstevel@tonic-gate 	struct ppp_stats64 *psp;
4720Sstevel@tonic-gate 	struct ppp_comp_stats *pcsp;
4730Sstevel@tonic-gate 	hrtime_t	hrtime;
4740Sstevel@tonic-gate 	int		sap;
4750Sstevel@tonic-gate 	int		count = 0;
4760Sstevel@tonic-gate 	int		error = EINVAL;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
4790Sstevel@tonic-gate 	ppa = sps->sps_ppa;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	iop = (struct iocblk *)mp->b_rptr;
4820Sstevel@tonic-gate 	switch (iop->ioc_cmd) {
4830Sstevel@tonic-gate 	case PPPIO_NPMODE:
4840Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps)) {
4850Sstevel@tonic-gate 			break;		/* return EINVAL */
4860Sstevel@tonic-gate 		} else if (iop->ioc_count != 2 * sizeof (uint32_t) ||
4870Sstevel@tonic-gate 		    (mp->b_cont == NULL)) {
4880Sstevel@tonic-gate 			error = EPROTO;
4890Sstevel@tonic-gate 			break;
4900Sstevel@tonic-gate 		}
4910Sstevel@tonic-gate 		ASSERT(ppa != NULL);
4920Sstevel@tonic-gate 		ASSERT(mp->b_cont->b_rptr != NULL);
4930Sstevel@tonic-gate 		ASSERT(sps->sps_npmode == NPMODE_PASS);
4940Sstevel@tonic-gate 		sap = ((uint32_t *)mp->b_cont->b_rptr)[0];
4950Sstevel@tonic-gate 		npmode = (enum NPmode)((uint32_t *)mp->b_cont->b_rptr)[1];
4960Sstevel@tonic-gate 		/*
4970Sstevel@tonic-gate 		 * Walk the sibling streams which belong to the same
4980Sstevel@tonic-gate 		 * ppa, and try to find a stream with matching sap
4990Sstevel@tonic-gate 		 * number.
5000Sstevel@tonic-gate 		 */
5010Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
5020Sstevel@tonic-gate 		for (nextsib = ppa->ppa_streams; nextsib != NULL;
5030Sstevel@tonic-gate 		    nextsib = nextsib->sps_nextsib) {
5040Sstevel@tonic-gate 			if (nextsib->sps_sap == sap) {
5050Sstevel@tonic-gate 				break;	/* found it */
5060Sstevel@tonic-gate 			}
5070Sstevel@tonic-gate 		}
5080Sstevel@tonic-gate 		if (nextsib == NULL) {
5090Sstevel@tonic-gate 			rw_exit(&ppa->ppa_sib_lock);
5100Sstevel@tonic-gate 			break;		/* return EINVAL */
5110Sstevel@tonic-gate 		} else {
5120Sstevel@tonic-gate 			nextsib->sps_npmode = npmode;
5130Sstevel@tonic-gate 			if ((nextsib->sps_npmode != NPMODE_QUEUE) &&
5140Sstevel@tonic-gate 			    (WR(nextsib->sps_rq)->q_first != NULL)) {
5150Sstevel@tonic-gate 				qenable(WR(nextsib->sps_rq));
5160Sstevel@tonic-gate 			}
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
5190Sstevel@tonic-gate 		error = 0;	/* return success */
5200Sstevel@tonic-gate 		break;
5210Sstevel@tonic-gate 	case PPPIO_GIDLE:
5220Sstevel@tonic-gate 		if (ppa == NULL) {
5230Sstevel@tonic-gate 			ASSERT(!IS_SPS_CONTROL(sps));
5240Sstevel@tonic-gate 			error = ENOLINK;
5250Sstevel@tonic-gate 			break;
5260Sstevel@tonic-gate 		} else if (!IS_PPA_TIMESTAMP(ppa)) {
5270Sstevel@tonic-gate 			break;		/* return EINVAL */
5280Sstevel@tonic-gate 		}
5290Sstevel@tonic-gate 		if ((nmp = allocb(sizeof (struct ppp_idle),
5300Sstevel@tonic-gate 		    BPRI_MED)) == NULL) {
5310Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
5320Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
5330Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
5340Sstevel@tonic-gate 			error = ENOSR;
5350Sstevel@tonic-gate 			break;
5360Sstevel@tonic-gate 		}
5370Sstevel@tonic-gate 		if (mp->b_cont != NULL) {
5380Sstevel@tonic-gate 			freemsg(mp->b_cont);
5390Sstevel@tonic-gate 		}
5400Sstevel@tonic-gate 		mp->b_cont = nmp;
5410Sstevel@tonic-gate 		pip = (struct ppp_idle *)nmp->b_wptr;
5420Sstevel@tonic-gate 		nmp->b_wptr += sizeof (struct ppp_idle);
5430Sstevel@tonic-gate 		/*
5440Sstevel@tonic-gate 		 * Get current timestamp and subtract the tx and rx
5450Sstevel@tonic-gate 		 * timestamps to get the actual idle time to be
5460Sstevel@tonic-gate 		 * returned.
5470Sstevel@tonic-gate 		 */
5480Sstevel@tonic-gate 		hrtime = gethrtime();
5490Sstevel@tonic-gate 		pip->xmit_idle = (hrtime - ppa->ppa_lasttx) / 1000000000ul;
5500Sstevel@tonic-gate 		pip->recv_idle = (hrtime - ppa->ppa_lastrx) / 1000000000ul;
5510Sstevel@tonic-gate 		count = msgsize(nmp);
5520Sstevel@tonic-gate 		error = 0;
5530Sstevel@tonic-gate 		break;		/* return success (error is 0) */
5540Sstevel@tonic-gate 	case PPPIO_GTYPE:
5550Sstevel@tonic-gate 		nmp = allocb(sizeof (uint32_t), BPRI_MED);
5560Sstevel@tonic-gate 		if (nmp == NULL) {
5570Sstevel@tonic-gate 			error = ENOSR;
5580Sstevel@tonic-gate 			break;
5590Sstevel@tonic-gate 		}
5600Sstevel@tonic-gate 		if (mp->b_cont != NULL) {
5610Sstevel@tonic-gate 			freemsg(mp->b_cont);
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 		mp->b_cont = nmp;
5640Sstevel@tonic-gate 		/*
5650Sstevel@tonic-gate 		 * Let the requestor know that we are the PPP
5660Sstevel@tonic-gate 		 * multiplexer (PPPTYP_MUX).
5670Sstevel@tonic-gate 		 */
5680Sstevel@tonic-gate 		*(uint32_t *)nmp->b_wptr = PPPTYP_MUX;
5690Sstevel@tonic-gate 		nmp->b_wptr += sizeof (uint32_t);
5700Sstevel@tonic-gate 		count = msgsize(nmp);
5710Sstevel@tonic-gate 		error = 0;		/* return success */
5720Sstevel@tonic-gate 		break;
5730Sstevel@tonic-gate 	case PPPIO_GETSTAT64:
5740Sstevel@tonic-gate 		if (ppa == NULL) {
5750Sstevel@tonic-gate 			break;		/* return EINVAL */
5760Sstevel@tonic-gate 		} else if ((ppa->ppa_lower_wq != NULL) &&
5770Sstevel@tonic-gate 		    !IS_PPA_LASTMOD(ppa)) {
5780Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
5790Sstevel@tonic-gate 			/*
5807643Sanil.udupa@sun.com 			 * We match sps_ioc_id on the M_IOC{ACK,NAK},
5817643Sanil.udupa@sun.com 			 * so if the response hasn't come back yet,
5827643Sanil.udupa@sun.com 			 * new ioctls must be queued instead.
5830Sstevel@tonic-gate 			 */
5847643Sanil.udupa@sun.com 			if (IS_SPS_IOCQ(sps)) {
5857643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
5867643Sanil.udupa@sun.com 				if (!putq(q, mp)) {
5877643Sanil.udupa@sun.com 					error = EAGAIN;
5887643Sanil.udupa@sun.com 					break;
5897643Sanil.udupa@sun.com 				}
5907643Sanil.udupa@sun.com 				return;
5917643Sanil.udupa@sun.com 			} else {
5927643Sanil.udupa@sun.com 				ppa->ppa_ioctlsfwd++;
5937643Sanil.udupa@sun.com 				/*
5947643Sanil.udupa@sun.com 				 * Record the ioctl CMD & ID - this will be
5957643Sanil.udupa@sun.com 				 * used to check the ACK or NAK responses
5967643Sanil.udupa@sun.com 				 * coming from below.
5977643Sanil.udupa@sun.com 				 */
5987643Sanil.udupa@sun.com 				sps->sps_ioc_id = iop->ioc_id;
5997643Sanil.udupa@sun.com 				sps->sps_flags |= SPS_IOCQ;
6007643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
6017643Sanil.udupa@sun.com 			}
6020Sstevel@tonic-gate 			putnext(ppa->ppa_lower_wq, mp);
6030Sstevel@tonic-gate 			return;	/* don't ack or nak the request */
6040Sstevel@tonic-gate 		}
6050Sstevel@tonic-gate 		nmp = allocb(sizeof (*psp), BPRI_MED);
6060Sstevel@tonic-gate 		if (nmp == NULL) {
6070Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
6080Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
6090Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
6100Sstevel@tonic-gate 			error = ENOSR;
6110Sstevel@tonic-gate 			break;
6120Sstevel@tonic-gate 		}
6130Sstevel@tonic-gate 		if (mp->b_cont != NULL) {
6140Sstevel@tonic-gate 			freemsg(mp->b_cont);
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 		mp->b_cont = nmp;
6170Sstevel@tonic-gate 		psp = (struct ppp_stats64 *)nmp->b_wptr;
6180Sstevel@tonic-gate 		/*
6190Sstevel@tonic-gate 		 * Copy the contents of ppp_stats64 structure for this
6200Sstevel@tonic-gate 		 * ppa and return them to the caller.
6210Sstevel@tonic-gate 		 */
6220Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
6230Sstevel@tonic-gate 		bcopy(&ppa->ppa_stats, psp, sizeof (*psp));
6240Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
6250Sstevel@tonic-gate 		nmp->b_wptr += sizeof (*psp);
6260Sstevel@tonic-gate 		count = sizeof (*psp);
6270Sstevel@tonic-gate 		error = 0;		/* return success */
6280Sstevel@tonic-gate 		break;
6290Sstevel@tonic-gate 	case PPPIO_GETCSTAT:
6300Sstevel@tonic-gate 		if (ppa == NULL) {
6310Sstevel@tonic-gate 			break;		/* return EINVAL */
6320Sstevel@tonic-gate 		} else if ((ppa->ppa_lower_wq != NULL) &&
6330Sstevel@tonic-gate 		    !IS_PPA_LASTMOD(ppa)) {
6340Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
6350Sstevel@tonic-gate 			/*
6367643Sanil.udupa@sun.com 			 * See comments in PPPIO_GETSTAT64 case
6377643Sanil.udupa@sun.com 			 * in sppp_ioctl().
6380Sstevel@tonic-gate 			 */
6397643Sanil.udupa@sun.com 			if (IS_SPS_IOCQ(sps)) {
6407643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
6417643Sanil.udupa@sun.com 				if (!putq(q, mp)) {
6427643Sanil.udupa@sun.com 					error = EAGAIN;
6437643Sanil.udupa@sun.com 					break;
6447643Sanil.udupa@sun.com 				}
6457643Sanil.udupa@sun.com 				return;
6467643Sanil.udupa@sun.com 			} else {
6477643Sanil.udupa@sun.com 				ppa->ppa_ioctlsfwd++;
6487643Sanil.udupa@sun.com 				/*
6497643Sanil.udupa@sun.com 				 * Record the ioctl CMD & ID - this will be
6507643Sanil.udupa@sun.com 				 * used to check the ACK or NAK responses
6517643Sanil.udupa@sun.com 				 * coming from below.
6527643Sanil.udupa@sun.com 				 */
6537643Sanil.udupa@sun.com 				sps->sps_ioc_id = iop->ioc_id;
6547643Sanil.udupa@sun.com 				sps->sps_flags |= SPS_IOCQ;
6557643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
6567643Sanil.udupa@sun.com 			}
6570Sstevel@tonic-gate 			putnext(ppa->ppa_lower_wq, mp);
6580Sstevel@tonic-gate 			return;	/* don't ack or nak the request */
6590Sstevel@tonic-gate 		}
6600Sstevel@tonic-gate 		nmp = allocb(sizeof (struct ppp_comp_stats), BPRI_MED);
6610Sstevel@tonic-gate 		if (nmp == NULL) {
6620Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
6630Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
6640Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
6650Sstevel@tonic-gate 			error = ENOSR;
6660Sstevel@tonic-gate 			break;
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 		if (mp->b_cont != NULL) {
6690Sstevel@tonic-gate 			freemsg(mp->b_cont);
6700Sstevel@tonic-gate 		}
6710Sstevel@tonic-gate 		mp->b_cont = nmp;
6720Sstevel@tonic-gate 		pcsp = (struct ppp_comp_stats *)nmp->b_wptr;
6730Sstevel@tonic-gate 		nmp->b_wptr += sizeof (struct ppp_comp_stats);
6740Sstevel@tonic-gate 		bzero((caddr_t)pcsp, sizeof (struct ppp_comp_stats));
6750Sstevel@tonic-gate 		count = msgsize(nmp);
6760Sstevel@tonic-gate 		error = 0;		/* return success */
6770Sstevel@tonic-gate 		break;
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	if (error == 0) {
6810Sstevel@tonic-gate 		/* Success; tell the user. */
6820Sstevel@tonic-gate 		miocack(q, mp, count, 0);
6830Sstevel@tonic-gate 	} else {
6840Sstevel@tonic-gate 		/* Failure; send error back upstream. */
6850Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate  * sppp_uwput()
6910Sstevel@tonic-gate  *
6920Sstevel@tonic-gate  * MT-Perimeters:
6930Sstevel@tonic-gate  *    shared inner, shared outer.
6940Sstevel@tonic-gate  *
6950Sstevel@tonic-gate  * Description:
6960Sstevel@tonic-gate  *    Upper write-side put procedure. Messages from above arrive here.
6970Sstevel@tonic-gate  */
6985640Scarlsonj void
sppp_uwput(queue_t * q,mblk_t * mp)6990Sstevel@tonic-gate sppp_uwput(queue_t *q, mblk_t *mp)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	queue_t		*nextq;
7020Sstevel@tonic-gate 	spppstr_t	*sps;
7030Sstevel@tonic-gate 	sppa_t		*ppa;
7040Sstevel@tonic-gate 	struct iocblk	*iop;
7050Sstevel@tonic-gate 	int		error;
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
7080Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
7090Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
7100Sstevel@tonic-gate 	ppa = sps->sps_ppa;
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	switch (MTYPE(mp)) {
7130Sstevel@tonic-gate 	case M_PCPROTO:
7140Sstevel@tonic-gate 	case M_PROTO:
7150Sstevel@tonic-gate 		if (IS_SPS_CONTROL(sps)) {
7160Sstevel@tonic-gate 			ASSERT(ppa != NULL);
7170Sstevel@tonic-gate 			/*
7180Sstevel@tonic-gate 			 * Intentionally change this to a high priority
7190Sstevel@tonic-gate 			 * message so it doesn't get queued up. M_PROTO is
7200Sstevel@tonic-gate 			 * specifically used for signalling between pppd and its
7210Sstevel@tonic-gate 			 * kernel-level component(s), such as ppptun, so we
7220Sstevel@tonic-gate 			 * make sure that it doesn't get queued up behind
7230Sstevel@tonic-gate 			 * data messages.
7240Sstevel@tonic-gate 			 */
7250Sstevel@tonic-gate 			MTYPE(mp) = M_PCPROTO;
7260Sstevel@tonic-gate 			if ((ppa->ppa_lower_wq != NULL) &&
7270Sstevel@tonic-gate 			    canputnext(ppa->ppa_lower_wq)) {
7280Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
7290Sstevel@tonic-gate 				ppa->ppa_mctlsfwd++;
7300Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
7310Sstevel@tonic-gate 				putnext(ppa->ppa_lower_wq, mp);
7320Sstevel@tonic-gate 			} else {
7330Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
7340Sstevel@tonic-gate 				ppa->ppa_mctlsfwderr++;
7350Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
7360Sstevel@tonic-gate 				freemsg(mp);
7370Sstevel@tonic-gate 			}
7380Sstevel@tonic-gate 		} else {
7395640Scarlsonj 			(void) sppp_mproto(q, mp, sps);
7405640Scarlsonj 			return;
7410Sstevel@tonic-gate 		}
7420Sstevel@tonic-gate 		break;
7430Sstevel@tonic-gate 	case M_DATA:
7440Sstevel@tonic-gate 		if ((nextq = sppp_send(q, &mp, sps)) != NULL)
7450Sstevel@tonic-gate 			putnext(nextq, mp);
7460Sstevel@tonic-gate 		break;
7470Sstevel@tonic-gate 	case M_IOCTL:
7480Sstevel@tonic-gate 		error = EINVAL;
7490Sstevel@tonic-gate 		iop = (struct iocblk *)mp->b_rptr;
7500Sstevel@tonic-gate 		switch (iop->ioc_cmd) {
7510Sstevel@tonic-gate 		case DLIOCRAW:
7520Sstevel@tonic-gate 		case DL_IOC_HDR_INFO:
7530Sstevel@tonic-gate 		case PPPIO_ATTACH:
7540Sstevel@tonic-gate 		case PPPIO_DEBUG:
7550Sstevel@tonic-gate 		case PPPIO_DETACH:
7560Sstevel@tonic-gate 		case PPPIO_LASTMOD:
7570Sstevel@tonic-gate 		case PPPIO_MRU:
7580Sstevel@tonic-gate 		case PPPIO_MTU:
7590Sstevel@tonic-gate 		case PPPIO_USETIMESTAMP:
7600Sstevel@tonic-gate 		case PPPIO_BLOCKNP:
7610Sstevel@tonic-gate 		case PPPIO_UNBLOCKNP:
7620Sstevel@tonic-gate 			qwriter(q, mp, sppp_inner_ioctl, PERIM_INNER);
7635640Scarlsonj 			return;
7640Sstevel@tonic-gate 		case I_LINK:
7650Sstevel@tonic-gate 		case I_UNLINK:
7660Sstevel@tonic-gate 		case PPPIO_NEWPPA:
7670Sstevel@tonic-gate 			qwriter(q, mp, sppp_outer_ioctl, PERIM_OUTER);
7685640Scarlsonj 			return;
7690Sstevel@tonic-gate 		case PPPIO_NPMODE:
7700Sstevel@tonic-gate 		case PPPIO_GIDLE:
7710Sstevel@tonic-gate 		case PPPIO_GTYPE:
7720Sstevel@tonic-gate 		case PPPIO_GETSTAT64:
7730Sstevel@tonic-gate 		case PPPIO_GETCSTAT:
7740Sstevel@tonic-gate 			/*
7750Sstevel@tonic-gate 			 * These require additional auto variables to
7760Sstevel@tonic-gate 			 * handle, so (for optimization reasons)
7770Sstevel@tonic-gate 			 * they're moved off to a separate function.
7780Sstevel@tonic-gate 			 */
7790Sstevel@tonic-gate 			sppp_ioctl(q, mp);
7805640Scarlsonj 			return;
7810Sstevel@tonic-gate 		case PPPIO_GETSTAT:
7820Sstevel@tonic-gate 			break;			/* 32 bit interface gone */
7830Sstevel@tonic-gate 		default:
7840Sstevel@tonic-gate 			if (iop->ioc_cr == NULL ||
785*9751Sjames.d.carlson@sun.com 			    secpolicy_ppp_config(iop->ioc_cr) != 0) {
7860Sstevel@tonic-gate 				error = EPERM;
7870Sstevel@tonic-gate 				break;
7880Sstevel@tonic-gate 			} else if ((ppa == NULL) ||
7890Sstevel@tonic-gate 			    (ppa->ppa_lower_wq == NULL)) {
7900Sstevel@tonic-gate 				break;		/* return EINVAL */
7910Sstevel@tonic-gate 			}
7920Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
7930Sstevel@tonic-gate 			/*
7947643Sanil.udupa@sun.com 			 * See comments in PPPIO_GETSTAT64 case
7957643Sanil.udupa@sun.com 			 * in sppp_ioctl().
7960Sstevel@tonic-gate 			 */
7977643Sanil.udupa@sun.com 			if (IS_SPS_IOCQ(sps)) {
7987643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
7997643Sanil.udupa@sun.com 				if (!putq(q, mp)) {
8007643Sanil.udupa@sun.com 					error = EAGAIN;
8017643Sanil.udupa@sun.com 					break;
8027643Sanil.udupa@sun.com 				}
8037643Sanil.udupa@sun.com 				return;
8047643Sanil.udupa@sun.com 			} else {
8057643Sanil.udupa@sun.com 				ppa->ppa_ioctlsfwd++;
8067643Sanil.udupa@sun.com 				/*
8077643Sanil.udupa@sun.com 				 * Record the ioctl CMD & ID -
8087643Sanil.udupa@sun.com 				 * this will be used to check the
8097643Sanil.udupa@sun.com 				 * ACK or NAK responses coming from below.
8107643Sanil.udupa@sun.com 				 */
8117643Sanil.udupa@sun.com 				sps->sps_ioc_id = iop->ioc_id;
8127643Sanil.udupa@sun.com 				sps->sps_flags |= SPS_IOCQ;
8137643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
8147643Sanil.udupa@sun.com 			}
8150Sstevel@tonic-gate 			putnext(ppa->ppa_lower_wq, mp);
8165640Scarlsonj 			return;		/* don't ack or nak the request */
8170Sstevel@tonic-gate 		}
8180Sstevel@tonic-gate 		/* Failure; send error back upstream. */
8190Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
8200Sstevel@tonic-gate 		break;
8210Sstevel@tonic-gate 	case M_FLUSH:
8220Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
8230Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
8260Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
8270Sstevel@tonic-gate 			qreply(q, mp);
8280Sstevel@tonic-gate 		} else {
8290Sstevel@tonic-gate 			freemsg(mp);
8300Sstevel@tonic-gate 		}
8310Sstevel@tonic-gate 		break;
8320Sstevel@tonic-gate 	default:
8330Sstevel@tonic-gate 		freemsg(mp);
8340Sstevel@tonic-gate 		break;
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate /*
8390Sstevel@tonic-gate  * sppp_uwsrv()
8400Sstevel@tonic-gate  *
8410Sstevel@tonic-gate  * MT-Perimeters:
8420Sstevel@tonic-gate  *    exclusive inner, shared outer.
8430Sstevel@tonic-gate  *
8440Sstevel@tonic-gate  * Description:
8450Sstevel@tonic-gate  *    Upper write-side service procedure. Note that this procedure does
8460Sstevel@tonic-gate  *    not get called when a message is placed on our write-side queue, since
8470Sstevel@tonic-gate  *    automatic queue scheduling has been turned off by noenable() when
8480Sstevel@tonic-gate  *    the queue was opened. We do this on purpose, as we explicitly control
8490Sstevel@tonic-gate  *    the write-side queue. Therefore, this procedure gets called when
8500Sstevel@tonic-gate  *    the lower write service procedure qenable() the upper write stream queue.
8510Sstevel@tonic-gate  */
8525640Scarlsonj void
sppp_uwsrv(queue_t * q)8530Sstevel@tonic-gate sppp_uwsrv(queue_t *q)
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate 	spppstr_t	*sps;
8567643Sanil.udupa@sun.com 	sppa_t		*ppa;
8570Sstevel@tonic-gate 	mblk_t		*mp;
8580Sstevel@tonic-gate 	queue_t		*nextq;
8597643Sanil.udupa@sun.com 	struct iocblk	*iop;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
8620Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
8637643Sanil.udupa@sun.com 
8640Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
8657643Sanil.udupa@sun.com 		if (MTYPE(mp) == M_IOCTL) {
8667643Sanil.udupa@sun.com 			ppa = sps->sps_ppa;
8677643Sanil.udupa@sun.com 			if ((ppa == NULL) || (ppa->ppa_lower_wq == NULL)) {
8687643Sanil.udupa@sun.com 				miocnak(q, mp, 0, EINVAL);
8697643Sanil.udupa@sun.com 				continue;
8707643Sanil.udupa@sun.com 			}
8717643Sanil.udupa@sun.com 
8727643Sanil.udupa@sun.com 			iop = (struct iocblk *)mp->b_rptr;
8737643Sanil.udupa@sun.com 			mutex_enter(&ppa->ppa_sta_lock);
8747643Sanil.udupa@sun.com 			/*
8757643Sanil.udupa@sun.com 			 * See comments in PPPIO_GETSTAT64 case
8767643Sanil.udupa@sun.com 			 * in sppp_ioctl().
8777643Sanil.udupa@sun.com 			 */
8787643Sanil.udupa@sun.com 			if (IS_SPS_IOCQ(sps)) {
8797643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
8807643Sanil.udupa@sun.com 				if (putbq(q, mp) == 0)
8817643Sanil.udupa@sun.com 					miocnak(q, mp, 0, EAGAIN);
8827643Sanil.udupa@sun.com 				break;
8837643Sanil.udupa@sun.com 			} else {
8847643Sanil.udupa@sun.com 				ppa->ppa_ioctlsfwd++;
8857643Sanil.udupa@sun.com 				sps->sps_ioc_id = iop->ioc_id;
8867643Sanil.udupa@sun.com 				sps->sps_flags |= SPS_IOCQ;
8877643Sanil.udupa@sun.com 				mutex_exit(&ppa->ppa_sta_lock);
8887643Sanil.udupa@sun.com 				putnext(ppa->ppa_lower_wq, mp);
8897643Sanil.udupa@sun.com 			}
8907643Sanil.udupa@sun.com 		} else if ((nextq =
8917643Sanil.udupa@sun.com 		    sppp_outpkt(q, &mp, msgdsize(mp), sps)) == NULL) {
8920Sstevel@tonic-gate 			if (mp != NULL) {
8930Sstevel@tonic-gate 				if (putbq(q, mp) == 0)
8940Sstevel@tonic-gate 					freemsg(mp);
8950Sstevel@tonic-gate 				break;
8960Sstevel@tonic-gate 			}
8970Sstevel@tonic-gate 		} else {
8980Sstevel@tonic-gate 			putnext(nextq, mp);
8990Sstevel@tonic-gate 		}
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate void
sppp_remove_ppa(spppstr_t * sps)9040Sstevel@tonic-gate sppp_remove_ppa(spppstr_t *sps)
9050Sstevel@tonic-gate {
9060Sstevel@tonic-gate 	spppstr_t *nextsib;
9070Sstevel@tonic-gate 	sppa_t *ppa = sps->sps_ppa;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
9100Sstevel@tonic-gate 	if (ppa->ppa_refcnt <= 1) {
9110Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
9120Sstevel@tonic-gate 		sppp_free_ppa(ppa);
9130Sstevel@tonic-gate 	} else {
9140Sstevel@tonic-gate 		nextsib = ppa->ppa_streams;
9150Sstevel@tonic-gate 		if (nextsib == sps) {
9160Sstevel@tonic-gate 			ppa->ppa_streams = sps->sps_nextsib;
9170Sstevel@tonic-gate 		} else {
9180Sstevel@tonic-gate 			while (nextsib->sps_nextsib != NULL) {
9190Sstevel@tonic-gate 				if (nextsib->sps_nextsib == sps) {
9200Sstevel@tonic-gate 					nextsib->sps_nextsib =
9210Sstevel@tonic-gate 					    sps->sps_nextsib;
9220Sstevel@tonic-gate 					break;
9230Sstevel@tonic-gate 				}
9240Sstevel@tonic-gate 				nextsib = nextsib->sps_nextsib;
9250Sstevel@tonic-gate 			}
9260Sstevel@tonic-gate 		}
9270Sstevel@tonic-gate 		ppa->ppa_refcnt--;
9280Sstevel@tonic-gate 		/*
9290Sstevel@tonic-gate 		 * And if this stream was marked as promiscuous
9300Sstevel@tonic-gate 		 * (SPS_PROMISC), then we need to update the
9310Sstevel@tonic-gate 		 * promiscuous streams count. This should only happen
9320Sstevel@tonic-gate 		 * when DL_DETACH_REQ is issued prior to marking the
9330Sstevel@tonic-gate 		 * stream as non-promiscuous, through
9340Sstevel@tonic-gate 		 * DL_PROMISCOFF_REQ request.
9350Sstevel@tonic-gate 		 */
9360Sstevel@tonic-gate 		if (IS_SPS_PROMISC(sps)) {
9370Sstevel@tonic-gate 			ASSERT(ppa->ppa_promicnt > 0);
9380Sstevel@tonic-gate 			ppa->ppa_promicnt--;
9390Sstevel@tonic-gate 		}
9400Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 	sps->sps_nextsib = NULL;
9430Sstevel@tonic-gate 	sps->sps_ppa = NULL;
9440Sstevel@tonic-gate 	freemsg(sps->sps_hangup);
9450Sstevel@tonic-gate 	sps->sps_hangup = NULL;
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate sppa_t *
sppp_find_ppa(uint32_t ppa_id)9490Sstevel@tonic-gate sppp_find_ppa(uint32_t ppa_id)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate 	sppa_t *ppa;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	for (ppa = ppa_list; ppa != NULL; ppa = ppa->ppa_nextppa) {
9540Sstevel@tonic-gate 		if (ppa->ppa_ppa_id == ppa_id) {
9550Sstevel@tonic-gate 			break;	/* found the ppa */
9560Sstevel@tonic-gate 		}
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 	return (ppa);
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate /*
9620Sstevel@tonic-gate  * sppp_inner_ioctl()
9630Sstevel@tonic-gate  *
9640Sstevel@tonic-gate  * MT-Perimeters:
9650Sstevel@tonic-gate  *    exclusive inner, shared outer
9660Sstevel@tonic-gate  *
9670Sstevel@tonic-gate  * Description:
9680Sstevel@tonic-gate  *    Called by sppp_uwput as a result of receiving ioctls which require
9690Sstevel@tonic-gate  *    an exclusive access at the inner perimeter.
9700Sstevel@tonic-gate  */
9710Sstevel@tonic-gate static void
sppp_inner_ioctl(queue_t * q,mblk_t * mp)9720Sstevel@tonic-gate sppp_inner_ioctl(queue_t *q, mblk_t *mp)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate 	spppstr_t	*sps;
9750Sstevel@tonic-gate 	sppa_t		*ppa;
9760Sstevel@tonic-gate 	struct iocblk	*iop;
9770Sstevel@tonic-gate 	mblk_t		*nmp;
9780Sstevel@tonic-gate 	int		error = EINVAL;
9790Sstevel@tonic-gate 	int		count = 0;
9800Sstevel@tonic-gate 	int		dbgcmd;
9810Sstevel@tonic-gate 	int		mru, mtu;
9820Sstevel@tonic-gate 	uint32_t	ppa_id;
9830Sstevel@tonic-gate 	hrtime_t	hrtime;
9840Sstevel@tonic-gate 	uint16_t	proto;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
9870Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
9900Sstevel@tonic-gate 	ppa = sps->sps_ppa;
9910Sstevel@tonic-gate 	iop = (struct iocblk *)mp->b_rptr;
9920Sstevel@tonic-gate 	switch (iop->ioc_cmd) {
9930Sstevel@tonic-gate 	case DLIOCRAW:
9940Sstevel@tonic-gate 		if (IS_SPS_CONTROL(sps)) {
9950Sstevel@tonic-gate 			break;		/* return EINVAL */
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 		sps->sps_flags |= SPS_RAWDATA;
9980Sstevel@tonic-gate 		error = 0;		/* return success */
9990Sstevel@tonic-gate 		break;
10000Sstevel@tonic-gate 	case DL_IOC_HDR_INFO:
10010Sstevel@tonic-gate 		if (IS_SPS_CONTROL(sps)) {
10020Sstevel@tonic-gate 			break;		/* return EINVAL */
10030Sstevel@tonic-gate 		} else if ((mp->b_cont == NULL) ||
10040Sstevel@tonic-gate 		    *((t_uscalar_t *)mp->b_cont->b_rptr) != DL_UNITDATA_REQ ||
10050Sstevel@tonic-gate 		    (MBLKL(mp->b_cont) < (sizeof (dl_unitdata_req_t) +
10065640Scarlsonj 		    SPPP_ADDRL))) {
10070Sstevel@tonic-gate 			error = EPROTO;
10080Sstevel@tonic-gate 			break;
10090Sstevel@tonic-gate 		} else if (ppa == NULL) {
10100Sstevel@tonic-gate 			error = ENOLINK;
10110Sstevel@tonic-gate 			break;
10120Sstevel@tonic-gate 		}
10130Sstevel@tonic-gate 		if ((nmp = allocb(PPP_HDRLEN, BPRI_MED)) == NULL) {
10140Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
10150Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
10160Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
10170Sstevel@tonic-gate 			error = ENOMEM;
10180Sstevel@tonic-gate 			break;
10190Sstevel@tonic-gate 		}
10200Sstevel@tonic-gate 		*(uchar_t *)nmp->b_wptr++ = PPP_ALLSTATIONS;
10210Sstevel@tonic-gate 		*(uchar_t *)nmp->b_wptr++ = PPP_UI;
10220Sstevel@tonic-gate 		*(uchar_t *)nmp->b_wptr++ = sps->sps_sap >> 8;
10230Sstevel@tonic-gate 		*(uchar_t *)nmp->b_wptr++ = sps->sps_sap & 0xff;
10240Sstevel@tonic-gate 		ASSERT(MBLKL(nmp) == PPP_HDRLEN);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		linkb(mp, nmp);
10270Sstevel@tonic-gate 		sps->sps_flags |= SPS_FASTPATH;
10280Sstevel@tonic-gate 		error = 0;		/* return success */
10290Sstevel@tonic-gate 		count = msgsize(nmp);
10300Sstevel@tonic-gate 		break;
10310Sstevel@tonic-gate 	case PPPIO_ATTACH:
10320Sstevel@tonic-gate 		if (IS_SPS_CONTROL(sps) || IS_SPS_PIOATTACH(sps) ||
10330Sstevel@tonic-gate 		    (sps->sps_dlstate != DL_UNATTACHED) ||
10340Sstevel@tonic-gate 		    (iop->ioc_count != sizeof (uint32_t))) {
10350Sstevel@tonic-gate 			break;		/* return EINVAL */
10360Sstevel@tonic-gate 		} else if (mp->b_cont == NULL) {
10370Sstevel@tonic-gate 			error = EPROTO;
10380Sstevel@tonic-gate 			break;
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 		ASSERT(mp->b_cont->b_rptr != NULL);
10410Sstevel@tonic-gate 		/* If there's something here, it's detached. */
10420Sstevel@tonic-gate 		if (ppa != NULL) {
10430Sstevel@tonic-gate 			sppp_remove_ppa(sps);
10440Sstevel@tonic-gate 		}
10450Sstevel@tonic-gate 		ppa_id = *(uint32_t *)mp->b_cont->b_rptr;
10460Sstevel@tonic-gate 		ppa = sppp_find_ppa(ppa_id);
10470Sstevel@tonic-gate 		/*
10480Sstevel@tonic-gate 		 * If we can't find it, then it's either because the requestor
10490Sstevel@tonic-gate 		 * has supplied a wrong ppa_id to be attached to, or because
10500Sstevel@tonic-gate 		 * the control stream for the specified ppa_id has been closed
10510Sstevel@tonic-gate 		 * before we get here.
10520Sstevel@tonic-gate 		 */
10530Sstevel@tonic-gate 		if (ppa == NULL) {
10540Sstevel@tonic-gate 			error = ENOENT;
10550Sstevel@tonic-gate 			break;
10560Sstevel@tonic-gate 		}
1057*9751Sjames.d.carlson@sun.com 		if (iop->ioc_cr == NULL ||
1058*9751Sjames.d.carlson@sun.com 		    ppa->ppa_zoneid != crgetzoneid(iop->ioc_cr)) {
1059*9751Sjames.d.carlson@sun.com 			error = EPERM;
1060*9751Sjames.d.carlson@sun.com 			break;
1061*9751Sjames.d.carlson@sun.com 		}
10620Sstevel@tonic-gate 		/*
10630Sstevel@tonic-gate 		 * Preallocate the hangup message so that we're always
10640Sstevel@tonic-gate 		 * able to send this upstream in the event of a
10650Sstevel@tonic-gate 		 * catastrophic failure.
10660Sstevel@tonic-gate 		 */
10670Sstevel@tonic-gate 		if ((sps->sps_hangup = allocb(1, BPRI_MED)) == NULL) {
10680Sstevel@tonic-gate 			error = ENOSR;
10690Sstevel@tonic-gate 			break;
10700Sstevel@tonic-gate 		}
10710Sstevel@tonic-gate 		/*
10720Sstevel@tonic-gate 		 * There are two ways to attach a stream to a ppa: one is
10730Sstevel@tonic-gate 		 * through DLPI (DL_ATTACH_REQ) and the other is through
10740Sstevel@tonic-gate 		 * PPPIO_ATTACH. This is why we need to distinguish whether or
10750Sstevel@tonic-gate 		 * not a stream was allocated via PPPIO_ATTACH, so that we can
10760Sstevel@tonic-gate 		 * properly detach it when we receive PPPIO_DETACH ioctl
10770Sstevel@tonic-gate 		 * request.
10780Sstevel@tonic-gate 		 */
10790Sstevel@tonic-gate 		sps->sps_flags |= SPS_PIOATTACH;
10800Sstevel@tonic-gate 		sps->sps_ppa = ppa;
10810Sstevel@tonic-gate 		/*
10820Sstevel@tonic-gate 		 * Add this stream to the head of the list of sibling streams
10830Sstevel@tonic-gate 		 * which belong to the same ppa as specified.
10840Sstevel@tonic-gate 		 */
10850Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_WRITER);
10860Sstevel@tonic-gate 		ppa->ppa_refcnt++;
10870Sstevel@tonic-gate 		sps->sps_nextsib = ppa->ppa_streams;
10880Sstevel@tonic-gate 		ppa->ppa_streams = sps;
10890Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
10900Sstevel@tonic-gate 		error = 0;		/* return success */
10910Sstevel@tonic-gate 		break;
10920Sstevel@tonic-gate 	case PPPIO_BLOCKNP:
10930Sstevel@tonic-gate 	case PPPIO_UNBLOCKNP:
10940Sstevel@tonic-gate 		if (iop->ioc_cr == NULL ||
1095*9751Sjames.d.carlson@sun.com 		    secpolicy_ppp_config(iop->ioc_cr) != 0) {
10960Sstevel@tonic-gate 			error = EPERM;
10970Sstevel@tonic-gate 			break;
10980Sstevel@tonic-gate 		}
10990Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (uint16_t));
11000Sstevel@tonic-gate 		if (error != 0)
11010Sstevel@tonic-gate 			break;
11020Sstevel@tonic-gate 		ASSERT(mp->b_cont->b_rptr != NULL);
11030Sstevel@tonic-gate 		proto = *(uint16_t *)mp->b_cont->b_rptr;
11040Sstevel@tonic-gate 		if (iop->ioc_cmd == PPPIO_BLOCKNP) {
11050Sstevel@tonic-gate 			uint32_t npflagpos = sppp_ppp2np(proto);
11060Sstevel@tonic-gate 			/*
11070Sstevel@tonic-gate 			 * Mark proto as blocked in ppa_npflag until the
11080Sstevel@tonic-gate 			 * corresponding queues for proto have been plumbed.
11090Sstevel@tonic-gate 			 */
11100Sstevel@tonic-gate 			if (npflagpos != 0) {
11110Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_npmutex);
11120Sstevel@tonic-gate 				ppa->ppa_npflag |= (1 << npflagpos);
11130Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_npmutex);
11140Sstevel@tonic-gate 			} else {
11150Sstevel@tonic-gate 				error = EINVAL;
11160Sstevel@tonic-gate 			}
11170Sstevel@tonic-gate 		} else {
11180Sstevel@tonic-gate 			/*
11190Sstevel@tonic-gate 			 * reset ppa_npflag and release proto
11200Sstevel@tonic-gate 			 * packets that were being held in control queue.
11210Sstevel@tonic-gate 			 */
11220Sstevel@tonic-gate 			sppp_release_pkts(ppa, proto);
11230Sstevel@tonic-gate 		}
11240Sstevel@tonic-gate 		break;
11250Sstevel@tonic-gate 	case PPPIO_DEBUG:
11260Sstevel@tonic-gate 		if (iop->ioc_cr == NULL ||
1127*9751Sjames.d.carlson@sun.com 		    secpolicy_ppp_config(iop->ioc_cr) != 0) {
11280Sstevel@tonic-gate 			error = EPERM;
11290Sstevel@tonic-gate 			break;
11300Sstevel@tonic-gate 		} else if (iop->ioc_count != sizeof (uint32_t)) {
11310Sstevel@tonic-gate 			break;		/* return EINVAL */
11320Sstevel@tonic-gate 		} else if (mp->b_cont == NULL) {
11330Sstevel@tonic-gate 			error = EPROTO;
11340Sstevel@tonic-gate 			break;
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 		ASSERT(mp->b_cont->b_rptr != NULL);
11370Sstevel@tonic-gate 		dbgcmd = *(uint32_t *)mp->b_cont->b_rptr;
11380Sstevel@tonic-gate 		/*
11390Sstevel@tonic-gate 		 * We accept PPPDBG_LOG + PPPDBG_DRIVER value as an indication
11400Sstevel@tonic-gate 		 * that SPS_KDEBUG needs to be enabled for this upper stream.
11410Sstevel@tonic-gate 		 */
11420Sstevel@tonic-gate 		if (dbgcmd == PPPDBG_LOG + PPPDBG_DRIVER) {
11430Sstevel@tonic-gate 			sps->sps_flags |= SPS_KDEBUG;
11440Sstevel@tonic-gate 			error = 0;	/* return success */
11450Sstevel@tonic-gate 			break;
11460Sstevel@tonic-gate 		}
11470Sstevel@tonic-gate 		/*
11480Sstevel@tonic-gate 		 * Otherwise, for any other values, we send them down only if
11490Sstevel@tonic-gate 		 * there is an attachment and if the attachment has something
11500Sstevel@tonic-gate 		 * linked underneath it.
11510Sstevel@tonic-gate 		 */
11520Sstevel@tonic-gate 		if ((ppa == NULL) || (ppa->ppa_lower_wq == NULL)) {
11530Sstevel@tonic-gate 			error = ENOLINK;
11540Sstevel@tonic-gate 			break;
11550Sstevel@tonic-gate 		}
11560Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
11570Sstevel@tonic-gate 		/*
11587643Sanil.udupa@sun.com 		 * See comments in PPPIO_GETSTAT64 case
11597643Sanil.udupa@sun.com 		 * in sppp_ioctl().
11600Sstevel@tonic-gate 		 */
11617643Sanil.udupa@sun.com 		if (IS_SPS_IOCQ(sps)) {
11627643Sanil.udupa@sun.com 			mutex_exit(&ppa->ppa_sta_lock);
11637643Sanil.udupa@sun.com 			if (!putq(q, mp)) {
11647643Sanil.udupa@sun.com 				error = EAGAIN;
11657643Sanil.udupa@sun.com 				break;
11667643Sanil.udupa@sun.com 			}
11677643Sanil.udupa@sun.com 			return;
11687643Sanil.udupa@sun.com 		} else {
11697643Sanil.udupa@sun.com 			ppa->ppa_ioctlsfwd++;
11707643Sanil.udupa@sun.com 			/*
11717643Sanil.udupa@sun.com 			 * Record the ioctl CMD & ID -
11727643Sanil.udupa@sun.com 			 * this will be used to check the
11737643Sanil.udupa@sun.com 			 * ACK or NAK responses coming from below.
11747643Sanil.udupa@sun.com 			 */
11757643Sanil.udupa@sun.com 			sps->sps_ioc_id = iop->ioc_id;
11767643Sanil.udupa@sun.com 			sps->sps_flags |= SPS_IOCQ;
11777643Sanil.udupa@sun.com 			mutex_exit(&ppa->ppa_sta_lock);
11787643Sanil.udupa@sun.com 		}
11790Sstevel@tonic-gate 		putnext(ppa->ppa_lower_wq, mp);
11800Sstevel@tonic-gate 		return;			/* don't ack or nak the request */
11810Sstevel@tonic-gate 	case PPPIO_DETACH:
11820Sstevel@tonic-gate 		if (!IS_SPS_PIOATTACH(sps)) {
11830Sstevel@tonic-gate 			break;		/* return EINVAL */
11840Sstevel@tonic-gate 		}
11850Sstevel@tonic-gate 		/*
11860Sstevel@tonic-gate 		 * The SPS_PIOATTACH flag set on the stream tells us that
11870Sstevel@tonic-gate 		 * the ppa field is still valid. In the event that the control
11880Sstevel@tonic-gate 		 * stream be closed prior to this stream's detachment, the
11890Sstevel@tonic-gate 		 * SPS_PIOATTACH flag would have been cleared from this stream
11900Sstevel@tonic-gate 		 * during close; in that case we won't get here.
11910Sstevel@tonic-gate 		 */
11920Sstevel@tonic-gate 		ASSERT(ppa != NULL);
11930Sstevel@tonic-gate 		ASSERT(ppa->ppa_ctl != sps);
11940Sstevel@tonic-gate 		ASSERT(sps->sps_dlstate == DL_UNATTACHED);
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 		/*
11970Sstevel@tonic-gate 		 * We don't actually detach anything until the stream is
11980Sstevel@tonic-gate 		 * closed or reattached.
11990Sstevel@tonic-gate 		 */
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 		sps->sps_flags &= ~SPS_PIOATTACH;
12020Sstevel@tonic-gate 		error = 0;		/* return success */
12030Sstevel@tonic-gate 		break;
12040Sstevel@tonic-gate 	case PPPIO_LASTMOD:
12050Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps)) {
12060Sstevel@tonic-gate 			break;		/* return EINVAL */
12070Sstevel@tonic-gate 		}
12080Sstevel@tonic-gate 		ASSERT(ppa != NULL);
12090Sstevel@tonic-gate 		ppa->ppa_flags |= PPA_LASTMOD;
12100Sstevel@tonic-gate 		error = 0;		/* return success */
12110Sstevel@tonic-gate 		break;
12120Sstevel@tonic-gate 	case PPPIO_MRU:
12130Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps) ||
12140Sstevel@tonic-gate 		    (iop->ioc_count != sizeof (uint32_t))) {
12150Sstevel@tonic-gate 			break;		/* return EINVAL */
12160Sstevel@tonic-gate 		} else if (mp->b_cont == NULL) {
12170Sstevel@tonic-gate 			error = EPROTO;
12180Sstevel@tonic-gate 			break;
12190Sstevel@tonic-gate 		}
12200Sstevel@tonic-gate 		ASSERT(ppa != NULL);
12210Sstevel@tonic-gate 		ASSERT(mp->b_cont->b_rptr != NULL);
12220Sstevel@tonic-gate 		mru = *(uint32_t *)mp->b_cont->b_rptr;
12230Sstevel@tonic-gate 		if ((mru <= 0) || (mru > PPP_MAXMRU)) {
12240Sstevel@tonic-gate 			error = EPROTO;
12250Sstevel@tonic-gate 			break;
12260Sstevel@tonic-gate 		}
12270Sstevel@tonic-gate 		if (mru < PPP_MRU) {
12280Sstevel@tonic-gate 			mru = PPP_MRU;
12290Sstevel@tonic-gate 		}
12300Sstevel@tonic-gate 		ppa->ppa_mru = (uint16_t)mru;
12310Sstevel@tonic-gate 		/*
12320Sstevel@tonic-gate 		 * If there's something beneath this driver for the ppa, then
12330Sstevel@tonic-gate 		 * inform it (or them) of the MRU size. Only do this is we
12340Sstevel@tonic-gate 		 * are not the last PPP module on the stream.
12350Sstevel@tonic-gate 		 */
12360Sstevel@tonic-gate 		if (!IS_PPA_LASTMOD(ppa) && (ppa->ppa_lower_wq != NULL)) {
12370Sstevel@tonic-gate 			(void) putctl4(ppa->ppa_lower_wq, M_CTL, PPPCTL_MRU,
12380Sstevel@tonic-gate 			    mru);
12390Sstevel@tonic-gate 		}
12400Sstevel@tonic-gate 		error = 0;		/* return success */
12410Sstevel@tonic-gate 		break;
12420Sstevel@tonic-gate 	case PPPIO_MTU:
12430Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps) ||
12440Sstevel@tonic-gate 		    (iop->ioc_count != sizeof (uint32_t))) {
12450Sstevel@tonic-gate 			break;		/* return EINVAL */
12460Sstevel@tonic-gate 		} else if (mp->b_cont == NULL) {
12470Sstevel@tonic-gate 			error = EPROTO;
12480Sstevel@tonic-gate 			break;
12490Sstevel@tonic-gate 		}
12500Sstevel@tonic-gate 		ASSERT(ppa != NULL);
12510Sstevel@tonic-gate 		ASSERT(mp->b_cont->b_rptr != NULL);
12520Sstevel@tonic-gate 		mtu = *(uint32_t *)mp->b_cont->b_rptr;
12530Sstevel@tonic-gate 		if ((mtu <= 0) || (mtu > PPP_MAXMTU)) {
12540Sstevel@tonic-gate 			error = EPROTO;
12550Sstevel@tonic-gate 			break;
12560Sstevel@tonic-gate 		}
12570Sstevel@tonic-gate 		ppa->ppa_mtu = (uint16_t)mtu;
12580Sstevel@tonic-gate 		/*
12590Sstevel@tonic-gate 		 * If there's something beneath this driver for the ppa, then
12600Sstevel@tonic-gate 		 * inform it (or them) of the MTU size. Only do this if we
12610Sstevel@tonic-gate 		 * are not the last PPP module on the stream.
12620Sstevel@tonic-gate 		 */
12630Sstevel@tonic-gate 		if (!IS_PPA_LASTMOD(ppa) && (ppa->ppa_lower_wq != NULL)) {
12640Sstevel@tonic-gate 			(void) putctl4(ppa->ppa_lower_wq, M_CTL, PPPCTL_MTU,
12650Sstevel@tonic-gate 			    mtu);
12660Sstevel@tonic-gate 		}
12670Sstevel@tonic-gate 		error = 0;		/* return success */
12680Sstevel@tonic-gate 		break;
12690Sstevel@tonic-gate 	case PPPIO_USETIMESTAMP:
12700Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps)) {
12710Sstevel@tonic-gate 			break;		/* return EINVAL */
12720Sstevel@tonic-gate 		}
12730Sstevel@tonic-gate 		if (!IS_PPA_TIMESTAMP(ppa)) {
12740Sstevel@tonic-gate 			hrtime = gethrtime();
12750Sstevel@tonic-gate 			ppa->ppa_lasttx = ppa->ppa_lastrx = hrtime;
12760Sstevel@tonic-gate 			ppa->ppa_flags |= PPA_TIMESTAMP;
12770Sstevel@tonic-gate 		}
12780Sstevel@tonic-gate 		error = 0;
12790Sstevel@tonic-gate 		break;
12800Sstevel@tonic-gate 	}
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	if (error == 0) {
12830Sstevel@tonic-gate 		/* Success; tell the user */
12840Sstevel@tonic-gate 		miocack(q, mp, count, 0);
12850Sstevel@tonic-gate 	} else {
12860Sstevel@tonic-gate 		/* Failure; send error back upstream */
12870Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
12880Sstevel@tonic-gate 	}
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate  * sppp_outer_ioctl()
12930Sstevel@tonic-gate  *
12940Sstevel@tonic-gate  * MT-Perimeters:
12950Sstevel@tonic-gate  *    exclusive inner, exclusive outer
12960Sstevel@tonic-gate  *
12970Sstevel@tonic-gate  * Description:
12980Sstevel@tonic-gate  *    Called by sppp_uwput as a result of receiving ioctls which require
12990Sstevel@tonic-gate  *    an exclusive access at the outer perimeter.
13000Sstevel@tonic-gate  */
13010Sstevel@tonic-gate static void
sppp_outer_ioctl(queue_t * q,mblk_t * mp)13020Sstevel@tonic-gate sppp_outer_ioctl(queue_t *q, mblk_t *mp)
13030Sstevel@tonic-gate {
1304*9751Sjames.d.carlson@sun.com 	spppstr_t	*sps = q->q_ptr;
13050Sstevel@tonic-gate 	spppstr_t	*nextsib;
13060Sstevel@tonic-gate 	queue_t		*lwq;
13070Sstevel@tonic-gate 	sppa_t		*ppa;
13080Sstevel@tonic-gate 	struct iocblk	*iop;
13090Sstevel@tonic-gate 	int		error = EINVAL;
13100Sstevel@tonic-gate 	int		count = 0;
13110Sstevel@tonic-gate 	uint32_t	ppa_id;
13120Sstevel@tonic-gate 	mblk_t		*nmp;
1313*9751Sjames.d.carlson@sun.com 	zoneid_t	zoneid;
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	sps = (spppstr_t *)q->q_ptr;
13160Sstevel@tonic-gate 	ppa = sps->sps_ppa;
13170Sstevel@tonic-gate 	iop = (struct iocblk *)mp->b_rptr;
13180Sstevel@tonic-gate 	switch (iop->ioc_cmd) {
13190Sstevel@tonic-gate 	case I_LINK:
13200Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps)) {
13210Sstevel@tonic-gate 			break;		/* return EINVAL */
13220Sstevel@tonic-gate 		} else if (ppa->ppa_lower_wq != NULL) {
13230Sstevel@tonic-gate 			error = EEXIST;
13240Sstevel@tonic-gate 			break;
13250Sstevel@tonic-gate 		}
13260Sstevel@tonic-gate 		ASSERT(ppa->ppa_ctl != NULL);
13270Sstevel@tonic-gate 		ASSERT(sps->sps_npmode == NPMODE_PASS);
13280Sstevel@tonic-gate 		ASSERT(mp->b_cont != NULL && mp->b_cont->b_rptr != NULL);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 		lwq = ((struct linkblk *)mp->b_cont->b_rptr)->l_qbot;
13310Sstevel@tonic-gate 		ASSERT(lwq != NULL);
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 		ppa->ppa_lower_wq = lwq;
13340Sstevel@tonic-gate 		lwq->q_ptr = RD(lwq)->q_ptr = (caddr_t)ppa;
13350Sstevel@tonic-gate 		/*
13360Sstevel@tonic-gate 		 * Unblock upper network streams which now feed this lower
13370Sstevel@tonic-gate 		 * stream. We don't need to hold ppa_sib_lock here, since we
13380Sstevel@tonic-gate 		 * are writer at the outer perimeter.
13390Sstevel@tonic-gate 		 */
13400Sstevel@tonic-gate 		if (WR(sps->sps_rq)->q_first != NULL)
13410Sstevel@tonic-gate 			qenable(WR(sps->sps_rq));
13420Sstevel@tonic-gate 		for (nextsib = ppa->ppa_streams; nextsib != NULL;
13430Sstevel@tonic-gate 		    nextsib = nextsib->sps_nextsib) {
13440Sstevel@tonic-gate 			nextsib->sps_npmode = NPMODE_PASS;
13450Sstevel@tonic-gate 			if (WR(nextsib->sps_rq)->q_first != NULL) {
13460Sstevel@tonic-gate 				qenable(WR(nextsib->sps_rq));
13470Sstevel@tonic-gate 			}
13480Sstevel@tonic-gate 		}
1349*9751Sjames.d.carlson@sun.com 
1350*9751Sjames.d.carlson@sun.com 		/*
1351*9751Sjames.d.carlson@sun.com 		 * Also unblock (run once) our lower read-side queue.  This is
1352*9751Sjames.d.carlson@sun.com 		 * where packets received while doing the I_LINK may be
1353*9751Sjames.d.carlson@sun.com 		 * languishing; see sppp_lrsrv.
1354*9751Sjames.d.carlson@sun.com 		 */
1355*9751Sjames.d.carlson@sun.com 		qenable(RD(lwq));
1356*9751Sjames.d.carlson@sun.com 
13570Sstevel@tonic-gate 		/*
13580Sstevel@tonic-gate 		 * Send useful information down to the modules which are now
13590Sstevel@tonic-gate 		 * linked below this driver (for this particular ppa). Only
13600Sstevel@tonic-gate 		 * do this if we are not the last PPP module on the stream.
13610Sstevel@tonic-gate 		 */
13620Sstevel@tonic-gate 		if (!IS_PPA_LASTMOD(ppa)) {
13630Sstevel@tonic-gate 			(void) putctl8(lwq, M_CTL, PPPCTL_UNIT,
13640Sstevel@tonic-gate 			    ppa->ppa_ppa_id);
13650Sstevel@tonic-gate 			(void) putctl4(lwq, M_CTL, PPPCTL_MRU, ppa->ppa_mru);
13660Sstevel@tonic-gate 			(void) putctl4(lwq, M_CTL, PPPCTL_MTU, ppa->ppa_mtu);
13670Sstevel@tonic-gate 		}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 		if (IS_SPS_KDEBUG(sps)) {
13700Sstevel@tonic-gate 			SPDEBUG(PPP_DRV_NAME
13710Sstevel@tonic-gate 			    "/%d: I_LINK lwq=0x%p sps=0x%p flags=0x%b ppa=0x%p "
13720Sstevel@tonic-gate 			    "flags=0x%b\n", sps->sps_mn_id,
13730Sstevel@tonic-gate 			    (void *)ppa->ppa_lower_wq, (void *)sps,
13740Sstevel@tonic-gate 			    sps->sps_flags, SPS_FLAGS_STR,
13750Sstevel@tonic-gate 			    (void *)ppa, ppa->ppa_flags,
13760Sstevel@tonic-gate 			    PPA_FLAGS_STR);
13770Sstevel@tonic-gate 		}
13780Sstevel@tonic-gate 		error = 0;		/* return success */
13790Sstevel@tonic-gate 		break;
13800Sstevel@tonic-gate 	case I_UNLINK:
13810Sstevel@tonic-gate 		ASSERT(IS_SPS_CONTROL(sps));
13820Sstevel@tonic-gate 		ASSERT(ppa != NULL);
13830Sstevel@tonic-gate 		lwq = ppa->ppa_lower_wq;
13840Sstevel@tonic-gate 		ASSERT(mp->b_cont != NULL && mp->b_cont->b_rptr != NULL);
13850Sstevel@tonic-gate 		ASSERT(lwq == ((struct linkblk *)mp->b_cont->b_rptr)->l_qbot);
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 		if (IS_SPS_KDEBUG(sps)) {
13880Sstevel@tonic-gate 			SPDEBUG(PPP_DRV_NAME
13890Sstevel@tonic-gate 			    "/%d: I_UNLINK lwq=0x%p sps=0x%p flags=0x%b "
13900Sstevel@tonic-gate 			    "ppa=0x%p flags=0x%b\n", sps->sps_mn_id,
13910Sstevel@tonic-gate 			    (void *)lwq, (void *)sps, sps->sps_flags,
13920Sstevel@tonic-gate 			    SPS_FLAGS_STR, (void *)ppa, ppa->ppa_flags,
13930Sstevel@tonic-gate 			    PPA_FLAGS_STR);
13940Sstevel@tonic-gate 		}
13950Sstevel@tonic-gate 		/*
13960Sstevel@tonic-gate 		 * While accessing the outer perimeter exclusively, we
13970Sstevel@tonic-gate 		 * disassociate our ppa's lower_wq from the lower stream linked
13980Sstevel@tonic-gate 		 * beneath us, and we also disassociate our control stream from
13990Sstevel@tonic-gate 		 * the q_ptr of the lower stream.
14000Sstevel@tonic-gate 		 */
14010Sstevel@tonic-gate 		lwq->q_ptr = RD(lwq)->q_ptr = NULL;
14020Sstevel@tonic-gate 		ppa->ppa_lower_wq = NULL;
14030Sstevel@tonic-gate 		/*
14040Sstevel@tonic-gate 		 * Unblock streams which now feed back up the control stream,
14050Sstevel@tonic-gate 		 * and acknowledge the request. We don't need to hold
14060Sstevel@tonic-gate 		 * ppa_sib_lock here, since we are writer at the outer
14070Sstevel@tonic-gate 		 * perimeter.
14080Sstevel@tonic-gate 		 */
14090Sstevel@tonic-gate 		if (WR(sps->sps_rq)->q_first != NULL)
14100Sstevel@tonic-gate 			qenable(WR(sps->sps_rq));
14110Sstevel@tonic-gate 		for (nextsib = ppa->ppa_streams; nextsib != NULL;
14120Sstevel@tonic-gate 		    nextsib = nextsib->sps_nextsib) {
14130Sstevel@tonic-gate 			if (WR(nextsib->sps_rq)->q_first != NULL) {
14140Sstevel@tonic-gate 				qenable(WR(nextsib->sps_rq));
14150Sstevel@tonic-gate 			}
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 		error = 0;		/* return success */
14180Sstevel@tonic-gate 		break;
14190Sstevel@tonic-gate 	case PPPIO_NEWPPA:
14200Sstevel@tonic-gate 		/*
14210Sstevel@tonic-gate 		 * Do sanity check to ensure that we don't accept PPPIO_NEWPPA
14220Sstevel@tonic-gate 		 * on a stream which DLPI is used (since certain DLPI messages
14230Sstevel@tonic-gate 		 * will cause state transition reflected in sps_dlstate,
14240Sstevel@tonic-gate 		 * changing it from its default DL_UNATTACHED value). In other
14250Sstevel@tonic-gate 		 * words, we won't allow a network/snoop stream to become
14260Sstevel@tonic-gate 		 * a control stream.
14270Sstevel@tonic-gate 		 */
14280Sstevel@tonic-gate 		if (iop->ioc_cr == NULL ||
1429*9751Sjames.d.carlson@sun.com 		    secpolicy_ppp_config(iop->ioc_cr) != 0) {
14300Sstevel@tonic-gate 			error = EPERM;
14310Sstevel@tonic-gate 			break;
14320Sstevel@tonic-gate 		} else if (IS_SPS_CONTROL(sps) || IS_SPS_PIOATTACH(sps) ||
14330Sstevel@tonic-gate 		    (ppa != NULL) || (sps->sps_dlstate != DL_UNATTACHED)) {
14340Sstevel@tonic-gate 			break;		/* return EINVAL */
14350Sstevel@tonic-gate 		}
14360Sstevel@tonic-gate 		/* Get requested unit number (if any) */
14370Sstevel@tonic-gate 		if (iop->ioc_count == sizeof (uint32_t) && mp->b_cont != NULL)
14380Sstevel@tonic-gate 			ppa_id = *(uint32_t *)mp->b_cont->b_rptr;
14390Sstevel@tonic-gate 		else
14400Sstevel@tonic-gate 			ppa_id = 0;
14410Sstevel@tonic-gate 		/* Get mblk to use for response message */
14420Sstevel@tonic-gate 		nmp = allocb(sizeof (uint32_t), BPRI_MED);
14430Sstevel@tonic-gate 		if (nmp == NULL) {
14440Sstevel@tonic-gate 			error = ENOSR;
14450Sstevel@tonic-gate 			break;
14460Sstevel@tonic-gate 		}
14470Sstevel@tonic-gate 		if (mp->b_cont != NULL) {
14480Sstevel@tonic-gate 			freemsg(mp->b_cont);
14490Sstevel@tonic-gate 		}
14500Sstevel@tonic-gate 		mp->b_cont = nmp;		/* chain our response mblk */
14510Sstevel@tonic-gate 		/*
14520Sstevel@tonic-gate 		 * Walk the global ppa list and determine the lowest
14530Sstevel@tonic-gate 		 * available ppa_id number to be used.
14540Sstevel@tonic-gate 		 */
14550Sstevel@tonic-gate 		if (ppa_id == (uint32_t)-1)
14560Sstevel@tonic-gate 			ppa_id = 0;
1457*9751Sjames.d.carlson@sun.com 		zoneid = crgetzoneid(iop->ioc_cr);
14580Sstevel@tonic-gate 		for (ppa = ppa_list; ppa != NULL; ppa = ppa->ppa_nextppa) {
14590Sstevel@tonic-gate 			if (ppa_id == (uint32_t)-2) {
1460*9751Sjames.d.carlson@sun.com 				if (ppa->ppa_ctl == NULL &&
1461*9751Sjames.d.carlson@sun.com 				    ppa->ppa_zoneid == zoneid)
14620Sstevel@tonic-gate 					break;
14630Sstevel@tonic-gate 			} else {
14640Sstevel@tonic-gate 				if (ppa_id < ppa->ppa_ppa_id)
14650Sstevel@tonic-gate 					break;
14660Sstevel@tonic-gate 				if (ppa_id == ppa->ppa_ppa_id)
14670Sstevel@tonic-gate 					++ppa_id;
14680Sstevel@tonic-gate 			}
14690Sstevel@tonic-gate 		}
14700Sstevel@tonic-gate 		if (ppa_id == (uint32_t)-2) {
14710Sstevel@tonic-gate 			if (ppa == NULL) {
14720Sstevel@tonic-gate 				error = ENXIO;
14730Sstevel@tonic-gate 				break;
14740Sstevel@tonic-gate 			}
14750Sstevel@tonic-gate 			/* Clear timestamp and lastmod flags */
14760Sstevel@tonic-gate 			ppa->ppa_flags = 0;
14770Sstevel@tonic-gate 		} else {
1478*9751Sjames.d.carlson@sun.com 			ppa = sppp_create_ppa(ppa_id, zoneid);
14790Sstevel@tonic-gate 			if (ppa == NULL) {
14800Sstevel@tonic-gate 				error = ENOMEM;
14810Sstevel@tonic-gate 				break;
14820Sstevel@tonic-gate 			}
14830Sstevel@tonic-gate 		}
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 		sps->sps_ppa = ppa;		/* chain the ppa structure */
14860Sstevel@tonic-gate 		sps->sps_npmode = NPMODE_PASS;	/* network packets may travel */
14870Sstevel@tonic-gate 		sps->sps_flags |= SPS_CONTROL;	/* this is the control stream */
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 		ppa->ppa_refcnt++;		/* new PPA reference */
14900Sstevel@tonic-gate 		ppa->ppa_ctl = sps;		/* back ptr to upper stream */
14910Sstevel@tonic-gate 		/*
14920Sstevel@tonic-gate 		 * Return the newly created ppa_id to the requestor and
14930Sstevel@tonic-gate 		 * acnowledge the request.
14940Sstevel@tonic-gate 		 */
14950Sstevel@tonic-gate 		*(uint32_t *)nmp->b_wptr = ppa->ppa_ppa_id;
14960Sstevel@tonic-gate 		nmp->b_wptr += sizeof (uint32_t);
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 		if (IS_SPS_KDEBUG(sps)) {
14990Sstevel@tonic-gate 			SPDEBUG(PPP_DRV_NAME
15000Sstevel@tonic-gate 			    "/%d: PPPIO_NEWPPA ppa_id=%d sps=0x%p flags=0x%b "
15010Sstevel@tonic-gate 			    "ppa=0x%p flags=0x%b\n", sps->sps_mn_id, ppa_id,
15020Sstevel@tonic-gate 			    (void *)sps, sps->sps_flags, SPS_FLAGS_STR,
15030Sstevel@tonic-gate 			    (void *)ppa, ppa->ppa_flags,
15040Sstevel@tonic-gate 			    PPA_FLAGS_STR);
15050Sstevel@tonic-gate 		}
15060Sstevel@tonic-gate 		count = msgsize(nmp);
15070Sstevel@tonic-gate 		error = 0;
15080Sstevel@tonic-gate 		break;
15090Sstevel@tonic-gate 	}
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	if (error == 0) {
15120Sstevel@tonic-gate 		/* Success; tell the user. */
15130Sstevel@tonic-gate 		miocack(q, mp, count, 0);
15140Sstevel@tonic-gate 	} else {
15150Sstevel@tonic-gate 		/* Failure; send error back upstream. */
15160Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
15170Sstevel@tonic-gate 	}
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate /*
15210Sstevel@tonic-gate  * sppp_send()
15220Sstevel@tonic-gate  *
15230Sstevel@tonic-gate  * MT-Perimeters:
15240Sstevel@tonic-gate  *    shared inner, shared outer.
15250Sstevel@tonic-gate  *
15260Sstevel@tonic-gate  * Description:
15270Sstevel@tonic-gate  *    Called by sppp_uwput to handle M_DATA message type.  Returns
15280Sstevel@tonic-gate  *    queue_t for putnext, or NULL to mean that the packet was
15290Sstevel@tonic-gate  *    handled internally.
15300Sstevel@tonic-gate  */
15310Sstevel@tonic-gate static queue_t *
sppp_send(queue_t * q,mblk_t ** mpp,spppstr_t * sps)15320Sstevel@tonic-gate sppp_send(queue_t *q, mblk_t **mpp, spppstr_t *sps)
15330Sstevel@tonic-gate {
15340Sstevel@tonic-gate 	mblk_t	*mp;
15350Sstevel@tonic-gate 	sppa_t	*ppa;
15360Sstevel@tonic-gate 	int	is_promisc;
15370Sstevel@tonic-gate 	int	msize;
15380Sstevel@tonic-gate 	int	error = 0;
15390Sstevel@tonic-gate 	queue_t	*nextq;
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	ASSERT(mpp != NULL);
15420Sstevel@tonic-gate 	mp = *mpp;
15430Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
15440Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
15450Sstevel@tonic-gate 	ASSERT(sps != NULL);
15460Sstevel@tonic-gate 	ASSERT(q->q_ptr == sps);
15470Sstevel@tonic-gate 	/*
15480Sstevel@tonic-gate 	 * We only let M_DATA through if the sender is either the control
15490Sstevel@tonic-gate 	 * stream (for PPP control packets) or one of the network streams
15500Sstevel@tonic-gate 	 * (for IP packets) in IP fastpath mode. If this stream is not attached
15510Sstevel@tonic-gate 	 * to any ppas, then discard data coming down through this stream.
15520Sstevel@tonic-gate 	 */
15530Sstevel@tonic-gate 	ppa = sps->sps_ppa;
15540Sstevel@tonic-gate 	if (ppa == NULL) {
15550Sstevel@tonic-gate 		ASSERT(!IS_SPS_CONTROL(sps));
15560Sstevel@tonic-gate 		error = ENOLINK;
15570Sstevel@tonic-gate 	} else if (!IS_SPS_CONTROL(sps) && !IS_SPS_FASTPATH(sps)) {
15580Sstevel@tonic-gate 		error = EPROTO;
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 	if (error != 0) {
15610Sstevel@tonic-gate 		merror(q, mp, error);
15620Sstevel@tonic-gate 		return (NULL);
15630Sstevel@tonic-gate 	}
15640Sstevel@tonic-gate 	msize = msgdsize(mp);
15650Sstevel@tonic-gate 	if (msize > (ppa->ppa_mtu + PPP_HDRLEN)) {
15660Sstevel@tonic-gate 		/* Log, and send it anyway */
15670Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
15680Sstevel@tonic-gate 		ppa->ppa_otoolongs++;
15690Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
15700Sstevel@tonic-gate 	} else if (msize < PPP_HDRLEN) {
15710Sstevel@tonic-gate 		/*
15720Sstevel@tonic-gate 		 * Log, and send it anyway. We log it because we get things
15730Sstevel@tonic-gate 		 * in M_DATA form here, which tells us that the sender is
15740Sstevel@tonic-gate 		 * either IP in fastpath transmission mode, or pppd. In both
15750Sstevel@tonic-gate 		 * cases, they are currently expected to send the 4-bytes
15760Sstevel@tonic-gate 		 * PPP header in front of any possible payloads.
15770Sstevel@tonic-gate 		 */
15780Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
15790Sstevel@tonic-gate 		ppa->ppa_orunts++;
15800Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
15810Sstevel@tonic-gate 	}
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	if (IS_SPS_KDEBUG(sps)) {
15840Sstevel@tonic-gate 		SPDEBUG(PPP_DRV_NAME
15850Sstevel@tonic-gate 		    "/%d: M_DATA send (%d bytes) sps=0x%p flags=0x%b "
15860Sstevel@tonic-gate 		    "ppa=0x%p flags=0x%b\n", sps->sps_mn_id, msize,
15870Sstevel@tonic-gate 		    (void *)sps, sps->sps_flags, SPS_FLAGS_STR,
15880Sstevel@tonic-gate 		    (void *)ppa, ppa->ppa_flags, PPA_FLAGS_STR);
15890Sstevel@tonic-gate 	}
15900Sstevel@tonic-gate 	/*
15910Sstevel@tonic-gate 	 * Should there be any promiscuous stream(s), send the data up
15920Sstevel@tonic-gate 	 * for each promiscuous stream that we recognize. Make sure that
15930Sstevel@tonic-gate 	 * for fastpath, we skip the PPP header in the M_DATA mblk. We skip
15940Sstevel@tonic-gate 	 * the control stream as we obviously never allow the control stream
15950Sstevel@tonic-gate 	 * to become promiscous and bind to PPP_ALLSAP.
15960Sstevel@tonic-gate 	 */
15970Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_READER);
15980Sstevel@tonic-gate 	is_promisc = sps->sps_ppa->ppa_promicnt;
15990Sstevel@tonic-gate 	if (is_promisc) {
16000Sstevel@tonic-gate 		ASSERT(ppa->ppa_streams != NULL);
16010Sstevel@tonic-gate 		sppp_dlprsendup(ppa->ppa_streams, mp, sps->sps_sap, B_TRUE);
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
16040Sstevel@tonic-gate 	/*
16050Sstevel@tonic-gate 	 * Only time-stamp the packet with hrtime if the upper stream
16060Sstevel@tonic-gate 	 * is configured to do so.  PPP control (negotiation) messages
16070Sstevel@tonic-gate 	 * are never considered link activity; only data is activity.
16080Sstevel@tonic-gate 	 */
16090Sstevel@tonic-gate 	if (!IS_SPS_CONTROL(sps) && IS_PPA_TIMESTAMP(ppa)) {
16100Sstevel@tonic-gate 		ppa->ppa_lasttx = gethrtime();
16110Sstevel@tonic-gate 	}
16120Sstevel@tonic-gate 	/*
16130Sstevel@tonic-gate 	 * If there's already a message in the write-side service queue,
16140Sstevel@tonic-gate 	 * then queue this message there as well, otherwise, try to send
16150Sstevel@tonic-gate 	 * it down to the module immediately below us.
16160Sstevel@tonic-gate 	 */
16170Sstevel@tonic-gate 	if (q->q_first != NULL ||
16180Sstevel@tonic-gate 	    (nextq = sppp_outpkt(q, mpp, msize, sps)) == NULL) {
16190Sstevel@tonic-gate 		mp = *mpp;
16200Sstevel@tonic-gate 		if (mp != NULL && putq(q, mp) == 0) {
16210Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
16220Sstevel@tonic-gate 			ppa->ppa_oqdropped++;
16230Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
16240Sstevel@tonic-gate 			freemsg(mp);
16250Sstevel@tonic-gate 		}
16260Sstevel@tonic-gate 		return (NULL);
16270Sstevel@tonic-gate 	}
16280Sstevel@tonic-gate 	return (nextq);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate /*
16320Sstevel@tonic-gate  * sppp_outpkt()
16330Sstevel@tonic-gate  *
16340Sstevel@tonic-gate  * MT-Perimeters:
16350Sstevel@tonic-gate  *    shared inner, shared outer (if called from sppp_wput, sppp_dlunitdatareq).
16360Sstevel@tonic-gate  *    exclusive inner, shared outer (if called from sppp_wsrv).
16370Sstevel@tonic-gate  *
16380Sstevel@tonic-gate  * Description:
16390Sstevel@tonic-gate  *    Called from 1) sppp_uwput when processing a M_DATA fastpath message,
16400Sstevel@tonic-gate  *    or 2) sppp_uwsrv when processing the upper write-side service queue.
16410Sstevel@tonic-gate  *    For both cases, it prepares to send the data to the module below
16420Sstevel@tonic-gate  *    this driver if there is a lower stream linked underneath. If none, then
16430Sstevel@tonic-gate  *    the data will be sent upstream via the control channel to pppd.
16440Sstevel@tonic-gate  *
16450Sstevel@tonic-gate  * Returns:
16460Sstevel@tonic-gate  *	Non-NULL queue_t if message should be sent now, otherwise
16470Sstevel@tonic-gate  *	if *mpp == NULL, then message was freed, otherwise put *mpp
16480Sstevel@tonic-gate  *	(back) on the queue.  (Does not do putq/putbq, since it's
16490Sstevel@tonic-gate  *	called both from srv and put procedures.)
16500Sstevel@tonic-gate  */
16510Sstevel@tonic-gate static queue_t *
sppp_outpkt(queue_t * q,mblk_t ** mpp,int msize,spppstr_t * sps)16520Sstevel@tonic-gate sppp_outpkt(queue_t *q, mblk_t **mpp, int msize, spppstr_t *sps)
16530Sstevel@tonic-gate {
16540Sstevel@tonic-gate 	mblk_t		*mp;
16550Sstevel@tonic-gate 	sppa_t		*ppa;
16560Sstevel@tonic-gate 	enum NPmode	npmode;
16570Sstevel@tonic-gate 	mblk_t		*mpnew;
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	ASSERT(mpp != NULL);
16600Sstevel@tonic-gate 	mp = *mpp;
16610Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
16620Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
16630Sstevel@tonic-gate 	ASSERT(sps != NULL);
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	ppa = sps->sps_ppa;
16660Sstevel@tonic-gate 	npmode = sps->sps_npmode;
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	if (npmode == NPMODE_QUEUE) {
16690Sstevel@tonic-gate 		ASSERT(!IS_SPS_CONTROL(sps));
16700Sstevel@tonic-gate 		return (NULL);	/* queue it for later */
16710Sstevel@tonic-gate 	} else if (ppa == NULL || ppa->ppa_ctl == NULL ||
16720Sstevel@tonic-gate 	    npmode == NPMODE_DROP || npmode == NPMODE_ERROR) {
16730Sstevel@tonic-gate 		/*
16740Sstevel@tonic-gate 		 * This can not be the control stream, as it must always have
16750Sstevel@tonic-gate 		 * a valid ppa, and its npmode must always be NPMODE_PASS.
16760Sstevel@tonic-gate 		 */
16770Sstevel@tonic-gate 		ASSERT(!IS_SPS_CONTROL(sps));
16780Sstevel@tonic-gate 		if (npmode == NPMODE_DROP) {
16790Sstevel@tonic-gate 			freemsg(mp);
16800Sstevel@tonic-gate 		} else {
16810Sstevel@tonic-gate 			/*
16820Sstevel@tonic-gate 			 * If we no longer have the control stream, or if the
16830Sstevel@tonic-gate 			 * mode is set to NPMODE_ERROR, then we need to tell IP
16840Sstevel@tonic-gate 			 * that the interface need to be marked as down. In
16850Sstevel@tonic-gate 			 * other words, we tell IP to be quiescent.
16860Sstevel@tonic-gate 			 */
16870Sstevel@tonic-gate 			merror(q, mp, EPROTO);
16880Sstevel@tonic-gate 		}
16890Sstevel@tonic-gate 		*mpp = NULL;
16900Sstevel@tonic-gate 		return (NULL);	/* don't queue it */
16910Sstevel@tonic-gate 	}
16920Sstevel@tonic-gate 	/*
16930Sstevel@tonic-gate 	 * Do we have a driver stream linked underneath ? If not, we need to
16940Sstevel@tonic-gate 	 * notify pppd that the link needs to be brought up and configure
16950Sstevel@tonic-gate 	 * this upper stream to drop subsequent outgoing packets. This is
16960Sstevel@tonic-gate 	 * for demand-dialing, in which case pppd has done the IP plumbing
16970Sstevel@tonic-gate 	 * but hasn't linked the driver stream underneath us. Therefore, when
16980Sstevel@tonic-gate 	 * a packet is sent down the IP interface, a notification message
16990Sstevel@tonic-gate 	 * will be sent up the control stream to pppd in order for it to
17000Sstevel@tonic-gate 	 * establish the physical link. The driver stream is then expected
17010Sstevel@tonic-gate 	 * to be linked underneath after physical link establishment is done.
17020Sstevel@tonic-gate 	 */
17030Sstevel@tonic-gate 	if (ppa->ppa_lower_wq == NULL) {
17040Sstevel@tonic-gate 		ASSERT(ppa->ppa_ctl != NULL);
17050Sstevel@tonic-gate 		ASSERT(ppa->ppa_ctl->sps_rq != NULL);
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 		*mpp = NULL;
17080Sstevel@tonic-gate 		mpnew = create_lsmsg(PPP_LINKSTAT_NEEDUP);
17090Sstevel@tonic-gate 		if (mpnew == NULL) {
17100Sstevel@tonic-gate 			freemsg(mp);
17110Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
17120Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
17130Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
17140Sstevel@tonic-gate 			return (NULL);	/* don't queue it */
17150Sstevel@tonic-gate 		}
17160Sstevel@tonic-gate 		/* Include the data in the message for logging. */
17170Sstevel@tonic-gate 		mpnew->b_cont = mp;
17180Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
17190Sstevel@tonic-gate 		ppa->ppa_lsneedup++;
17200Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
17210Sstevel@tonic-gate 		/*
17220Sstevel@tonic-gate 		 * We need to set the mode to NPMODE_DROP, but should only
17230Sstevel@tonic-gate 		 * do so when this stream is not the control stream.
17240Sstevel@tonic-gate 		 */
17250Sstevel@tonic-gate 		if (!IS_SPS_CONTROL(sps)) {
17260Sstevel@tonic-gate 			sps->sps_npmode = NPMODE_DROP;
17270Sstevel@tonic-gate 		}
17280Sstevel@tonic-gate 		putnext(ppa->ppa_ctl->sps_rq, mpnew);
17290Sstevel@tonic-gate 		return (NULL);	/* don't queue it */
17300Sstevel@tonic-gate 	}
17310Sstevel@tonic-gate 	/*
17320Sstevel@tonic-gate 	 * If so, then try to send it down. The lower queue is only ever
17330Sstevel@tonic-gate 	 * detached while holding an exclusive lock on the whole driver,
17340Sstevel@tonic-gate 	 * so we can be confident that the lower queue is still there.
17350Sstevel@tonic-gate 	 */
17360Sstevel@tonic-gate 	if (bcanputnext(ppa->ppa_lower_wq, mp->b_band)) {
17370Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
17380Sstevel@tonic-gate 		ppa->ppa_stats.p.ppp_opackets++;
17390Sstevel@tonic-gate 		if (IS_SPS_CONTROL(sps)) {
17400Sstevel@tonic-gate 			ppa->ppa_opkt_ctl++;
17410Sstevel@tonic-gate 		}
17420Sstevel@tonic-gate 		ppa->ppa_stats.p.ppp_obytes += msize;
17430Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
17440Sstevel@tonic-gate 		return (ppa->ppa_lower_wq);	/* don't queue it */
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate 	return (NULL);	/* queue it for later */
17470Sstevel@tonic-gate }
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate /*
17500Sstevel@tonic-gate  * sppp_lwsrv()
17510Sstevel@tonic-gate  *
17520Sstevel@tonic-gate  * MT-Perimeters:
17530Sstevel@tonic-gate  *    exclusive inner, shared outer.
17540Sstevel@tonic-gate  *
17550Sstevel@tonic-gate  * Description:
17560Sstevel@tonic-gate  *    Lower write-side service procedure. No messages are ever placed on
17570Sstevel@tonic-gate  *    the write queue here, this just back-enables all upper write side
17580Sstevel@tonic-gate  *    service procedures.
17590Sstevel@tonic-gate  */
17605640Scarlsonj void
sppp_lwsrv(queue_t * q)17610Sstevel@tonic-gate sppp_lwsrv(queue_t *q)
17620Sstevel@tonic-gate {
17630Sstevel@tonic-gate 	sppa_t		*ppa;
17640Sstevel@tonic-gate 	spppstr_t	*nextsib;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
17670Sstevel@tonic-gate 	ppa = (sppa_t *)q->q_ptr;
17680Sstevel@tonic-gate 	ASSERT(ppa != NULL);
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_READER);
17710Sstevel@tonic-gate 	if ((nextsib = ppa->ppa_ctl) != NULL &&
17720Sstevel@tonic-gate 	    WR(nextsib->sps_rq)->q_first != NULL)
17730Sstevel@tonic-gate 		qenable(WR(nextsib->sps_rq));
17740Sstevel@tonic-gate 	for (nextsib = ppa->ppa_streams; nextsib != NULL;
17750Sstevel@tonic-gate 	    nextsib = nextsib->sps_nextsib) {
17760Sstevel@tonic-gate 		if (WR(nextsib->sps_rq)->q_first != NULL) {
17770Sstevel@tonic-gate 			qenable(WR(nextsib->sps_rq));
17780Sstevel@tonic-gate 		}
17790Sstevel@tonic-gate 	}
17800Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate /*
17840Sstevel@tonic-gate  * sppp_lrput()
17850Sstevel@tonic-gate  *
17860Sstevel@tonic-gate  * MT-Perimeters:
17870Sstevel@tonic-gate  *    shared inner, shared outer.
17880Sstevel@tonic-gate  *
17890Sstevel@tonic-gate  * Description:
17900Sstevel@tonic-gate  *    Lower read-side put procedure. Messages from below get here.
17910Sstevel@tonic-gate  *    Data messages are handled separately to limit stack usage
17920Sstevel@tonic-gate  *    going into IP.
17935640Scarlsonj  *
17945640Scarlsonj  *    Note that during I_UNLINK processing, it's possible for a downstream
17955640Scarlsonj  *    message to enable upstream data (due to pass_wput() removing the
17965640Scarlsonj  *    SQ_BLOCKED flag), and thus we must protect against a NULL sppa pointer.
17975640Scarlsonj  *    In this case, the only thing above us is passthru, and we might as well
17985640Scarlsonj  *    discard.
17990Sstevel@tonic-gate  */
18005640Scarlsonj void
sppp_lrput(queue_t * q,mblk_t * mp)18010Sstevel@tonic-gate sppp_lrput(queue_t *q, mblk_t *mp)
18020Sstevel@tonic-gate {
18030Sstevel@tonic-gate 	sppa_t		*ppa;
18040Sstevel@tonic-gate 	spppstr_t	*sps;
18050Sstevel@tonic-gate 
18065640Scarlsonj 	if ((ppa = q->q_ptr) == NULL) {
18075640Scarlsonj 		freemsg(mp);
18085640Scarlsonj 		return;
18095640Scarlsonj 	}
18105640Scarlsonj 
18110Sstevel@tonic-gate 	sps = ppa->ppa_ctl;
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	if (MTYPE(mp) != M_DATA) {
18140Sstevel@tonic-gate 		sppp_recv_nondata(q, mp, sps);
18150Sstevel@tonic-gate 	} else if (sps == NULL) {
18160Sstevel@tonic-gate 		freemsg(mp);
18170Sstevel@tonic-gate 	} else if ((q = sppp_recv(q, &mp, sps)) != NULL) {
18180Sstevel@tonic-gate 		putnext(q, mp);
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate }
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate /*
1823*9751Sjames.d.carlson@sun.com  * sppp_lrsrv()
1824*9751Sjames.d.carlson@sun.com  *
1825*9751Sjames.d.carlson@sun.com  * MT-Perimeters:
1826*9751Sjames.d.carlson@sun.com  *    exclusive inner, shared outer.
1827*9751Sjames.d.carlson@sun.com  *
1828*9751Sjames.d.carlson@sun.com  * Description:
1829*9751Sjames.d.carlson@sun.com  *    Lower read-side service procedure.  This is run once after the I_LINK
1830*9751Sjames.d.carlson@sun.com  *    occurs in order to clean up any packets that came in while we were
1831*9751Sjames.d.carlson@sun.com  *    transferring in the lower stream.  Otherwise, it's not used.
1832*9751Sjames.d.carlson@sun.com  */
1833*9751Sjames.d.carlson@sun.com void
sppp_lrsrv(queue_t * q)1834*9751Sjames.d.carlson@sun.com sppp_lrsrv(queue_t *q)
1835*9751Sjames.d.carlson@sun.com {
1836*9751Sjames.d.carlson@sun.com 	mblk_t *mp;
1837*9751Sjames.d.carlson@sun.com 
1838*9751Sjames.d.carlson@sun.com 	while ((mp = getq(q)) != NULL)
1839*9751Sjames.d.carlson@sun.com 		sppp_lrput(q, mp);
1840*9751Sjames.d.carlson@sun.com }
1841*9751Sjames.d.carlson@sun.com 
1842*9751Sjames.d.carlson@sun.com /*
18430Sstevel@tonic-gate  * sppp_recv_nondata()
18440Sstevel@tonic-gate  *
18450Sstevel@tonic-gate  * MT-Perimeters:
18460Sstevel@tonic-gate  *    shared inner, shared outer.
18470Sstevel@tonic-gate  *
18480Sstevel@tonic-gate  * Description:
18490Sstevel@tonic-gate  *    All received non-data messages come through here.
18500Sstevel@tonic-gate  */
18510Sstevel@tonic-gate static void
sppp_recv_nondata(queue_t * q,mblk_t * mp,spppstr_t * ctlsps)18520Sstevel@tonic-gate sppp_recv_nondata(queue_t *q, mblk_t *mp, spppstr_t *ctlsps)
18530Sstevel@tonic-gate {
18540Sstevel@tonic-gate 	sppa_t		*ppa;
18550Sstevel@tonic-gate 	spppstr_t	*destsps;
18560Sstevel@tonic-gate 	struct iocblk	*iop;
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 	ppa = (sppa_t *)q->q_ptr;
18590Sstevel@tonic-gate 	ctlsps = ppa->ppa_ctl;
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	switch (MTYPE(mp)) {
18620Sstevel@tonic-gate 	case M_CTL:
18630Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
18640Sstevel@tonic-gate 		if (*mp->b_rptr == PPPCTL_IERROR) {
18650Sstevel@tonic-gate 			ppa->ppa_stats.p.ppp_ierrors++;
18660Sstevel@tonic-gate 			ppa->ppa_ierr_low++;
18670Sstevel@tonic-gate 			ppa->ppa_mctlsknown++;
18680Sstevel@tonic-gate 		} else if (*mp->b_rptr == PPPCTL_OERROR) {
18690Sstevel@tonic-gate 			ppa->ppa_stats.p.ppp_oerrors++;
18700Sstevel@tonic-gate 			ppa->ppa_oerr_low++;
18710Sstevel@tonic-gate 			ppa->ppa_mctlsknown++;
18720Sstevel@tonic-gate 		} else {
18730Sstevel@tonic-gate 			ppa->ppa_mctlsunknown++;
18740Sstevel@tonic-gate 		}
18750Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
18760Sstevel@tonic-gate 		freemsg(mp);
18770Sstevel@tonic-gate 		break;
18780Sstevel@tonic-gate 	case M_IOCTL:
18790Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
18800Sstevel@tonic-gate 		break;
18810Sstevel@tonic-gate 	case M_IOCACK:
18820Sstevel@tonic-gate 	case M_IOCNAK:
18830Sstevel@tonic-gate 		iop = (struct iocblk *)mp->b_rptr;
18840Sstevel@tonic-gate 		ASSERT(iop != NULL);
18850Sstevel@tonic-gate 		/*
18860Sstevel@tonic-gate 		 * Attempt to match up the response with the stream that the
18870Sstevel@tonic-gate 		 * request came from. If ioc_id doesn't match the one that we
18880Sstevel@tonic-gate 		 * recorded, then discard this message.
18890Sstevel@tonic-gate 		 */
18900Sstevel@tonic-gate 		rw_enter(&ppa->ppa_sib_lock, RW_READER);
18910Sstevel@tonic-gate 		if ((destsps = ctlsps) == NULL ||
18920Sstevel@tonic-gate 		    destsps->sps_ioc_id != iop->ioc_id) {
18930Sstevel@tonic-gate 			destsps = ppa->ppa_streams;
18940Sstevel@tonic-gate 			while (destsps != NULL) {
18950Sstevel@tonic-gate 				if (destsps->sps_ioc_id == iop->ioc_id) {
18960Sstevel@tonic-gate 					break;	/* found the upper stream */
18970Sstevel@tonic-gate 				}
18980Sstevel@tonic-gate 				destsps = destsps->sps_nextsib;
18990Sstevel@tonic-gate 			}
19000Sstevel@tonic-gate 		}
19010Sstevel@tonic-gate 		rw_exit(&ppa->ppa_sib_lock);
19020Sstevel@tonic-gate 		if (destsps == NULL) {
19030Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
19040Sstevel@tonic-gate 			ppa->ppa_ioctlsfwderr++;
19050Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
19060Sstevel@tonic-gate 			freemsg(mp);
19070Sstevel@tonic-gate 			break;
19080Sstevel@tonic-gate 		}
19090Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
19100Sstevel@tonic-gate 		ppa->ppa_ioctlsfwdok++;
19117643Sanil.udupa@sun.com 
19127643Sanil.udupa@sun.com 		/*
19137643Sanil.udupa@sun.com 		 * Clear SPS_IOCQ and enable the lower write side queue,
19147643Sanil.udupa@sun.com 		 * this would allow the upper stream service routine
19157643Sanil.udupa@sun.com 		 * to start processing the queue for pending messages.
19167643Sanil.udupa@sun.com 		 * sppp_lwsrv -> sppp_uwsrv.
19177643Sanil.udupa@sun.com 		 */
19187643Sanil.udupa@sun.com 		destsps->sps_flags &= ~SPS_IOCQ;
19190Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
19207643Sanil.udupa@sun.com 		qenable(WR(destsps->sps_rq));
19217643Sanil.udupa@sun.com 
19220Sstevel@tonic-gate 		putnext(destsps->sps_rq, mp);
19230Sstevel@tonic-gate 		break;
19240Sstevel@tonic-gate 	case M_HANGUP:
19250Sstevel@tonic-gate 		/*
19260Sstevel@tonic-gate 		 * Free the original mblk_t. We don't really want to send
19270Sstevel@tonic-gate 		 * a M_HANGUP message upstream, so we need to translate this
19280Sstevel@tonic-gate 		 * message into something else.
19290Sstevel@tonic-gate 		 */
19300Sstevel@tonic-gate 		freemsg(mp);
19310Sstevel@tonic-gate 		if (ctlsps == NULL)
19320Sstevel@tonic-gate 			break;
19330Sstevel@tonic-gate 		mp = create_lsmsg(PPP_LINKSTAT_HANGUP);
19340Sstevel@tonic-gate 		if (mp == NULL) {
19350Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
19360Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
19370Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
19380Sstevel@tonic-gate 			break;
19390Sstevel@tonic-gate 		}
19400Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
19410Sstevel@tonic-gate 		ppa->ppa_lsdown++;
19420Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
19430Sstevel@tonic-gate 		putnext(ctlsps->sps_rq, mp);
19440Sstevel@tonic-gate 		break;
19450Sstevel@tonic-gate 	case M_FLUSH:
19460Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
19470Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
19480Sstevel@tonic-gate 		}
19490Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
19500Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHR;
19510Sstevel@tonic-gate 			qreply(q, mp);
19520Sstevel@tonic-gate 		} else {
19530Sstevel@tonic-gate 			freemsg(mp);
19540Sstevel@tonic-gate 		}
19550Sstevel@tonic-gate 		break;
19560Sstevel@tonic-gate 	default:
19570Sstevel@tonic-gate 		if (ctlsps != NULL &&
19580Sstevel@tonic-gate 		    (queclass(mp) == QPCTL) || canputnext(ctlsps->sps_rq)) {
19590Sstevel@tonic-gate 			putnext(ctlsps->sps_rq, mp);
19600Sstevel@tonic-gate 		} else {
19610Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
19620Sstevel@tonic-gate 			ppa->ppa_iqdropped++;
19630Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
19640Sstevel@tonic-gate 			freemsg(mp);
19650Sstevel@tonic-gate 		}
19660Sstevel@tonic-gate 		break;
19670Sstevel@tonic-gate 	}
19680Sstevel@tonic-gate }
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate /*
19710Sstevel@tonic-gate  * sppp_recv()
19720Sstevel@tonic-gate  *
19730Sstevel@tonic-gate  * MT-Perimeters:
19740Sstevel@tonic-gate  *    shared inner, shared outer.
19750Sstevel@tonic-gate  *
19760Sstevel@tonic-gate  * Description:
19770Sstevel@tonic-gate  *    Receive function called by sppp_lrput.  Finds appropriate
19780Sstevel@tonic-gate  *    receive stream and does accounting.
19790Sstevel@tonic-gate  */
19800Sstevel@tonic-gate static queue_t *
sppp_recv(queue_t * q,mblk_t ** mpp,spppstr_t * ctlsps)19810Sstevel@tonic-gate sppp_recv(queue_t *q, mblk_t **mpp, spppstr_t *ctlsps)
19820Sstevel@tonic-gate {
19830Sstevel@tonic-gate 	mblk_t		*mp;
19840Sstevel@tonic-gate 	int		len;
19850Sstevel@tonic-gate 	sppa_t		*ppa;
19860Sstevel@tonic-gate 	spppstr_t	*destsps;
19870Sstevel@tonic-gate 	mblk_t		*zmp;
19880Sstevel@tonic-gate 	uint32_t	npflagpos;
19890Sstevel@tonic-gate 
19900Sstevel@tonic-gate 	ASSERT(mpp != NULL);
19910Sstevel@tonic-gate 	mp = *mpp;
19920Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
19930Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
19940Sstevel@tonic-gate 	ASSERT(ctlsps != NULL);
19950Sstevel@tonic-gate 	ASSERT(IS_SPS_CONTROL(ctlsps));
19960Sstevel@tonic-gate 	ppa = ctlsps->sps_ppa;
19970Sstevel@tonic-gate 	ASSERT(ppa != NULL && ppa->ppa_ctl != NULL);
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	len = msgdsize(mp);
20000Sstevel@tonic-gate 	mutex_enter(&ppa->ppa_sta_lock);
20010Sstevel@tonic-gate 	ppa->ppa_stats.p.ppp_ibytes += len;
20020Sstevel@tonic-gate 	mutex_exit(&ppa->ppa_sta_lock);
20030Sstevel@tonic-gate 	/*
20040Sstevel@tonic-gate 	 * If the entire data size of the mblk is less than the length of the
20050Sstevel@tonic-gate 	 * PPP header, then free it. We can't do much with such message anyway,
20060Sstevel@tonic-gate 	 * since we can't really determine what the PPP protocol type is.
20070Sstevel@tonic-gate 	 */
20080Sstevel@tonic-gate 	if (len < PPP_HDRLEN) {
20090Sstevel@tonic-gate 		/* Log, and free it */
20100Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
20110Sstevel@tonic-gate 		ppa->ppa_irunts++;
20120Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
20130Sstevel@tonic-gate 		freemsg(mp);
20140Sstevel@tonic-gate 		return (NULL);
20150Sstevel@tonic-gate 	} else if (len > (ppa->ppa_mru + PPP_HDRLEN)) {
20160Sstevel@tonic-gate 		/* Log, and accept it anyway */
20170Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
20180Sstevel@tonic-gate 		ppa->ppa_itoolongs++;
20190Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
20200Sstevel@tonic-gate 	}
20210Sstevel@tonic-gate 	/*
20220Sstevel@tonic-gate 	 * We need at least be able to read the PPP protocol from the header,
20230Sstevel@tonic-gate 	 * so if the first message block is too small, then we concatenate the
20240Sstevel@tonic-gate 	 * rest of the following blocks into one message.
20250Sstevel@tonic-gate 	 */
20260Sstevel@tonic-gate 	if (MBLKL(mp) < PPP_HDRLEN) {
20270Sstevel@tonic-gate 		zmp = msgpullup(mp, PPP_HDRLEN);
20280Sstevel@tonic-gate 		freemsg(mp);
20290Sstevel@tonic-gate 		mp = zmp;
20300Sstevel@tonic-gate 		if (mp == NULL) {
20310Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
20320Sstevel@tonic-gate 			ppa->ppa_allocbfail++;
20330Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
20340Sstevel@tonic-gate 			return (NULL);
20350Sstevel@tonic-gate 		}
20360Sstevel@tonic-gate 		*mpp = mp;
20370Sstevel@tonic-gate 	}
20380Sstevel@tonic-gate 	/*
20390Sstevel@tonic-gate 	 * Hold this packet in the control-queue until
20400Sstevel@tonic-gate 	 * the matching network-layer upper stream for the PPP protocol (sap)
20410Sstevel@tonic-gate 	 * has not been plumbed and configured
20420Sstevel@tonic-gate 	 */
20430Sstevel@tonic-gate 	npflagpos = sppp_ppp2np(PPP_PROTOCOL(mp->b_rptr));
20440Sstevel@tonic-gate 	mutex_enter(&ppa->ppa_npmutex);
20450Sstevel@tonic-gate 	if (npflagpos != 0 && (ppa->ppa_npflag & (1 << npflagpos))) {
20460Sstevel@tonic-gate 		/*
20470Sstevel@tonic-gate 		 * proto is currently blocked; Hold up to 4 packets
20480Sstevel@tonic-gate 		 * in the kernel.
20490Sstevel@tonic-gate 		 */
20500Sstevel@tonic-gate 		if (ppa->ppa_holdpkts[npflagpos] > 3 ||
20510Sstevel@tonic-gate 		    putq(ctlsps->sps_rq, mp) == 0)
20520Sstevel@tonic-gate 			freemsg(mp);
20530Sstevel@tonic-gate 		else
20540Sstevel@tonic-gate 			ppa->ppa_holdpkts[npflagpos]++;
20550Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_npmutex);
20560Sstevel@tonic-gate 		return (NULL);
20570Sstevel@tonic-gate 	}
20580Sstevel@tonic-gate 	mutex_exit(&ppa->ppa_npmutex);
20590Sstevel@tonic-gate 	/*
20600Sstevel@tonic-gate 	 * Try to find a matching network-layer upper stream for the specified
20610Sstevel@tonic-gate 	 * PPP protocol (sap), and if none is found, send this frame up the
20620Sstevel@tonic-gate 	 * control stream.
20630Sstevel@tonic-gate 	 */
20640Sstevel@tonic-gate 	destsps = sppp_inpkt(q, mp, ctlsps);
20650Sstevel@tonic-gate 	if (destsps == NULL) {
20660Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
20670Sstevel@tonic-gate 		ppa->ppa_ipkt_ctl++;
20680Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
20690Sstevel@tonic-gate 		if (canputnext(ctlsps->sps_rq)) {
20700Sstevel@tonic-gate 			if (IS_SPS_KDEBUG(ctlsps)) {
20710Sstevel@tonic-gate 				SPDEBUG(PPP_DRV_NAME
20720Sstevel@tonic-gate 				    "/%d: M_DATA recv (%d bytes) sps=0x%p "
20730Sstevel@tonic-gate 				    "flags=0x%b ppa=0x%p flags=0x%b\n",
20740Sstevel@tonic-gate 				    ctlsps->sps_mn_id, len, (void *)ctlsps,
20750Sstevel@tonic-gate 				    ctlsps->sps_flags, SPS_FLAGS_STR,
20760Sstevel@tonic-gate 				    (void *)ppa, ppa->ppa_flags,
20770Sstevel@tonic-gate 				    PPA_FLAGS_STR);
20780Sstevel@tonic-gate 			}
20790Sstevel@tonic-gate 			return (ctlsps->sps_rq);
20800Sstevel@tonic-gate 		} else {
20810Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
20820Sstevel@tonic-gate 			ppa->ppa_iqdropped++;
20830Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
20840Sstevel@tonic-gate 			freemsg(mp);
20850Sstevel@tonic-gate 			return (NULL);
20860Sstevel@tonic-gate 		}
20870Sstevel@tonic-gate 	}
20880Sstevel@tonic-gate 	if (canputnext(destsps->sps_rq)) {
20890Sstevel@tonic-gate 		if (IS_SPS_KDEBUG(destsps)) {
20900Sstevel@tonic-gate 			SPDEBUG(PPP_DRV_NAME
20910Sstevel@tonic-gate 			    "/%d: M_DATA recv (%d bytes) sps=0x%p flags=0x%b "
20920Sstevel@tonic-gate 			    "ppa=0x%p flags=0x%b\n", destsps->sps_mn_id, len,
20930Sstevel@tonic-gate 			    (void *)destsps, destsps->sps_flags,
20940Sstevel@tonic-gate 			    SPS_FLAGS_STR, (void *)ppa, ppa->ppa_flags,
20950Sstevel@tonic-gate 			    PPA_FLAGS_STR);
20960Sstevel@tonic-gate 		}
20970Sstevel@tonic-gate 		/*
20980Sstevel@tonic-gate 		 * If fastpath is enabled on the network-layer stream, then
20990Sstevel@tonic-gate 		 * make sure we skip over the PPP header, otherwise, we wrap
21000Sstevel@tonic-gate 		 * the message in a DLPI message.
21010Sstevel@tonic-gate 		 */
21020Sstevel@tonic-gate 		if (IS_SPS_FASTPATH(destsps)) {
21030Sstevel@tonic-gate 			mp->b_rptr += PPP_HDRLEN;
21040Sstevel@tonic-gate 			return (destsps->sps_rq);
21050Sstevel@tonic-gate 		} else {
21060Sstevel@tonic-gate 			spppstr_t *uqs = (spppstr_t *)destsps->sps_rq->q_ptr;
21070Sstevel@tonic-gate 			ASSERT(uqs != NULL);
21080Sstevel@tonic-gate 			mp->b_rptr += PPP_HDRLEN;
21090Sstevel@tonic-gate 			mp = sppp_dladdud(uqs, mp, uqs->sps_sap, B_FALSE);
21100Sstevel@tonic-gate 			if (mp != NULL) {
21110Sstevel@tonic-gate 				*mpp = mp;
21120Sstevel@tonic-gate 				return (destsps->sps_rq);
21130Sstevel@tonic-gate 			} else {
21140Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
21150Sstevel@tonic-gate 				ppa->ppa_allocbfail++;
21160Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
21170Sstevel@tonic-gate 				/* mp already freed by sppp_dladdud */
21180Sstevel@tonic-gate 				return (NULL);
21190Sstevel@tonic-gate 			}
21200Sstevel@tonic-gate 		}
21210Sstevel@tonic-gate 	} else {
21220Sstevel@tonic-gate 		mutex_enter(&ppa->ppa_sta_lock);
21230Sstevel@tonic-gate 		ppa->ppa_iqdropped++;
21240Sstevel@tonic-gate 		mutex_exit(&ppa->ppa_sta_lock);
21250Sstevel@tonic-gate 		freemsg(mp);
21260Sstevel@tonic-gate 		return (NULL);
21270Sstevel@tonic-gate 	}
21280Sstevel@tonic-gate }
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate /*
21310Sstevel@tonic-gate  * sppp_inpkt()
21320Sstevel@tonic-gate  *
21330Sstevel@tonic-gate  * MT-Perimeters:
21340Sstevel@tonic-gate  *    shared inner, shared outer.
21350Sstevel@tonic-gate  *
21360Sstevel@tonic-gate  * Description:
21370Sstevel@tonic-gate  *    Find the destination upper stream for the received packet, called
21380Sstevel@tonic-gate  *    from sppp_recv.
21390Sstevel@tonic-gate  *
21400Sstevel@tonic-gate  * Returns:
21410Sstevel@tonic-gate  *    ptr to destination upper network stream, or NULL for control stream.
21420Sstevel@tonic-gate  */
21430Sstevel@tonic-gate /* ARGSUSED */
21440Sstevel@tonic-gate static spppstr_t *
sppp_inpkt(queue_t * q,mblk_t * mp,spppstr_t * ctlsps)21450Sstevel@tonic-gate sppp_inpkt(queue_t *q, mblk_t *mp, spppstr_t *ctlsps)
21460Sstevel@tonic-gate {
21470Sstevel@tonic-gate 	spppstr_t	*destsps = NULL;
21480Sstevel@tonic-gate 	sppa_t		*ppa;
21490Sstevel@tonic-gate 	uint16_t	proto;
21500Sstevel@tonic-gate 	int		is_promisc;
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 	ASSERT(q != NULL && q->q_ptr != NULL);
21530Sstevel@tonic-gate 	ASSERT(mp != NULL && mp->b_rptr != NULL);
21540Sstevel@tonic-gate 	ASSERT(IS_SPS_CONTROL(ctlsps));
21550Sstevel@tonic-gate 	ppa = ctlsps->sps_ppa;
21560Sstevel@tonic-gate 	ASSERT(ppa != NULL);
21570Sstevel@tonic-gate 	/*
21580Sstevel@tonic-gate 	 * From RFC 1661 (Section 2):
21590Sstevel@tonic-gate 	 *
21600Sstevel@tonic-gate 	 * The Protocol field is one or two octets, and its value identifies
21610Sstevel@tonic-gate 	 * the datagram encapsulated in the Information field of the packet.
21620Sstevel@tonic-gate 	 * The field is transmitted and received most significant octet first.
21630Sstevel@tonic-gate 	 *
21640Sstevel@tonic-gate 	 * The structure of this field is consistent with the ISO 3309
21650Sstevel@tonic-gate 	 * extension mechanism for address fields.  All Protocols MUST be odd;
21660Sstevel@tonic-gate 	 * the least significant bit of the least significant octet MUST equal
21670Sstevel@tonic-gate 	 * "1".  Also, all Protocols MUST be assigned such that the least
21680Sstevel@tonic-gate 	 * significant bit of the most significant octet equals "0". Frames
21690Sstevel@tonic-gate 	 * received which don't comply with these rules MUST be treated as
21700Sstevel@tonic-gate 	 * having an unrecognized Protocol.
21710Sstevel@tonic-gate 	 *
21720Sstevel@tonic-gate 	 * Protocol field values in the "0***" to "3***" range identify the
21730Sstevel@tonic-gate 	 * network-layer protocol of specific packets, and values in the
21740Sstevel@tonic-gate 	 * "8***" to "b***" range identify packets belonging to the associated
21750Sstevel@tonic-gate 	 * Network Control Protocols (NCPs), if any.
21760Sstevel@tonic-gate 	 *
21770Sstevel@tonic-gate 	 * Protocol field values in the "4***" to "7***" range are used for
21780Sstevel@tonic-gate 	 * protocols with low volume traffic which have no associated NCP.
21790Sstevel@tonic-gate 	 * Protocol field values in the "c***" to "f***" range identify packets
21800Sstevel@tonic-gate 	 * as link-layer Control Protocols (such as LCP).
21810Sstevel@tonic-gate 	 */
21820Sstevel@tonic-gate 	proto = PPP_PROTOCOL(mp->b_rptr);
21830Sstevel@tonic-gate 	mutex_enter(&ppa->ppa_sta_lock);
21840Sstevel@tonic-gate 	ppa->ppa_stats.p.ppp_ipackets++;
21850Sstevel@tonic-gate 	mutex_exit(&ppa->ppa_sta_lock);
21860Sstevel@tonic-gate 	/*
21870Sstevel@tonic-gate 	 * We check if this is not a network-layer protocol, and if so,
21880Sstevel@tonic-gate 	 * then send this packet up the control stream.
21890Sstevel@tonic-gate 	 */
21900Sstevel@tonic-gate 	if (proto > 0x7fff) {
21910Sstevel@tonic-gate 		goto inpkt_done;	/* send it up the control stream */
21920Sstevel@tonic-gate 	}
21930Sstevel@tonic-gate 	/*
21940Sstevel@tonic-gate 	 * Try to grab the destination upper stream from the network-layer
21950Sstevel@tonic-gate 	 * stream cache for this ppa for PPP_IP (0x0021) or PPP_IPV6 (0x0057)
21960Sstevel@tonic-gate 	 * protocol types. Otherwise, if the type is not known to the cache,
21970Sstevel@tonic-gate 	 * or if its sap can't be matched with any of the upper streams, then
21980Sstevel@tonic-gate 	 * send this packet up the control stream so that it can be rejected.
21990Sstevel@tonic-gate 	 */
22000Sstevel@tonic-gate 	if (proto == PPP_IP) {
22010Sstevel@tonic-gate 		destsps = ppa->ppa_ip_cache;
22020Sstevel@tonic-gate 	} else if (proto == PPP_IPV6) {
22030Sstevel@tonic-gate 		destsps = ppa->ppa_ip6_cache;
22040Sstevel@tonic-gate 	}
22050Sstevel@tonic-gate 	/*
22060Sstevel@tonic-gate 	 * Toss this one away up the control stream if there's no matching sap;
22070Sstevel@tonic-gate 	 * this way the protocol can be rejected (destsps is NULL).
22080Sstevel@tonic-gate 	 */
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate inpkt_done:
22110Sstevel@tonic-gate 	/*
22120Sstevel@tonic-gate 	 * Only time-stamp the packet with hrtime if the upper stream
22130Sstevel@tonic-gate 	 * is configured to do so.  PPP control (negotiation) messages
22140Sstevel@tonic-gate 	 * are never considered link activity; only data is activity.
22150Sstevel@tonic-gate 	 */
22160Sstevel@tonic-gate 	if (destsps != NULL && IS_PPA_TIMESTAMP(ppa)) {
22170Sstevel@tonic-gate 		ppa->ppa_lastrx = gethrtime();
22180Sstevel@tonic-gate 	}
22190Sstevel@tonic-gate 	/*
22200Sstevel@tonic-gate 	 * Should there be any promiscuous stream(s), send the data up for
22210Sstevel@tonic-gate 	 * each promiscuous stream that we recognize. We skip the control
22220Sstevel@tonic-gate 	 * stream as we obviously never allow the control stream to become
22230Sstevel@tonic-gate 	 * promiscous and bind to PPP_ALLSAP.
22240Sstevel@tonic-gate 	 */
22250Sstevel@tonic-gate 	rw_enter(&ppa->ppa_sib_lock, RW_READER);
22260Sstevel@tonic-gate 	is_promisc = ppa->ppa_promicnt;
22270Sstevel@tonic-gate 	if (is_promisc) {
22280Sstevel@tonic-gate 		ASSERT(ppa->ppa_streams != NULL);
22290Sstevel@tonic-gate 		sppp_dlprsendup(ppa->ppa_streams, mp, proto, B_TRUE);
22300Sstevel@tonic-gate 	}
22310Sstevel@tonic-gate 	rw_exit(&ppa->ppa_sib_lock);
22320Sstevel@tonic-gate 	return (destsps);
22330Sstevel@tonic-gate }
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate /*
22360Sstevel@tonic-gate  * sppp_kstat_update()
22370Sstevel@tonic-gate  *
22380Sstevel@tonic-gate  * Description:
22390Sstevel@tonic-gate  *    Update per-ppa kstat interface statistics.
22400Sstevel@tonic-gate  */
22410Sstevel@tonic-gate static int
sppp_kstat_update(kstat_t * ksp,int rw)22420Sstevel@tonic-gate sppp_kstat_update(kstat_t *ksp, int rw)
22430Sstevel@tonic-gate {
22440Sstevel@tonic-gate 	register sppa_t		*ppa;
22450Sstevel@tonic-gate 	register sppp_kstats_t	*pppkp;
22460Sstevel@tonic-gate 	register struct pppstat64 *sp;
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
22490Sstevel@tonic-gate 		return (EACCES);
22500Sstevel@tonic-gate 	}
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 	ppa = (sppa_t *)ksp->ks_private;
22530Sstevel@tonic-gate 	ASSERT(ppa != NULL);
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 	pppkp = (sppp_kstats_t *)ksp->ks_data;
22560Sstevel@tonic-gate 	sp = &ppa->ppa_stats.p;
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 	mutex_enter(&ppa->ppa_sta_lock);
22590Sstevel@tonic-gate 	pppkp->allocbfail.value.ui32	= ppa->ppa_allocbfail;
22600Sstevel@tonic-gate 	pppkp->mctlsfwd.value.ui32	= ppa->ppa_mctlsfwd;
22610Sstevel@tonic-gate 	pppkp->mctlsfwderr.value.ui32	= ppa->ppa_mctlsfwderr;
22620Sstevel@tonic-gate 	pppkp->rbytes.value.ui32	= sp->ppp_ibytes;
22630Sstevel@tonic-gate 	pppkp->rbytes64.value.ui64	= sp->ppp_ibytes;
22640Sstevel@tonic-gate 	pppkp->ierrors.value.ui32	= sp->ppp_ierrors;
22650Sstevel@tonic-gate 	pppkp->ierrors_lower.value.ui32	= ppa->ppa_ierr_low;
22660Sstevel@tonic-gate 	pppkp->ioctlsfwd.value.ui32	= ppa->ppa_ioctlsfwd;
22670Sstevel@tonic-gate 	pppkp->ioctlsfwdok.value.ui32	= ppa->ppa_ioctlsfwdok;
22680Sstevel@tonic-gate 	pppkp->ioctlsfwderr.value.ui32	= ppa->ppa_ioctlsfwderr;
22690Sstevel@tonic-gate 	pppkp->ipackets.value.ui32	= sp->ppp_ipackets;
22700Sstevel@tonic-gate 	pppkp->ipackets64.value.ui64	= sp->ppp_ipackets;
22710Sstevel@tonic-gate 	pppkp->ipackets_ctl.value.ui32	= ppa->ppa_ipkt_ctl;
22720Sstevel@tonic-gate 	pppkp->iqdropped.value.ui32	= ppa->ppa_iqdropped;
22730Sstevel@tonic-gate 	pppkp->irunts.value.ui32	= ppa->ppa_irunts;
22740Sstevel@tonic-gate 	pppkp->itoolongs.value.ui32	= ppa->ppa_itoolongs;
22750Sstevel@tonic-gate 	pppkp->lsneedup.value.ui32	= ppa->ppa_lsneedup;
22760Sstevel@tonic-gate 	pppkp->lsdown.value.ui32	= ppa->ppa_lsdown;
22770Sstevel@tonic-gate 	pppkp->mctlsknown.value.ui32	= ppa->ppa_mctlsknown;
22780Sstevel@tonic-gate 	pppkp->mctlsunknown.value.ui32	= ppa->ppa_mctlsunknown;
22790Sstevel@tonic-gate 	pppkp->obytes.value.ui32	= sp->ppp_obytes;
22800Sstevel@tonic-gate 	pppkp->obytes64.value.ui64	= sp->ppp_obytes;
22810Sstevel@tonic-gate 	pppkp->oerrors.value.ui32	= sp->ppp_oerrors;
22820Sstevel@tonic-gate 	pppkp->oerrors_lower.value.ui32	= ppa->ppa_oerr_low;
22830Sstevel@tonic-gate 	pppkp->opackets.value.ui32	= sp->ppp_opackets;
22840Sstevel@tonic-gate 	pppkp->opackets64.value.ui64	= sp->ppp_opackets;
22850Sstevel@tonic-gate 	pppkp->opackets_ctl.value.ui32	= ppa->ppa_opkt_ctl;
22860Sstevel@tonic-gate 	pppkp->oqdropped.value.ui32	= ppa->ppa_oqdropped;
22870Sstevel@tonic-gate 	pppkp->otoolongs.value.ui32	= ppa->ppa_otoolongs;
22880Sstevel@tonic-gate 	pppkp->orunts.value.ui32	= ppa->ppa_orunts;
22890Sstevel@tonic-gate 	mutex_exit(&ppa->ppa_sta_lock);
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	return (0);
22920Sstevel@tonic-gate }
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate /*
22950Sstevel@tonic-gate  * Turn off proto in ppa_npflag to indicate that
22960Sstevel@tonic-gate  * the corresponding network protocol has been plumbed.
22970Sstevel@tonic-gate  * Release proto packets that were being held in the control
22980Sstevel@tonic-gate  * queue in anticipation of this event.
22990Sstevel@tonic-gate  */
23000Sstevel@tonic-gate static void
sppp_release_pkts(sppa_t * ppa,uint16_t proto)23010Sstevel@tonic-gate sppp_release_pkts(sppa_t *ppa, uint16_t proto)
23020Sstevel@tonic-gate {
23030Sstevel@tonic-gate 	uint32_t npflagpos = sppp_ppp2np(proto);
23040Sstevel@tonic-gate 	int count;
23050Sstevel@tonic-gate 	mblk_t *mp;
23060Sstevel@tonic-gate 	uint16_t mp_proto;
23070Sstevel@tonic-gate 	queue_t *q;
23080Sstevel@tonic-gate 	spppstr_t *destsps;
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 	ASSERT(ppa != NULL);
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 	if (npflagpos == 0 || (ppa->ppa_npflag & (1 << npflagpos)) == 0)
23130Sstevel@tonic-gate 		return;
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	mutex_enter(&ppa->ppa_npmutex);
23160Sstevel@tonic-gate 	ppa->ppa_npflag &= ~(1 << npflagpos);
23170Sstevel@tonic-gate 	count = ppa->ppa_holdpkts[npflagpos];
23180Sstevel@tonic-gate 	ppa->ppa_holdpkts[npflagpos] = 0;
23190Sstevel@tonic-gate 	mutex_exit(&ppa->ppa_npmutex);
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	q = ppa->ppa_ctl->sps_rq;
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	while (count > 0) {
23240Sstevel@tonic-gate 		mp = getq(q);
23250Sstevel@tonic-gate 		ASSERT(mp != NULL);
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 		mp_proto = PPP_PROTOCOL(mp->b_rptr);
23280Sstevel@tonic-gate 		if (mp_proto !=  proto) {
23290Sstevel@tonic-gate 			(void) putq(q, mp);
23300Sstevel@tonic-gate 			continue;
23310Sstevel@tonic-gate 		}
23320Sstevel@tonic-gate 		count--;
23330Sstevel@tonic-gate 		destsps = NULL;
23340Sstevel@tonic-gate 		if (mp_proto == PPP_IP) {
23350Sstevel@tonic-gate 			destsps = ppa->ppa_ip_cache;
23360Sstevel@tonic-gate 		} else if (mp_proto == PPP_IPV6) {
23370Sstevel@tonic-gate 			destsps = ppa->ppa_ip6_cache;
23380Sstevel@tonic-gate 		}
23390Sstevel@tonic-gate 		ASSERT(destsps != NULL);
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 		if (IS_SPS_FASTPATH(destsps)) {
23420Sstevel@tonic-gate 			mp->b_rptr += PPP_HDRLEN;
23430Sstevel@tonic-gate 		} else {
23440Sstevel@tonic-gate 			spppstr_t *uqs = (spppstr_t *)destsps->sps_rq->q_ptr;
23450Sstevel@tonic-gate 			ASSERT(uqs != NULL);
23460Sstevel@tonic-gate 			mp->b_rptr += PPP_HDRLEN;
23470Sstevel@tonic-gate 			mp = sppp_dladdud(uqs, mp, uqs->sps_sap, B_FALSE);
23480Sstevel@tonic-gate 			if (mp == NULL) {
23490Sstevel@tonic-gate 				mutex_enter(&ppa->ppa_sta_lock);
23500Sstevel@tonic-gate 				ppa->ppa_allocbfail++;
23510Sstevel@tonic-gate 				mutex_exit(&ppa->ppa_sta_lock);
23520Sstevel@tonic-gate 				/* mp already freed by sppp_dladdud */
23530Sstevel@tonic-gate 				continue;
23540Sstevel@tonic-gate 			}
23550Sstevel@tonic-gate 		}
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 		if (canputnext(destsps->sps_rq)) {
23580Sstevel@tonic-gate 			putnext(destsps->sps_rq, mp);
23590Sstevel@tonic-gate 		} else {
23600Sstevel@tonic-gate 			mutex_enter(&ppa->ppa_sta_lock);
23610Sstevel@tonic-gate 			ppa->ppa_iqdropped++;
23620Sstevel@tonic-gate 			mutex_exit(&ppa->ppa_sta_lock);
23630Sstevel@tonic-gate 			freemsg(mp);
23640Sstevel@tonic-gate 			continue;
23650Sstevel@tonic-gate 		}
23660Sstevel@tonic-gate 	}
23670Sstevel@tonic-gate }
2368