1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate #include <sys/types.h> 9*0Sstevel@tonic-gate #include <sys/debug.h> 10*0Sstevel@tonic-gate #include <sys/param.h> 11*0Sstevel@tonic-gate #include <sys/stat.h> 12*0Sstevel@tonic-gate #include <sys/systm.h> 13*0Sstevel@tonic-gate #include <sys/socket.h> 14*0Sstevel@tonic-gate #include <sys/stream.h> 15*0Sstevel@tonic-gate #include <sys/stropts.h> 16*0Sstevel@tonic-gate #include <sys/errno.h> 17*0Sstevel@tonic-gate #include <sys/time.h> 18*0Sstevel@tonic-gate #include <sys/cmn_err.h> 19*0Sstevel@tonic-gate #include <sys/conf.h> 20*0Sstevel@tonic-gate #include <sys/dlpi.h> 21*0Sstevel@tonic-gate #include <sys/ddi.h> 22*0Sstevel@tonic-gate #include <sys/kstat.h> 23*0Sstevel@tonic-gate #include <sys/strsun.h> 24*0Sstevel@tonic-gate #include <sys/bitmap.h> 25*0Sstevel@tonic-gate #include <sys/sysmacros.h> 26*0Sstevel@tonic-gate #include <sys/note.h> 27*0Sstevel@tonic-gate #include <sys/policy.h> 28*0Sstevel@tonic-gate #include <net/ppp_defs.h> 29*0Sstevel@tonic-gate #include <net/pppio.h> 30*0Sstevel@tonic-gate #include <net/sppptun.h> 31*0Sstevel@tonic-gate #include <net/pppoe.h> 32*0Sstevel@tonic-gate #include <netinet/in.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include "s_common.h" 35*0Sstevel@tonic-gate #include "sppptun_mod.h" 36*0Sstevel@tonic-gate #include "sppptun_impl.h" 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #define NTUN_INITIAL 16 /* Initial number of sppptun slots */ 39*0Sstevel@tonic-gate #define NTUN_PERCENT 5 /* Percent of memory to use */ 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate /* 42*0Sstevel@tonic-gate * This is used to tag official Solaris sources. Please do not define 43*0Sstevel@tonic-gate * "INTERNAL_BUILD" when building this software outside of Sun 44*0Sstevel@tonic-gate * Microsystems. 45*0Sstevel@tonic-gate */ 46*0Sstevel@tonic-gate #ifdef INTERNAL_BUILD 47*0Sstevel@tonic-gate /* MODINFO is limited to 32 characters. */ 48*0Sstevel@tonic-gate const char sppptun_driver_description[] = "PPP 4.0 tunnel driver v%I%"; 49*0Sstevel@tonic-gate const char sppptun_module_description[] = "PPP 4.0 tunnel module v%I%"; 50*0Sstevel@tonic-gate #else 51*0Sstevel@tonic-gate const char sppptun_driver_description[] = "ANU PPP tundrv $Revision: $"; 52*0Sstevel@tonic-gate const char sppptun_module_description[] = "ANU PPP tunmod $Revision: $"; 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate /* LINTED */ 55*0Sstevel@tonic-gate static const char buildtime[] = "Built " __DATE__ " at " __TIME__ 56*0Sstevel@tonic-gate #ifdef DEBUG 57*0Sstevel@tonic-gate " DEBUG" 58*0Sstevel@tonic-gate #endif 59*0Sstevel@tonic-gate "\n"; 60*0Sstevel@tonic-gate #endif 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* 63*0Sstevel@tonic-gate * Tunable values; these are similar to the values used in ptms_conf.c. 64*0Sstevel@tonic-gate * Override these settings via /etc/system. 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate uint_t sppptun_cnt = 0; /* Minimum number of tunnels */ 67*0Sstevel@tonic-gate size_t sppptun_max_pty = 0; /* Maximum number of tunnels */ 68*0Sstevel@tonic-gate uint_t sppptun_init_cnt = NTUN_INITIAL; /* Initial number of tunnel slots */ 69*0Sstevel@tonic-gate uint_t sppptun_pctofmem = NTUN_PERCENT; /* Percent of memory to use */ 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate typedef struct ether_dest_s { 72*0Sstevel@tonic-gate ether_addr_t addr; 73*0Sstevel@tonic-gate ushort_t type; 74*0Sstevel@tonic-gate } ether_dest_t; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* Allows unaligned access. */ 77*0Sstevel@tonic-gate #define GETLONG(x) (((x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate static const char *tll_kstats_list[] = { TLL_KSTATS_NAMES }; 80*0Sstevel@tonic-gate static const char *tcl_kstats_list[] = { TCL_KSTATS_NAMES }; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate #define KREF(p, m, vn) p->m.vn.value.ui64 83*0Sstevel@tonic-gate #define KINCR(p, m, vn) ++KREF(p, m, vn) 84*0Sstevel@tonic-gate #define KDECR(p, m, vn) --KREF(p, m, vn) 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #define KLINCR(vn) KINCR(tll, tll_kstats, vn) 87*0Sstevel@tonic-gate #define KLDECR(vn) KDECR(tll, tll_kstats, vn) 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate #define KCINCR(vn) KINCR(tcl, tcl_kstats, vn) 90*0Sstevel@tonic-gate #define KCDECR(vn) KDECR(tcl, tcl_kstats, vn) 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate #define DBGTSIDE(t) ((((tuncl_t *)(t))->tcl_flags & TCLF_ISCLIENT) ? \ 93*0Sstevel@tonic-gate "device" : "module") 94*0Sstevel@tonic-gate #define DBGQSIDE(q) (DBGTSIDE((q)->q_ptr)) 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate static int sppptun_open(queue_t *, dev_t *, int, int, cred_t *); 97*0Sstevel@tonic-gate static int sppptun_close(queue_t *); 98*0Sstevel@tonic-gate static void sppptun_urput(queue_t *, mblk_t *); 99*0Sstevel@tonic-gate static void sppptun_uwput(queue_t *, mblk_t *); 100*0Sstevel@tonic-gate static int sppptun_ursrv(queue_t *); 101*0Sstevel@tonic-gate static int sppptun_uwsrv(queue_t *); 102*0Sstevel@tonic-gate static void sppptun_lrput(queue_t *, mblk_t *); 103*0Sstevel@tonic-gate static void sppptun_lwput(queue_t *, mblk_t *); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * This is the hash table of clients. Clients are the programs that 107*0Sstevel@tonic-gate * open /dev/sppptun as a device. There may be a large number of 108*0Sstevel@tonic-gate * these; one per tunneled PPP session. 109*0Sstevel@tonic-gate * 110*0Sstevel@tonic-gate * Note: slots are offset from minor node value by 1 because 111*0Sstevel@tonic-gate * vmem_alloc returns 0 for failure. 112*0Sstevel@tonic-gate * 113*0Sstevel@tonic-gate * The tcl_slots array entries are modified only when exclusive on 114*0Sstevel@tonic-gate * both inner and outer perimeters. This ensures that threads on 115*0Sstevel@tonic-gate * shared perimeters always view this as unchanging memory with no 116*0Sstevel@tonic-gate * need to lock around accesses. (Specifically, the tcl_slots array 117*0Sstevel@tonic-gate * is modified by entry to sppptun_open, sppptun_close, and _fini.) 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate static tuncl_t **tcl_slots = NULL; /* Slots for tuncl_t */ 120*0Sstevel@tonic-gate static size_t tcl_nslots = 0; /* Size of slot array */ 121*0Sstevel@tonic-gate static size_t tcl_minormax = 0; /* Maximum number of tunnels */ 122*0Sstevel@tonic-gate static size_t tcl_inuse = 0; /* # of tunnels currently allocated */ 123*0Sstevel@tonic-gate static krwlock_t tcl_rwlock; 124*0Sstevel@tonic-gate static struct kmem_cache *tcl_cache = NULL; /* tunnel cache */ 125*0Sstevel@tonic-gate static vmem_t *tcl_minor_arena = NULL; /* Arena for device minors */ 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * This is the simple list of lower layers. For PPPoE, there is one 129*0Sstevel@tonic-gate * of these per Ethernet interface. Lower layers are established by 130*0Sstevel@tonic-gate * "plumbing" -- using I_PLINK to connect the tunnel multiplexor to 131*0Sstevel@tonic-gate * the physical interface. 132*0Sstevel@tonic-gate */ 133*0Sstevel@tonic-gate static struct qelem tunll_list; 134*0Sstevel@tonic-gate static int tunll_index; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* Test value; if all zeroes, then address hasn't been set yet. */ 137*0Sstevel@tonic-gate static const ether_addr_t zero_mac_addr = { 0, 0, 0, 0, 0, 0 }; 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate #define MIN_SET_FASTPATH_UNITDATAREQ_SIZE \ 140*0Sstevel@tonic-gate (sizeof (dl_unitdata_req_t) + 4) 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate #define TUN_MI_ID 2104 /* officially allocated module ID */ 143*0Sstevel@tonic-gate #define TUN_MI_MINPSZ (0) 144*0Sstevel@tonic-gate #define TUN_MI_MAXPSZ (PPP_MAXMTU) 145*0Sstevel@tonic-gate #define TUN_MI_HIWAT (PPP_MTU * 8) 146*0Sstevel@tonic-gate #define TUN_MI_LOWAT (128) 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate static struct module_info sppptun_modinfo = { 149*0Sstevel@tonic-gate TUN_MI_ID, /* mi_idnum */ 150*0Sstevel@tonic-gate PPP_TUN_NAME, /* mi_idname */ 151*0Sstevel@tonic-gate TUN_MI_MINPSZ, /* mi_minpsz */ 152*0Sstevel@tonic-gate TUN_MI_MAXPSZ, /* mi_maxpsz */ 153*0Sstevel@tonic-gate TUN_MI_HIWAT, /* mi_hiwat */ 154*0Sstevel@tonic-gate TUN_MI_LOWAT /* mi_lowat */ 155*0Sstevel@tonic-gate }; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate static struct qinit sppptun_urinit = { 158*0Sstevel@tonic-gate (int (*)())sppptun_urput, /* qi_putp */ 159*0Sstevel@tonic-gate sppptun_ursrv, /* qi_srvp */ 160*0Sstevel@tonic-gate sppptun_open, /* qi_qopen */ 161*0Sstevel@tonic-gate sppptun_close, /* qi_qclose */ 162*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 163*0Sstevel@tonic-gate &sppptun_modinfo, /* qi_minfo */ 164*0Sstevel@tonic-gate NULL /* qi_mstat */ 165*0Sstevel@tonic-gate }; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate static struct qinit sppptun_uwinit = { 168*0Sstevel@tonic-gate (int (*)())sppptun_uwput, /* qi_putp */ 169*0Sstevel@tonic-gate sppptun_uwsrv, /* qi_srvp */ 170*0Sstevel@tonic-gate NULL, /* qi_qopen */ 171*0Sstevel@tonic-gate NULL, /* qi_qclose */ 172*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 173*0Sstevel@tonic-gate &sppptun_modinfo, /* qi_minfo */ 174*0Sstevel@tonic-gate NULL /* qi_mstat */ 175*0Sstevel@tonic-gate }; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate static struct qinit sppptun_lrinit = { 178*0Sstevel@tonic-gate (int (*)())sppptun_lrput, /* qi_putp */ 179*0Sstevel@tonic-gate NULL, /* qi_srvp */ 180*0Sstevel@tonic-gate NULL, /* qi_qopen */ 181*0Sstevel@tonic-gate NULL, /* qi_qclose */ 182*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 183*0Sstevel@tonic-gate &sppptun_modinfo, /* qi_minfo */ 184*0Sstevel@tonic-gate NULL /* qi_mstat */ 185*0Sstevel@tonic-gate }; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate static struct qinit sppptun_lwinit = { 188*0Sstevel@tonic-gate (int (*)())sppptun_lwput, /* qi_putp */ 189*0Sstevel@tonic-gate NULL, /* qi_srvp */ 190*0Sstevel@tonic-gate NULL, /* qi_qopen */ 191*0Sstevel@tonic-gate NULL, /* qi_qclose */ 192*0Sstevel@tonic-gate NULL, /* qi_qadmin */ 193*0Sstevel@tonic-gate &sppptun_modinfo, /* qi_minfo */ 194*0Sstevel@tonic-gate NULL /* qi_mstat */ 195*0Sstevel@tonic-gate }; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * This is referenced in sppptun_mod.c. 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate struct streamtab sppptun_tab = { 201*0Sstevel@tonic-gate &sppptun_urinit, /* st_rdinit */ 202*0Sstevel@tonic-gate &sppptun_uwinit, /* st_wrinit */ 203*0Sstevel@tonic-gate &sppptun_lrinit, /* st_muxrinit */ 204*0Sstevel@tonic-gate &sppptun_lwinit /* st_muxwrinit */ 205*0Sstevel@tonic-gate }; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate /* 208*0Sstevel@tonic-gate * Nifty packet dumper; copied from pppd AIX 4.1 port. This routine 209*0Sstevel@tonic-gate * dumps the raw received and transmitted data through syslog. This 210*0Sstevel@tonic-gate * allows debug of communications problems without resorting to a line 211*0Sstevel@tonic-gate * analyzer. 212*0Sstevel@tonic-gate * 213*0Sstevel@tonic-gate * The expression "3*BYTES_PER_LINE" used frequently here represents 214*0Sstevel@tonic-gate * the size of each hex value printed -- two hex digits and a space. 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate #define BYTES_PER_LINE 8 217*0Sstevel@tonic-gate static void 218*0Sstevel@tonic-gate sppp_dump_frame(int unit, mblk_t *mptr, const char *msg) 219*0Sstevel@tonic-gate { 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * Buffer is big enough for hex digits, two spaces, ASCII output, 222*0Sstevel@tonic-gate * and one NUL byte. 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate char buf[3 * BYTES_PER_LINE + 2 + BYTES_PER_LINE + 1]; 225*0Sstevel@tonic-gate uchar_t *rptr, *eptr; 226*0Sstevel@tonic-gate int i, chr; 227*0Sstevel@tonic-gate char *bp; 228*0Sstevel@tonic-gate static const char digits[] = "0123456789abcdef"; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate cmn_err(CE_CONT, "!sppp%d: %s %ld bytes\n", unit, msg, msgsize(mptr)); 231*0Sstevel@tonic-gate i = 0; 232*0Sstevel@tonic-gate bp = buf; 233*0Sstevel@tonic-gate /* Add filler spaces between hex output and ASCII */ 234*0Sstevel@tonic-gate buf[3 * BYTES_PER_LINE] = ' '; 235*0Sstevel@tonic-gate buf[3 * BYTES_PER_LINE + 1] = ' '; 236*0Sstevel@tonic-gate /* Add NUL byte at end */ 237*0Sstevel@tonic-gate buf[sizeof (buf) - 1] = '\0'; 238*0Sstevel@tonic-gate while (mptr != NULL) { 239*0Sstevel@tonic-gate rptr = mptr->b_rptr; /* get pointer to beginning */ 240*0Sstevel@tonic-gate eptr = mptr->b_wptr; 241*0Sstevel@tonic-gate while (rptr < eptr) { 242*0Sstevel@tonic-gate chr = *rptr++; 243*0Sstevel@tonic-gate /* convert byte to ascii hex */ 244*0Sstevel@tonic-gate *bp++ = digits[chr >> 4]; 245*0Sstevel@tonic-gate *bp++ = digits[chr & 0xf]; 246*0Sstevel@tonic-gate *bp++ = ' '; 247*0Sstevel@tonic-gate /* Insert ASCII past hex output and filler */ 248*0Sstevel@tonic-gate buf[3 * BYTES_PER_LINE + 2 + i] = 249*0Sstevel@tonic-gate (chr >= 0x20 && chr <= 0x7E) ? (char)chr : '.'; 250*0Sstevel@tonic-gate i++; 251*0Sstevel@tonic-gate if (i >= BYTES_PER_LINE) { 252*0Sstevel@tonic-gate cmn_err(CE_CONT, "!sppp%d: %s\n", unit, 253*0Sstevel@tonic-gate buf); 254*0Sstevel@tonic-gate bp = buf; 255*0Sstevel@tonic-gate i = 0; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate mptr = mptr->b_cont; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate if (bp > buf) { 261*0Sstevel@tonic-gate /* fill over unused hex display positions */ 262*0Sstevel@tonic-gate while (bp < buf + 3 * BYTES_PER_LINE) 263*0Sstevel@tonic-gate *bp++ = ' '; 264*0Sstevel@tonic-gate /* terminate ASCII string at right position */ 265*0Sstevel@tonic-gate buf[3 * BYTES_PER_LINE + 2 + i] = '\0'; 266*0Sstevel@tonic-gate cmn_err(CE_CONT, "!sppp%d: %s\n", unit, buf); 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * Allocate another slot table twice as large as the original one 272*0Sstevel@tonic-gate * (limited to global maximum). Migrate all tunnels to the new slot 273*0Sstevel@tonic-gate * table and free the original one. Assumes we're exclusive on both 274*0Sstevel@tonic-gate * inner and outer perimeters, and thus there are no other users of 275*0Sstevel@tonic-gate * the tcl_slots array. 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate static minor_t 278*0Sstevel@tonic-gate tcl_grow(void) 279*0Sstevel@tonic-gate { 280*0Sstevel@tonic-gate minor_t old_size = tcl_nslots; 281*0Sstevel@tonic-gate minor_t new_size = 2 * old_size; 282*0Sstevel@tonic-gate tuncl_t **tcl_old = tcl_slots; 283*0Sstevel@tonic-gate tuncl_t **tcl_new; 284*0Sstevel@tonic-gate void *vaddr; /* vmem_add return value */ 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&tcl_rwlock)); 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate /* Allocate new ptms array */ 289*0Sstevel@tonic-gate tcl_new = kmem_zalloc(new_size * sizeof (tuncl_t *), KM_NOSLEEP); 290*0Sstevel@tonic-gate if (tcl_new == NULL) 291*0Sstevel@tonic-gate return ((minor_t)0); 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate /* Increase clone index space */ 294*0Sstevel@tonic-gate vaddr = vmem_add(tcl_minor_arena, (void*)((uintptr_t)old_size + 1), 295*0Sstevel@tonic-gate new_size - old_size, VM_NOSLEEP); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate if (vaddr == NULL) { 298*0Sstevel@tonic-gate kmem_free(tcl_new, new_size * sizeof (tuncl_t *)); 299*0Sstevel@tonic-gate return ((minor_t)0); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate /* Migrate tuncl_t entries to a new location */ 303*0Sstevel@tonic-gate tcl_nslots = new_size; 304*0Sstevel@tonic-gate bcopy(tcl_old, tcl_new, old_size * sizeof (tuncl_t *)); 305*0Sstevel@tonic-gate tcl_slots = tcl_new; 306*0Sstevel@tonic-gate kmem_free(tcl_old, old_size * sizeof (tuncl_t *)); 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* Allocate minor number and return it */ 309*0Sstevel@tonic-gate return ((minor_t)(uintptr_t)vmem_alloc(tcl_minor_arena, 1, VM_NOSLEEP)); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * Allocate new minor number and tunnel client entry. Returns the new 314*0Sstevel@tonic-gate * entry or NULL if no memory or maximum number of entries reached. 315*0Sstevel@tonic-gate * Assumes we're exclusive on both inner and outer perimeters, and 316*0Sstevel@tonic-gate * thus there are no other users of the tcl_slots array. 317*0Sstevel@tonic-gate */ 318*0Sstevel@tonic-gate static tuncl_t * 319*0Sstevel@tonic-gate tuncl_alloc(int wantminor) 320*0Sstevel@tonic-gate { 321*0Sstevel@tonic-gate minor_t dminor; 322*0Sstevel@tonic-gate tuncl_t *tcl = NULL; 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate rw_enter(&tcl_rwlock, RW_WRITER); 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate ASSERT(tcl_slots != NULL); 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * Always try to allocate new pty when sppptun_cnt minimum 330*0Sstevel@tonic-gate * limit is not achieved. If it is achieved, the maximum is 331*0Sstevel@tonic-gate * determined by either user-specified value (if it is 332*0Sstevel@tonic-gate * non-zero) or our memory estimations - whatever is less. 333*0Sstevel@tonic-gate */ 334*0Sstevel@tonic-gate if (tcl_inuse >= sppptun_cnt) { 335*0Sstevel@tonic-gate /* 336*0Sstevel@tonic-gate * When system achieved required minimum of tunnels, 337*0Sstevel@tonic-gate * check for the denial of service limits. 338*0Sstevel@tonic-gate * 339*0Sstevel@tonic-gate * Get user-imposed maximum, if configured, or 340*0Sstevel@tonic-gate * calculated memory constraint. 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate size_t user_max = (sppptun_max_pty == 0 ? tcl_minormax : 343*0Sstevel@tonic-gate min(sppptun_max_pty, tcl_minormax)); 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* Do not try to allocate more than allowed */ 346*0Sstevel@tonic-gate if (tcl_inuse >= user_max) { 347*0Sstevel@tonic-gate rw_exit(&tcl_rwlock); 348*0Sstevel@tonic-gate return (NULL); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate tcl_inuse++; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * Allocate new minor number. If this fails, all slots are 355*0Sstevel@tonic-gate * busy and we need to grow the hash. 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate if (wantminor <= 0) { 358*0Sstevel@tonic-gate dminor = (minor_t)(uintptr_t)vmem_alloc(tcl_minor_arena, 1, 359*0Sstevel@tonic-gate VM_NOSLEEP); 360*0Sstevel@tonic-gate if (dminor == 0) { 361*0Sstevel@tonic-gate /* Grow the cache and retry allocation */ 362*0Sstevel@tonic-gate dminor = tcl_grow(); 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate } else { 365*0Sstevel@tonic-gate dminor = (minor_t)(uintptr_t)vmem_xalloc(tcl_minor_arena, 1, 366*0Sstevel@tonic-gate 0, 0, 0, (void *)(uintptr_t)wantminor, 367*0Sstevel@tonic-gate (void *)((uintptr_t)wantminor+1), VM_NOSLEEP); 368*0Sstevel@tonic-gate if (dminor != 0 && dminor != wantminor) { 369*0Sstevel@tonic-gate vmem_free(tcl_minor_arena, (void *)(uintptr_t)dminor, 370*0Sstevel@tonic-gate 1); 371*0Sstevel@tonic-gate dminor = 0; 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate if (dminor == 0) { 376*0Sstevel@tonic-gate /* Not enough memory now */ 377*0Sstevel@tonic-gate tcl_inuse--; 378*0Sstevel@tonic-gate rw_exit(&tcl_rwlock); 379*0Sstevel@tonic-gate return (NULL); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate tcl = kmem_cache_alloc(tcl_cache, KM_NOSLEEP); 383*0Sstevel@tonic-gate if (tcl == NULL) { 384*0Sstevel@tonic-gate /* Not enough memory - this entry can't be used now. */ 385*0Sstevel@tonic-gate vmem_free(tcl_minor_arena, (void *)(uintptr_t)dminor, 1); 386*0Sstevel@tonic-gate tcl_inuse--; 387*0Sstevel@tonic-gate } else { 388*0Sstevel@tonic-gate bzero(tcl, sizeof (*tcl)); 389*0Sstevel@tonic-gate tcl->tcl_lsessid = dminor; 390*0Sstevel@tonic-gate ASSERT(tcl_slots[dminor - 1] == NULL); 391*0Sstevel@tonic-gate tcl_slots[dminor - 1] = tcl; 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate rw_exit(&tcl_rwlock); 395*0Sstevel@tonic-gate return (tcl); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * This routine frees an upper level (client) stream by removing it 400*0Sstevel@tonic-gate * from the minor number pool and freeing the state structure storage. 401*0Sstevel@tonic-gate * Assumes we're exclusive on both inner and outer perimeters, and 402*0Sstevel@tonic-gate * thus there are no other concurrent users of the tcl_slots array or 403*0Sstevel@tonic-gate * of any entry in that array. 404*0Sstevel@tonic-gate */ 405*0Sstevel@tonic-gate static void 406*0Sstevel@tonic-gate tuncl_free(tuncl_t *tcl) 407*0Sstevel@tonic-gate { 408*0Sstevel@tonic-gate rw_enter(&tcl_rwlock, RW_WRITER); 409*0Sstevel@tonic-gate ASSERT(tcl->tcl_lsessid <= tcl_nslots); 410*0Sstevel@tonic-gate ASSERT(tcl_slots[tcl->tcl_lsessid - 1] == tcl); 411*0Sstevel@tonic-gate ASSERT(tcl_inuse > 0); 412*0Sstevel@tonic-gate tcl_inuse--; 413*0Sstevel@tonic-gate tcl_slots[tcl->tcl_lsessid - 1] = NULL; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate if (tcl->tcl_ksp != NULL) { 416*0Sstevel@tonic-gate kstat_delete(tcl->tcl_ksp); 417*0Sstevel@tonic-gate tcl->tcl_ksp = NULL; 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate /* Return minor number to the pool of minors */ 421*0Sstevel@tonic-gate vmem_free(tcl_minor_arena, (void *)(uintptr_t)tcl->tcl_lsessid, 1); 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate /* Return tuncl_t to the cache */ 424*0Sstevel@tonic-gate kmem_cache_free(tcl_cache, tcl); 425*0Sstevel@tonic-gate rw_exit(&tcl_rwlock); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Get tuncl_t structure by minor number. Returns NULL when minor is 430*0Sstevel@tonic-gate * out of range. Note that lookup of tcl pointers (and use of those 431*0Sstevel@tonic-gate * pointers) is safe because modification is done only when exclusive 432*0Sstevel@tonic-gate * on both inner and outer perimeters. 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate static tuncl_t * 435*0Sstevel@tonic-gate tcl_by_minor(minor_t dminor) 436*0Sstevel@tonic-gate { 437*0Sstevel@tonic-gate tuncl_t *tcl = NULL; 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate if ((dminor >= 1) && (dminor <= tcl_nslots) && tcl_slots != NULL) { 440*0Sstevel@tonic-gate tcl = tcl_slots[dminor - 1]; 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate return (tcl); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate /* 447*0Sstevel@tonic-gate * Set up kstats for upper or lower stream. 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate static kstat_t * 450*0Sstevel@tonic-gate kstat_setup(kstat_named_t *knt, const char **names, int nstat, 451*0Sstevel@tonic-gate const char *modname, int unitnum) 452*0Sstevel@tonic-gate { 453*0Sstevel@tonic-gate kstat_t *ksp; 454*0Sstevel@tonic-gate char unitname[KSTAT_STRLEN]; 455*0Sstevel@tonic-gate int i; 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate for (i = 0; i < nstat; i++) { 458*0Sstevel@tonic-gate kstat_set_string(knt[i].name, (char *)names[i]); 459*0Sstevel@tonic-gate knt[i].data_type = KSTAT_DATA_UINT64; 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate (void) sprintf(unitname, "%s%d", modname, unitnum); 462*0Sstevel@tonic-gate ksp = kstat_create((char *)modname, unitnum, unitname, "net", 463*0Sstevel@tonic-gate KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_VIRTUAL); 464*0Sstevel@tonic-gate if (ksp != NULL) { 465*0Sstevel@tonic-gate ksp->ks_data = (void *)knt; 466*0Sstevel@tonic-gate kstat_install(ksp); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate return (ksp); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * sppptun_open() 473*0Sstevel@tonic-gate * 474*0Sstevel@tonic-gate * MT-Perimeters: 475*0Sstevel@tonic-gate * exclusive inner, exclusive outer. 476*0Sstevel@tonic-gate * 477*0Sstevel@tonic-gate * Description: 478*0Sstevel@tonic-gate * Common open procedure for module and driver. 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate static int 481*0Sstevel@tonic-gate sppptun_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 482*0Sstevel@tonic-gate { 483*0Sstevel@tonic-gate _NOTE(ARGUNUSED(oflag)) 484*0Sstevel@tonic-gate ASSERT(q != NULL); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate DBGENTRY((CE_CONT, "sppptun_open as %s", 487*0Sstevel@tonic-gate (sflag & MODOPEN) ? "module" :"device")); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* Allow a re-open */ 490*0Sstevel@tonic-gate if (q->q_ptr != NULL) 491*0Sstevel@tonic-gate return (0); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate /* In the off chance that we're on our way out, just return error */ 494*0Sstevel@tonic-gate if (tcl_slots == NULL) { 495*0Sstevel@tonic-gate DBGERROR((CE_CONT, "tcl_slots is NULL on open\n")); 496*0Sstevel@tonic-gate return (EINVAL); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if (sflag & MODOPEN) { 500*0Sstevel@tonic-gate tunll_t *tll; 501*0Sstevel@tonic-gate char *cp; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate /* ordinary users have no need to push this module */ 504*0Sstevel@tonic-gate if (secpolicy_net_config(credp, B_FALSE) != 0) 505*0Sstevel@tonic-gate return (EPERM); 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate tll = kmem_zalloc(sizeof (tunll_t), KM_SLEEP); 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate tll->tll_index = tunll_index++; 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate tll->tll_wq = WR(q); 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate /* Insert at end of list */ 514*0Sstevel@tonic-gate insque(&tll->tll_next, tunll_list.q_back); 515*0Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = tll; 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate tll->tll_style = PTS_PPPOE; 518*0Sstevel@tonic-gate tll->tll_alen = sizeof (tll->tll_lcladdr.pta_pppoe); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate tll->tll_ksp = kstat_setup((kstat_named_t *)&tll->tll_kstats, 521*0Sstevel@tonic-gate tll_kstats_list, Dim(tll_kstats_list), "tll", 522*0Sstevel@tonic-gate tll->tll_index); 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate /* 525*0Sstevel@tonic-gate * Find the name of the driver somewhere beneath us. 526*0Sstevel@tonic-gate * Note that we have no driver under us until after 527*0Sstevel@tonic-gate * qprocson(). 528*0Sstevel@tonic-gate */ 529*0Sstevel@tonic-gate qprocson(q); 530*0Sstevel@tonic-gate for (q = WR(q); q->q_next != NULL; q = q->q_next) 531*0Sstevel@tonic-gate ; 532*0Sstevel@tonic-gate cp = NULL; 533*0Sstevel@tonic-gate if (q->q_qinfo != NULL && q->q_qinfo->qi_minfo != NULL) 534*0Sstevel@tonic-gate cp = q->q_qinfo->qi_minfo->mi_idname; 535*0Sstevel@tonic-gate if (cp != NULL && *cp == '\0') 536*0Sstevel@tonic-gate cp = NULL; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate /* Set initial name; user should overwrite. */ 539*0Sstevel@tonic-gate if (cp == NULL) 540*0Sstevel@tonic-gate (void) snprintf(tll->tll_name, sizeof (tll->tll_name), 541*0Sstevel@tonic-gate PPP_TUN_NAME "%d", tll->tll_index); 542*0Sstevel@tonic-gate else 543*0Sstevel@tonic-gate (void) snprintf(tll->tll_name, sizeof (tll->tll_name), 544*0Sstevel@tonic-gate "%s:tun%d", cp, tll->tll_index); 545*0Sstevel@tonic-gate } else { 546*0Sstevel@tonic-gate tuncl_t *tcl; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate ASSERT(devp != NULL); 549*0Sstevel@tonic-gate if (sflag & CLONEOPEN) { 550*0Sstevel@tonic-gate tcl = tuncl_alloc(-1); 551*0Sstevel@tonic-gate } else { 552*0Sstevel@tonic-gate minor_t mn; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * Support of non-clone open (ie, mknod with 556*0Sstevel@tonic-gate * defined minor number) is supported for 557*0Sstevel@tonic-gate * testing purposes so that 'arbitrary' minor 558*0Sstevel@tonic-gate * numbers can be used. 559*0Sstevel@tonic-gate */ 560*0Sstevel@tonic-gate mn = getminor(*devp); 561*0Sstevel@tonic-gate if (mn == 0 || (tcl = tcl_by_minor(mn)) != NULL) { 562*0Sstevel@tonic-gate return (EPERM); 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate tcl = tuncl_alloc(mn); 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate if (tcl == NULL) 567*0Sstevel@tonic-gate return (ENOSR); 568*0Sstevel@tonic-gate tcl->tcl_rq = q; /* save read queue pointer */ 569*0Sstevel@tonic-gate tcl->tcl_flags |= TCLF_ISCLIENT; /* sanity check */ 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = (caddr_t)tcl; 572*0Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), tcl->tcl_lsessid); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate tcl->tcl_ksp = kstat_setup((kstat_named_t *)&tcl->tcl_kstats, 575*0Sstevel@tonic-gate tcl_kstats_list, Dim(tcl_kstats_list), "tcl", 576*0Sstevel@tonic-gate tcl->tcl_lsessid); 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate qprocson(q); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate return (0); 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate /* 584*0Sstevel@tonic-gate * Create an appropriate control message for this client event. 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate static mblk_t * 587*0Sstevel@tonic-gate make_control(tuncl_t *tclabout, tunll_t *tllabout, int action, tuncl_t *tclto) 588*0Sstevel@tonic-gate { 589*0Sstevel@tonic-gate struct ppptun_control *ptc; 590*0Sstevel@tonic-gate mblk_t *mp = allocb(sizeof (*ptc), BPRI_HI); 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate if (mp != NULL) { 593*0Sstevel@tonic-gate MTYPE(mp) = M_PROTO; 594*0Sstevel@tonic-gate ptc = (struct ppptun_control *)mp->b_wptr; 595*0Sstevel@tonic-gate mp->b_wptr += sizeof (*ptc); 596*0Sstevel@tonic-gate if (tclabout != NULL) { 597*0Sstevel@tonic-gate ptc->ptc_rsessid = tclabout->tcl_rsessid; 598*0Sstevel@tonic-gate ptc->ptc_address = tclabout->tcl_address; 599*0Sstevel@tonic-gate } else { 600*0Sstevel@tonic-gate bzero(ptc, sizeof (*ptc)); 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate ptc->ptc_discrim = tclto->tcl_ctlval; 603*0Sstevel@tonic-gate ptc->ptc_action = action; 604*0Sstevel@tonic-gate (void) strncpy(ptc->ptc_name, tllabout->tll_name, 605*0Sstevel@tonic-gate sizeof (ptc->ptc_name)); 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate return (mp); 608*0Sstevel@tonic-gate } 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate /* 611*0Sstevel@tonic-gate * Send an appropriate control message up this client session. 612*0Sstevel@tonic-gate */ 613*0Sstevel@tonic-gate static void 614*0Sstevel@tonic-gate send_control(tuncl_t *tclabout, tunll_t *tllabout, int action, tuncl_t *tcl) 615*0Sstevel@tonic-gate { 616*0Sstevel@tonic-gate mblk_t *mp; 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate if (tcl->tcl_rq != NULL) { 619*0Sstevel@tonic-gate mp = make_control(tclabout, tllabout, action, tcl); 620*0Sstevel@tonic-gate if (mp != NULL) { 621*0Sstevel@tonic-gate KCINCR(cks_octrl_spec); 622*0Sstevel@tonic-gate putnext(tcl->tcl_rq, mp); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate } 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate /* 628*0Sstevel@tonic-gate * If a lower stream is being unplumbed, then the upper streams 629*0Sstevel@tonic-gate * connected to this lower stream must be disconnected. This routine 630*0Sstevel@tonic-gate * accomplishes this by sending M_HANGUP to data streams and M_PROTO 631*0Sstevel@tonic-gate * messages to control streams. This is called by vmem_walk, and 632*0Sstevel@tonic-gate * handles a span of minor node numbers. 633*0Sstevel@tonic-gate * 634*0Sstevel@tonic-gate * No need to update lks_clients here; the lower stream is on its way 635*0Sstevel@tonic-gate * out. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate static void 638*0Sstevel@tonic-gate tclvm_remove_tll(void *arg, void *firstv, size_t numv) 639*0Sstevel@tonic-gate { 640*0Sstevel@tonic-gate tunll_t *tll = (tunll_t *)arg; 641*0Sstevel@tonic-gate int minorn = (int)(uintptr_t)firstv; 642*0Sstevel@tonic-gate int minormax = minorn + numv; 643*0Sstevel@tonic-gate tuncl_t *tcl; 644*0Sstevel@tonic-gate mblk_t *mp; 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate while (minorn < minormax) { 647*0Sstevel@tonic-gate tcl = tcl_slots[minorn - 1]; 648*0Sstevel@tonic-gate ASSERT(tcl != NULL); 649*0Sstevel@tonic-gate if (tcl->tcl_data_tll == tll && tcl->tcl_rq != NULL) { 650*0Sstevel@tonic-gate tcl->tcl_data_tll = NULL; 651*0Sstevel@tonic-gate mp = allocb(0, BPRI_HI); 652*0Sstevel@tonic-gate if (mp != NULL) { 653*0Sstevel@tonic-gate MTYPE(mp) = M_HANGUP; 654*0Sstevel@tonic-gate putnext(tcl->tcl_rq, mp); 655*0Sstevel@tonic-gate if (tcl->tcl_ctrl_tll == tll) 656*0Sstevel@tonic-gate tcl->tcl_ctrl_tll = NULL; 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate if (tcl->tcl_ctrl_tll == tll) { 660*0Sstevel@tonic-gate send_control(tcl, tll, PTCA_UNPLUMB, tcl); 661*0Sstevel@tonic-gate tcl->tcl_ctrl_tll = NULL; 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate minorn++; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate } 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* 668*0Sstevel@tonic-gate * sppptun_close() 669*0Sstevel@tonic-gate * 670*0Sstevel@tonic-gate * MT-Perimeters: 671*0Sstevel@tonic-gate * exclusive inner, exclusive outer. 672*0Sstevel@tonic-gate * 673*0Sstevel@tonic-gate * Description: 674*0Sstevel@tonic-gate * Common close procedure for module and driver. 675*0Sstevel@tonic-gate */ 676*0Sstevel@tonic-gate static int 677*0Sstevel@tonic-gate sppptun_close(queue_t *q) 678*0Sstevel@tonic-gate { 679*0Sstevel@tonic-gate int err; 680*0Sstevel@tonic-gate void *qptr; 681*0Sstevel@tonic-gate tunll_t *tll; 682*0Sstevel@tonic-gate tuncl_t *tcl; 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate ASSERT(q != NULL); 685*0Sstevel@tonic-gate qptr = q->q_ptr; 686*0Sstevel@tonic-gate ASSERT(qptr != NULL); 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate err = 0; 689*0Sstevel@tonic-gate tll = (tunll_t *)qptr; 690*0Sstevel@tonic-gate if (!(tll->tll_flags & TLLF_NOTLOWER)) { 691*0Sstevel@tonic-gate /* q_next is set on modules */ 692*0Sstevel@tonic-gate ASSERT(WR(q)->q_next != NULL); 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate /* unlink any clients using this lower layer. */ 695*0Sstevel@tonic-gate vmem_walk(tcl_minor_arena, VMEM_ALLOC, tclvm_remove_tll, tll); 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate /* tell daemon that this has been removed. */ 698*0Sstevel@tonic-gate if ((tcl = tll->tll_defcl) != NULL) 699*0Sstevel@tonic-gate send_control(NULL, tll, PTCA_UNPLUMB, tcl); 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate tll->tll_flags |= TLLF_CLOSING; 702*0Sstevel@tonic-gate while (!(tll->tll_flags & TLLF_CLOSE_DONE)) { 703*0Sstevel@tonic-gate qenable(tll->tll_wq); 704*0Sstevel@tonic-gate qwait(tll->tll_wq); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate tll->tll_error = 0; 707*0Sstevel@tonic-gate while (!(tll->tll_flags & TLLF_SHUTDOWN_DONE)) { 708*0Sstevel@tonic-gate if (!qwait_sig(tll->tll_wq)) 709*0Sstevel@tonic-gate break; 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate qprocsoff(q); 713*0Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 714*0Sstevel@tonic-gate tll->tll_wq = NULL; 715*0Sstevel@tonic-gate remque(&tll->tll_next); 716*0Sstevel@tonic-gate err = tll->tll_error; 717*0Sstevel@tonic-gate if (tll->tll_ksp != NULL) 718*0Sstevel@tonic-gate kstat_delete(tll->tll_ksp); 719*0Sstevel@tonic-gate kmem_free(tll, sizeof (*tll)); 720*0Sstevel@tonic-gate } else { 721*0Sstevel@tonic-gate tcl = (tuncl_t *)tll; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate /* devices are end of line; no q_next. */ 724*0Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL); 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate qprocsoff(q); 727*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "session %d closed", tcl->tcl_rsessid)); 728*0Sstevel@tonic-gate tcl->tcl_rq = NULL; 729*0Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL; 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate tll = TO_TLL(tunll_list.q_forw); 732*0Sstevel@tonic-gate while (tll != TO_TLL(&tunll_list)) { 733*0Sstevel@tonic-gate if (tll->tll_defcl == tcl) 734*0Sstevel@tonic-gate tll->tll_defcl = NULL; 735*0Sstevel@tonic-gate if (tll->tll_lastcl == tcl) 736*0Sstevel@tonic-gate tll->tll_lastcl = NULL; 737*0Sstevel@tonic-gate tll = TO_TLL(tll->tll_next); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate /* 740*0Sstevel@tonic-gate * If this was a normal session, then tell the daemon. 741*0Sstevel@tonic-gate */ 742*0Sstevel@tonic-gate if (!(tcl->tcl_flags & TCLF_DAEMON) && 743*0Sstevel@tonic-gate (tll = tcl->tcl_ctrl_tll) != NULL && 744*0Sstevel@tonic-gate tll->tll_defcl != NULL) { 745*0Sstevel@tonic-gate DBGERROR((CE_CONT, "unexpected client disconnect")); 746*0Sstevel@tonic-gate send_control(tcl, tll, PTCA_DISCONNECT, 747*0Sstevel@tonic-gate tll->tll_defcl); 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate /* Update statistics for references being dropped. */ 751*0Sstevel@tonic-gate if ((tll = tcl->tcl_data_tll) != NULL) { 752*0Sstevel@tonic-gate KLDECR(lks_clients); 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate if ((tll = tcl->tcl_ctrl_tll) != NULL) { 755*0Sstevel@tonic-gate KLDECR(lks_clients); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate tuncl_free(tcl); 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate return (err); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate /* 765*0Sstevel@tonic-gate * Allocate and initialize a DLPI or TPI template of the specified 766*0Sstevel@tonic-gate * length. 767*0Sstevel@tonic-gate */ 768*0Sstevel@tonic-gate static mblk_t * 769*0Sstevel@tonic-gate pi_alloc(size_t len, int prim) 770*0Sstevel@tonic-gate { 771*0Sstevel@tonic-gate mblk_t *mp; 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate mp = allocb(len, BPRI_MED); 774*0Sstevel@tonic-gate if (mp != NULL) { 775*0Sstevel@tonic-gate MTYPE(mp) = M_PROTO; 776*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + len; 777*0Sstevel@tonic-gate bzero(mp->b_rptr, len); 778*0Sstevel@tonic-gate *(int *)mp->b_rptr = prim; 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate return (mp); 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate #define dlpi_alloc(l, p) pi_alloc((l), (p)) 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* 786*0Sstevel@tonic-gate * Prepend some room to an mblk. Try to reuse the existing buffer, if 787*0Sstevel@tonic-gate * at all possible, rather than allocating a new one. (Fast-path 788*0Sstevel@tonic-gate * output should be able to use this.) 789*0Sstevel@tonic-gate * 790*0Sstevel@tonic-gate * (XXX why isn't this a library function ...?) 791*0Sstevel@tonic-gate */ 792*0Sstevel@tonic-gate static mblk_t * 793*0Sstevel@tonic-gate prependb(mblk_t *mp, size_t len, size_t align) 794*0Sstevel@tonic-gate { 795*0Sstevel@tonic-gate mblk_t *newmp; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate if (align == 0) 799*0Sstevel@tonic-gate align = 8; 800*0Sstevel@tonic-gate if (DB_REF(mp) > 1 || mp->b_datap->db_base+len > mp->b_rptr || 801*0Sstevel@tonic-gate ((uint_t)((uintptr_t)mp->b_rptr - len) % align) != 0) { 802*0Sstevel@tonic-gate if ((newmp = allocb(len, BPRI_LO)) == NULL) { 803*0Sstevel@tonic-gate freemsg(mp); 804*0Sstevel@tonic-gate return (NULL); 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate newmp->b_wptr = newmp->b_rptr + len; 807*0Sstevel@tonic-gate newmp->b_cont = mp; 808*0Sstevel@tonic-gate return (newmp); 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate mp->b_rptr -= len; 811*0Sstevel@tonic-gate return (mp); 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate /* 815*0Sstevel@tonic-gate * sppptun_outpkt() 816*0Sstevel@tonic-gate * 817*0Sstevel@tonic-gate * MT-Perimeters: 818*0Sstevel@tonic-gate * shared inner, shared outer (if called from sppptun_uwput), 819*0Sstevel@tonic-gate * exclusive inner, shared outer (if called from sppptun_uwsrv). 820*0Sstevel@tonic-gate * 821*0Sstevel@tonic-gate * Description: 822*0Sstevel@tonic-gate * Called from sppptun_uwput or sppptun_uwsrv when processing a 823*0Sstevel@tonic-gate * M_DATA, M_PROTO, or M_PCPROTO message. For all cases, it tries 824*0Sstevel@tonic-gate * to prepare the data to be sent to the module below this driver 825*0Sstevel@tonic-gate * if there is a lower stream linked underneath. If no lower 826*0Sstevel@tonic-gate * stream exists, then the data will be discarded and an ENXIO 827*0Sstevel@tonic-gate * error returned. 828*0Sstevel@tonic-gate * 829*0Sstevel@tonic-gate * Returns: 830*0Sstevel@tonic-gate * pointer to queue if caller should do putnext, otherwise 831*0Sstevel@tonic-gate * *mpp != NULL if message should be enqueued, otherwise 832*0Sstevel@tonic-gate * *mpp == NULL if message is gone. 833*0Sstevel@tonic-gate */ 834*0Sstevel@tonic-gate static queue_t * 835*0Sstevel@tonic-gate sppptun_outpkt(queue_t *q, mblk_t **mpp) 836*0Sstevel@tonic-gate { 837*0Sstevel@tonic-gate mblk_t *mp; 838*0Sstevel@tonic-gate tuncl_t *tcl; 839*0Sstevel@tonic-gate tunll_t *tll; 840*0Sstevel@tonic-gate mblk_t *encmb; 841*0Sstevel@tonic-gate mblk_t *datamb; 842*0Sstevel@tonic-gate dl_unitdata_req_t *dur; 843*0Sstevel@tonic-gate queue_t *lowerq; 844*0Sstevel@tonic-gate poep_t *poep; 845*0Sstevel@tonic-gate int len; 846*0Sstevel@tonic-gate ether_dest_t *edestp; 847*0Sstevel@tonic-gate enum { luNone, luCopy, luSend } loopup; 848*0Sstevel@tonic-gate boolean_t isdata; 849*0Sstevel@tonic-gate struct ppptun_control *ptc; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate ASSERT(mpp != NULL); 852*0Sstevel@tonic-gate mp = *mpp; 853*0Sstevel@tonic-gate ASSERT(mp != NULL); 854*0Sstevel@tonic-gate ASSERT(q != NULL); 855*0Sstevel@tonic-gate tcl = (tuncl_t *)q->q_ptr; 856*0Sstevel@tonic-gate ASSERT(tcl != NULL); 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate *mpp = NULL; 859*0Sstevel@tonic-gate if (!(tcl->tcl_flags & TCLF_ISCLIENT)) { 860*0Sstevel@tonic-gate DBGERROR((CE_CONT, "discard data sent on lower stream\n")); 861*0Sstevel@tonic-gate merror(q, mp, EINVAL); 862*0Sstevel@tonic-gate return (NULL); 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate isdata = (MTYPE(mp) == M_DATA); 866*0Sstevel@tonic-gate if (isdata) { 867*0Sstevel@tonic-gate tll = tcl->tcl_data_tll; 868*0Sstevel@tonic-gate ptc = NULL; 869*0Sstevel@tonic-gate } else { 870*0Sstevel@tonic-gate /* 871*0Sstevel@tonic-gate * If data are unaligned or otherwise unsuitable, then 872*0Sstevel@tonic-gate * discard. 873*0Sstevel@tonic-gate */ 874*0Sstevel@tonic-gate if (MBLKL(mp) != sizeof (*ptc) || DB_REF(mp) > 1 || 875*0Sstevel@tonic-gate !IS_P2ALIGNED(mp->b_rptr, sizeof (ptc))) { 876*0Sstevel@tonic-gate KCINCR(cks_octrl_drop); 877*0Sstevel@tonic-gate DBGERROR((CE_CONT, "discard bad control message\n")); 878*0Sstevel@tonic-gate merror(q, mp, EINVAL); 879*0Sstevel@tonic-gate return (NULL); 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate ptc = (struct ppptun_control *)mp->b_rptr; 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate /* Set stream discriminator value if not yet set. */ 884*0Sstevel@tonic-gate if (tcl->tcl_ctlval == 0) 885*0Sstevel@tonic-gate tcl->tcl_ctlval = ptc->ptc_discrim; 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate /* If this is a test message, then reply to caller. */ 888*0Sstevel@tonic-gate if (ptc->ptc_action == PTCA_TEST) { 889*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "sending test reply")); 890*0Sstevel@tonic-gate if (mp->b_cont != NULL) { 891*0Sstevel@tonic-gate freemsg(mp->b_cont); 892*0Sstevel@tonic-gate mp->b_cont = NULL; 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate ptc->ptc_discrim = tcl->tcl_ctlval; 895*0Sstevel@tonic-gate putnext(RD(q), mp); 896*0Sstevel@tonic-gate return (NULL); 897*0Sstevel@tonic-gate } 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate /* If this one isn't for us, then discard it */ 900*0Sstevel@tonic-gate if (tcl->tcl_ctlval != ptc->ptc_discrim) { 901*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "Discriminator %X != %X; ignoring", 902*0Sstevel@tonic-gate tcl->tcl_ctlval, ptc->ptc_discrim)); 903*0Sstevel@tonic-gate freemsg(mp); 904*0Sstevel@tonic-gate return (NULL); 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate /* Don't allow empty control packets. */ 908*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 909*0Sstevel@tonic-gate KCINCR(cks_octrl_drop); 910*0Sstevel@tonic-gate merror(q, mp, EINVAL); 911*0Sstevel@tonic-gate return (NULL); 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate tll = tcl->tcl_ctrl_tll; 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate if (tll == NULL || (lowerq = tll->tll_wq) == NULL) { 917*0Sstevel@tonic-gate DBGERROR((CE_CONT, "can't send; no %s on %X\n", 918*0Sstevel@tonic-gate tll == NULL ? "attached lower layer" : "output queue", 919*0Sstevel@tonic-gate tll == NULL ? (unsigned)tcl : (unsigned)tll)); 920*0Sstevel@tonic-gate merror(q, mp, ENXIO); 921*0Sstevel@tonic-gate if (isdata) { 922*0Sstevel@tonic-gate tcl->tcl_stats.ppp_oerrors++; 923*0Sstevel@tonic-gate } else { 924*0Sstevel@tonic-gate KCINCR(cks_octrl_drop); 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate return (NULL); 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate /* 930*0Sstevel@tonic-gate * If so, then try to send it down. The lower queue is only 931*0Sstevel@tonic-gate * ever detached while holding an exclusive lock on the whole 932*0Sstevel@tonic-gate * driver, so we can be confident that the lower queue is 933*0Sstevel@tonic-gate * still there. 934*0Sstevel@tonic-gate */ 935*0Sstevel@tonic-gate if (!bcanputnext(lowerq, mp->b_band)) { 936*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "can't send; !canputnext\n")); 937*0Sstevel@tonic-gate *mpp = mp; 938*0Sstevel@tonic-gate return (NULL); 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate /* 942*0Sstevel@tonic-gate * Note: DLPI and TPI expect that the first buffer contains 943*0Sstevel@tonic-gate * the control (unitdata-req) header, destination address, and 944*0Sstevel@tonic-gate * nothing else. Any protocol headers must go in the next 945*0Sstevel@tonic-gate * buffer. 946*0Sstevel@tonic-gate */ 947*0Sstevel@tonic-gate loopup = luNone; 948*0Sstevel@tonic-gate encmb = NULL; 949*0Sstevel@tonic-gate if (isdata) { 950*0Sstevel@tonic-gate if (tll->tll_alen != 0 && 951*0Sstevel@tonic-gate bcmp(&tcl->tcl_address, &tll->tll_lcladdr, 952*0Sstevel@tonic-gate tll->tll_alen) == 0) 953*0Sstevel@tonic-gate loopup = luSend; 954*0Sstevel@tonic-gate switch (tll->tll_style) { 955*0Sstevel@tonic-gate case PTS_PPPOE: 956*0Sstevel@tonic-gate /* Strip address and control fields if present. */ 957*0Sstevel@tonic-gate if (mp->b_rptr[0] == 0xFF) { 958*0Sstevel@tonic-gate if (MBLKL(mp) < 3) { 959*0Sstevel@tonic-gate encmb = msgpullup(mp, 3); 960*0Sstevel@tonic-gate freemsg(mp); 961*0Sstevel@tonic-gate if ((mp = encmb) == NULL) 962*0Sstevel@tonic-gate break; 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate mp->b_rptr += 2; 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate /* Broadcasting data is probably not a good idea. */ 967*0Sstevel@tonic-gate if (tcl->tcl_address.pta_pppoe.ptma_mac[0] & 1) 968*0Sstevel@tonic-gate break; 969*0Sstevel@tonic-gate encmb = dlpi_alloc(sizeof (*dur) + sizeof (*edestp), 970*0Sstevel@tonic-gate DL_UNITDATA_REQ); 971*0Sstevel@tonic-gate if (encmb == NULL) 972*0Sstevel@tonic-gate break; 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate dur = (dl_unitdata_req_t *)encmb->b_rptr; 975*0Sstevel@tonic-gate dur->dl_dest_addr_length = sizeof (*edestp); 976*0Sstevel@tonic-gate dur->dl_dest_addr_offset = sizeof (*dur); 977*0Sstevel@tonic-gate edestp = (ether_dest_t *)(dur + 1); 978*0Sstevel@tonic-gate ether_copy(tcl->tcl_address.pta_pppoe.ptma_mac, 979*0Sstevel@tonic-gate edestp->addr); 980*0Sstevel@tonic-gate /* DLPI SAPs are in host byte order! */ 981*0Sstevel@tonic-gate edestp->type = ETHERTYPE_PPPOES; 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate /* Make sure the protocol field isn't compressed. */ 984*0Sstevel@tonic-gate len = (*mp->b_rptr & 1); 985*0Sstevel@tonic-gate mp = prependb(mp, sizeof (*poep) + len, POE_HDR_ALIGN); 986*0Sstevel@tonic-gate if (mp == NULL) 987*0Sstevel@tonic-gate break; 988*0Sstevel@tonic-gate poep = (poep_t *)mp->b_rptr; 989*0Sstevel@tonic-gate poep->poep_version_type = POE_VERSION; 990*0Sstevel@tonic-gate poep->poep_code = POECODE_DATA; 991*0Sstevel@tonic-gate poep->poep_session_id = htons(tcl->tcl_rsessid); 992*0Sstevel@tonic-gate poep->poep_length = htons(msgsize(mp) - 993*0Sstevel@tonic-gate sizeof (*poep)); 994*0Sstevel@tonic-gate if (len > 0) 995*0Sstevel@tonic-gate *(char *)(poep + 1) = '\0'; 996*0Sstevel@tonic-gate break; 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate default: 999*0Sstevel@tonic-gate ASSERT(0); 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate } else { 1002*0Sstevel@tonic-gate /* 1003*0Sstevel@tonic-gate * Control side encapsulation. 1004*0Sstevel@tonic-gate */ 1005*0Sstevel@tonic-gate if (bcmp(&ptc->ptc_address, &tll->tll_lcladdr, tll->tll_alen) 1006*0Sstevel@tonic-gate == 0) 1007*0Sstevel@tonic-gate loopup = luSend; 1008*0Sstevel@tonic-gate datamb = mp->b_cont; 1009*0Sstevel@tonic-gate switch (tll->tll_style) { 1010*0Sstevel@tonic-gate case PTS_PPPOE: 1011*0Sstevel@tonic-gate /* 1012*0Sstevel@tonic-gate * Don't allow a loopback session to establish 1013*0Sstevel@tonic-gate * itself. PPPoE is broken; it uses only one 1014*0Sstevel@tonic-gate * session ID for both data directions, so the 1015*0Sstevel@tonic-gate * loopback data path can simply never work. 1016*0Sstevel@tonic-gate */ 1017*0Sstevel@tonic-gate if (loopup == luSend && 1018*0Sstevel@tonic-gate ((poep_t *)datamb->b_rptr)->poep_code == 1019*0Sstevel@tonic-gate POECODE_PADR) 1020*0Sstevel@tonic-gate break; 1021*0Sstevel@tonic-gate encmb = dlpi_alloc(sizeof (*dur) + sizeof (*edestp), 1022*0Sstevel@tonic-gate DL_UNITDATA_REQ); 1023*0Sstevel@tonic-gate if (encmb == NULL) 1024*0Sstevel@tonic-gate break; 1025*0Sstevel@tonic-gate dur = (dl_unitdata_req_t *)encmb->b_rptr; 1026*0Sstevel@tonic-gate dur->dl_dest_addr_length = sizeof (*edestp); 1027*0Sstevel@tonic-gate dur->dl_dest_addr_offset = sizeof (*dur); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate edestp = (ether_dest_t *)(dur + 1); 1030*0Sstevel@tonic-gate /* DLPI SAPs are in host byte order! */ 1031*0Sstevel@tonic-gate edestp->type = ETHERTYPE_PPPOED; 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate /* 1034*0Sstevel@tonic-gate * If destination isn't set yet, then we have to 1035*0Sstevel@tonic-gate * allow anything at all. Otherwise, force use 1036*0Sstevel@tonic-gate * of configured peer address. 1037*0Sstevel@tonic-gate */ 1038*0Sstevel@tonic-gate if (bcmp(tcl->tcl_address.pta_pppoe.ptma_mac, 1039*0Sstevel@tonic-gate zero_mac_addr, sizeof (zero_mac_addr)) == 0 || 1040*0Sstevel@tonic-gate (tcl->tcl_flags & TCLF_DAEMON)) { 1041*0Sstevel@tonic-gate ether_copy(ptc->ptc_address.pta_pppoe.ptma_mac, 1042*0Sstevel@tonic-gate edestp->addr); 1043*0Sstevel@tonic-gate } else { 1044*0Sstevel@tonic-gate ether_copy(tcl->tcl_address.pta_pppoe.ptma_mac, 1045*0Sstevel@tonic-gate edestp->addr); 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate /* Reflect multicast/broadcast back up. */ 1048*0Sstevel@tonic-gate if (edestp->addr[0] & 1) 1049*0Sstevel@tonic-gate loopup = luCopy; 1050*0Sstevel@tonic-gate break; 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate case PTS_PPTP: 1053*0Sstevel@tonic-gate /* 1054*0Sstevel@tonic-gate * PPTP's control side is actually done over 1055*0Sstevel@tonic-gate * separate TCP connections. 1056*0Sstevel@tonic-gate */ 1057*0Sstevel@tonic-gate default: 1058*0Sstevel@tonic-gate ASSERT(0); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate freeb(mp); 1061*0Sstevel@tonic-gate mp = datamb; 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate if (mp == NULL || encmb == NULL) { 1064*0Sstevel@tonic-gate DBGERROR((CE_CONT, "output failure\n")); 1065*0Sstevel@tonic-gate freemsg(mp); 1066*0Sstevel@tonic-gate freemsg(encmb); 1067*0Sstevel@tonic-gate if (isdata) { 1068*0Sstevel@tonic-gate tcl->tcl_stats.ppp_oerrors++; 1069*0Sstevel@tonic-gate } else { 1070*0Sstevel@tonic-gate KCINCR(cks_octrl_drop); 1071*0Sstevel@tonic-gate KLINCR(lks_octrl_drop); 1072*0Sstevel@tonic-gate } 1073*0Sstevel@tonic-gate lowerq = NULL; 1074*0Sstevel@tonic-gate } else { 1075*0Sstevel@tonic-gate if (tcl->tcl_flags & TCLF_DEBUG) 1076*0Sstevel@tonic-gate sppp_dump_frame(tcl->tcl_unit, mp, 1077*0Sstevel@tonic-gate isdata ? "sent" : "sctl"); 1078*0Sstevel@tonic-gate if (isdata) { 1079*0Sstevel@tonic-gate tcl->tcl_stats.ppp_obytes += msgsize(mp); 1080*0Sstevel@tonic-gate tcl->tcl_stats.ppp_opackets++; 1081*0Sstevel@tonic-gate } else { 1082*0Sstevel@tonic-gate KCINCR(cks_octrls); 1083*0Sstevel@tonic-gate KLINCR(lks_octrls); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate if (encmb != mp) 1086*0Sstevel@tonic-gate encmb->b_cont = mp; 1087*0Sstevel@tonic-gate switch (loopup) { 1088*0Sstevel@tonic-gate case luNone: 1089*0Sstevel@tonic-gate *mpp = encmb; 1090*0Sstevel@tonic-gate break; 1091*0Sstevel@tonic-gate case luCopy: 1092*0Sstevel@tonic-gate mp = copymsg(encmb); 1093*0Sstevel@tonic-gate if (mp != NULL) 1094*0Sstevel@tonic-gate sppptun_urput(RD(lowerq), mp); 1095*0Sstevel@tonic-gate *mpp = encmb; 1096*0Sstevel@tonic-gate break; 1097*0Sstevel@tonic-gate case luSend: 1098*0Sstevel@tonic-gate sppptun_urput(RD(lowerq), encmb); 1099*0Sstevel@tonic-gate lowerq = NULL; 1100*0Sstevel@tonic-gate break; 1101*0Sstevel@tonic-gate } 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate return (lowerq); 1104*0Sstevel@tonic-gate } 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate /* 1107*0Sstevel@tonic-gate * Enqueue a message to be sent when the lower stream is closed. This 1108*0Sstevel@tonic-gate * is done so that we're guaranteed that we always have the necessary 1109*0Sstevel@tonic-gate * resources to properly detach ourselves from the system. (If we 1110*0Sstevel@tonic-gate * waited until the close was done to allocate these messages, then 1111*0Sstevel@tonic-gate * the message allocation could fail, and we'd be unable to properly 1112*0Sstevel@tonic-gate * detach.) 1113*0Sstevel@tonic-gate */ 1114*0Sstevel@tonic-gate static void 1115*0Sstevel@tonic-gate save_for_close(tunll_t *tll, mblk_t *mp) 1116*0Sstevel@tonic-gate { 1117*0Sstevel@tonic-gate mblk_t *onc; 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate if ((onc = tll->tll_onclose) == NULL) 1120*0Sstevel@tonic-gate tll->tll_onclose = mp; 1121*0Sstevel@tonic-gate else { 1122*0Sstevel@tonic-gate while (onc->b_next != NULL) 1123*0Sstevel@tonic-gate onc = onc->b_next; 1124*0Sstevel@tonic-gate onc->b_next = mp; 1125*0Sstevel@tonic-gate } 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate /* 1129*0Sstevel@tonic-gate * Given the lower stream name, locate the state structure. Note that 1130*0Sstevel@tonic-gate * lookup of tcl pointers (and use of those pointers) is safe because 1131*0Sstevel@tonic-gate * modification is done only when exclusive on both inner and outer 1132*0Sstevel@tonic-gate * perimeters. 1133*0Sstevel@tonic-gate */ 1134*0Sstevel@tonic-gate static tunll_t * 1135*0Sstevel@tonic-gate tll_lookup_on_name(char *dname) 1136*0Sstevel@tonic-gate { 1137*0Sstevel@tonic-gate tunll_t *tll; 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate tll = TO_TLL(tunll_list.q_forw); 1140*0Sstevel@tonic-gate for (; tll != TO_TLL(&tunll_list); tll = TO_TLL(tll->tll_next)) 1141*0Sstevel@tonic-gate if (strcmp(dname, tll->tll_name) == 0) 1142*0Sstevel@tonic-gate return (tll); 1143*0Sstevel@tonic-gate return (NULL); 1144*0Sstevel@tonic-gate } 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate /* 1147*0Sstevel@tonic-gate * sppptun_inner_ioctl() 1148*0Sstevel@tonic-gate * 1149*0Sstevel@tonic-gate * MT-Perimeters: 1150*0Sstevel@tonic-gate * exclusive inner, shared outer. 1151*0Sstevel@tonic-gate * 1152*0Sstevel@tonic-gate * Description: 1153*0Sstevel@tonic-gate * Called by qwriter from sppptun_ioctl as the result of receiving 1154*0Sstevel@tonic-gate * a handled ioctl. 1155*0Sstevel@tonic-gate */ 1156*0Sstevel@tonic-gate static void 1157*0Sstevel@tonic-gate sppptun_inner_ioctl(queue_t *q, mblk_t *mp) 1158*0Sstevel@tonic-gate { 1159*0Sstevel@tonic-gate struct iocblk *iop; 1160*0Sstevel@tonic-gate int rc = 0; 1161*0Sstevel@tonic-gate int len = 0; 1162*0Sstevel@tonic-gate int i; 1163*0Sstevel@tonic-gate tuncl_t *tcl; 1164*0Sstevel@tonic-gate tunll_t *tll; 1165*0Sstevel@tonic-gate union ppptun_name *ptn; 1166*0Sstevel@tonic-gate struct ppptun_info *pti; 1167*0Sstevel@tonic-gate struct ppptun_peer *ptp; 1168*0Sstevel@tonic-gate mblk_t *mptmp; 1169*0Sstevel@tonic-gate ppptun_atype *pap; 1170*0Sstevel@tonic-gate struct ppp_stats64 *psp; 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate ASSERT(q != NULL); 1173*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 1174*0Sstevel@tonic-gate ASSERT(mp != NULL); 1175*0Sstevel@tonic-gate ASSERT(mp->b_rptr != NULL); 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate iop = (struct iocblk *)mp->b_rptr; 1178*0Sstevel@tonic-gate tcl = NULL; 1179*0Sstevel@tonic-gate tll = (tunll_t *)q->q_ptr; 1180*0Sstevel@tonic-gate if (tll->tll_flags & TLLF_NOTLOWER) { 1181*0Sstevel@tonic-gate tcl = (tuncl_t *)tll; 1182*0Sstevel@tonic-gate tll = NULL; 1183*0Sstevel@tonic-gate } 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate switch (iop->ioc_cmd) { 1186*0Sstevel@tonic-gate case PPPIO_DEBUG: 1187*0Sstevel@tonic-gate /* Client (device) side only */ 1188*0Sstevel@tonic-gate if (tcl == NULL || iop->ioc_count != sizeof (uint32_t) || 1189*0Sstevel@tonic-gate mp->b_cont == NULL) { 1190*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad PPPIO_DEBUG")); 1191*0Sstevel@tonic-gate rc = EINVAL; 1192*0Sstevel@tonic-gate break; 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate /* just one type of debug so far */ 1196*0Sstevel@tonic-gate i = *(uint32_t *)mp->b_cont->b_rptr; 1197*0Sstevel@tonic-gate if (i != PPPDBG_LOG + PPPDBG_AHDLC) 1198*0Sstevel@tonic-gate rc = EINVAL; 1199*0Sstevel@tonic-gate else 1200*0Sstevel@tonic-gate tcl->tcl_flags |= TCLF_DEBUG; 1201*0Sstevel@tonic-gate break; 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate case PPPIO_GETSTAT: 1204*0Sstevel@tonic-gate rc = EINVAL; 1205*0Sstevel@tonic-gate break; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate case PPPIO_GETSTAT64: 1208*0Sstevel@tonic-gate /* Client (device) side only */ 1209*0Sstevel@tonic-gate if (tcl == NULL) { 1210*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad PPPIO_GETSTAT64")); 1211*0Sstevel@tonic-gate rc = EINVAL; 1212*0Sstevel@tonic-gate break; 1213*0Sstevel@tonic-gate } 1214*0Sstevel@tonic-gate mptmp = allocb(sizeof (*psp), BPRI_HI); 1215*0Sstevel@tonic-gate if (mptmp == NULL) { 1216*0Sstevel@tonic-gate rc = ENOSR; 1217*0Sstevel@tonic-gate break; 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate freemsg(mp->b_cont); 1220*0Sstevel@tonic-gate mp->b_cont = mptmp; 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate psp = (struct ppp_stats64 *)mptmp->b_wptr; 1223*0Sstevel@tonic-gate bzero((caddr_t)psp, sizeof (*psp)); 1224*0Sstevel@tonic-gate psp->p = tcl->tcl_stats; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate len = sizeof (*psp); 1227*0Sstevel@tonic-gate break; 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate case PPPTUN_SNAME: 1230*0Sstevel@tonic-gate /* This is done on the *module* (lower level) side. */ 1231*0Sstevel@tonic-gate if (tll == NULL || mp->b_cont == NULL || 1232*0Sstevel@tonic-gate iop->ioc_count != sizeof (*ptn) || 1233*0Sstevel@tonic-gate *mp->b_cont->b_rptr == '\0') { 1234*0Sstevel@tonic-gate rc = EINVAL; 1235*0Sstevel@tonic-gate break; 1236*0Sstevel@tonic-gate } 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate ptn = (union ppptun_name *)mp->b_cont->b_rptr; 1239*0Sstevel@tonic-gate ptn->ptn_name[sizeof (ptn->ptn_name) - 1] = '\0'; 1240*0Sstevel@tonic-gate 1241*0Sstevel@tonic-gate if ((tll = tll_lookup_on_name(ptn->ptn_name)) != NULL) { 1242*0Sstevel@tonic-gate rc = EEXIST; 1243*0Sstevel@tonic-gate break; 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate tll = (tunll_t *)q->q_ptr; 1246*0Sstevel@tonic-gate (void) strcpy(tll->tll_name, ptn->ptn_name); 1247*0Sstevel@tonic-gate break; 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate case PPPTUN_GNAME: 1250*0Sstevel@tonic-gate /* This is done on the *module* (lower level) side. */ 1251*0Sstevel@tonic-gate if (tll == NULL) { 1252*0Sstevel@tonic-gate rc = EINVAL; 1253*0Sstevel@tonic-gate break; 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate if (mp->b_cont != NULL) 1256*0Sstevel@tonic-gate freemsg(mp->b_cont); 1257*0Sstevel@tonic-gate if ((mp->b_cont = allocb(sizeof (*ptn), BPRI_HI)) == NULL) { 1258*0Sstevel@tonic-gate rc = ENOSR; 1259*0Sstevel@tonic-gate break; 1260*0Sstevel@tonic-gate } 1261*0Sstevel@tonic-gate ptn = (union ppptun_name *)mp->b_cont->b_rptr; 1262*0Sstevel@tonic-gate bcopy(tll->tll_name, ptn->ptn_name, sizeof (ptn->ptn_name)); 1263*0Sstevel@tonic-gate len = sizeof (*ptn); 1264*0Sstevel@tonic-gate break; 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate case PPPTUN_SINFO: 1267*0Sstevel@tonic-gate case PPPTUN_GINFO: 1268*0Sstevel@tonic-gate /* Either side */ 1269*0Sstevel@tonic-gate if (mp->b_cont == NULL || iop->ioc_count != sizeof (*pti)) { 1270*0Sstevel@tonic-gate DBGERROR((CE_CONT, "missing ioctl data")); 1271*0Sstevel@tonic-gate rc = EINVAL; 1272*0Sstevel@tonic-gate break; 1273*0Sstevel@tonic-gate } 1274*0Sstevel@tonic-gate pti = (struct ppptun_info *)mp->b_cont->b_rptr; 1275*0Sstevel@tonic-gate if (pti->pti_name[0] != '\0') 1276*0Sstevel@tonic-gate tll = tll_lookup_on_name(pti->pti_name); 1277*0Sstevel@tonic-gate if (tll == NULL) { 1278*0Sstevel@tonic-gate /* Driver (client) side must have name */ 1279*0Sstevel@tonic-gate if (tcl != NULL && pti->pti_name[0] == '\0') { 1280*0Sstevel@tonic-gate DBGERROR((CE_CONT, 1281*0Sstevel@tonic-gate "null sinfo name on driver")); 1282*0Sstevel@tonic-gate rc = EINVAL; 1283*0Sstevel@tonic-gate } else 1284*0Sstevel@tonic-gate rc = ESRCH; 1285*0Sstevel@tonic-gate break; 1286*0Sstevel@tonic-gate } 1287*0Sstevel@tonic-gate if (iop->ioc_cmd == PPPTUN_GINFO) { 1288*0Sstevel@tonic-gate pti->pti_muxid = tll->tll_muxid; 1289*0Sstevel@tonic-gate pti->pti_style = tll->tll_style; 1290*0Sstevel@tonic-gate len = sizeof (*pti); 1291*0Sstevel@tonic-gate break; 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate tll->tll_muxid = pti->pti_muxid; 1294*0Sstevel@tonic-gate tll->tll_style = pti->pti_style; 1295*0Sstevel@tonic-gate switch (tll->tll_style) { 1296*0Sstevel@tonic-gate case PTS_PPPOE: /* DLPI type */ 1297*0Sstevel@tonic-gate tll->tll_alen = sizeof (tll->tll_lcladdr.pta_pppoe); 1298*0Sstevel@tonic-gate mptmp = dlpi_alloc(sizeof (dl_unbind_req_t), 1299*0Sstevel@tonic-gate DL_UNBIND_REQ); 1300*0Sstevel@tonic-gate if (mptmp == NULL) { 1301*0Sstevel@tonic-gate rc = ENOSR; 1302*0Sstevel@tonic-gate break; 1303*0Sstevel@tonic-gate } 1304*0Sstevel@tonic-gate save_for_close(tll, mptmp); 1305*0Sstevel@tonic-gate mptmp = dlpi_alloc(sizeof (dl_detach_req_t), 1306*0Sstevel@tonic-gate DL_DETACH_REQ); 1307*0Sstevel@tonic-gate if (mptmp == NULL) { 1308*0Sstevel@tonic-gate rc = ENOSR; 1309*0Sstevel@tonic-gate break; 1310*0Sstevel@tonic-gate } 1311*0Sstevel@tonic-gate save_for_close(tll, mptmp); 1312*0Sstevel@tonic-gate break; 1313*0Sstevel@tonic-gate default: 1314*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad style %d driver", 1315*0Sstevel@tonic-gate tll->tll_style)); 1316*0Sstevel@tonic-gate tll->tll_style = PTS_NONE; 1317*0Sstevel@tonic-gate tll->tll_alen = 0; 1318*0Sstevel@tonic-gate rc = EINVAL; 1319*0Sstevel@tonic-gate break; 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate break; 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate case PPPTUN_GNNAME: 1324*0Sstevel@tonic-gate /* This can be done on either side. */ 1325*0Sstevel@tonic-gate if (mp->b_cont == NULL || iop->ioc_count < sizeof (uint32_t)) { 1326*0Sstevel@tonic-gate rc = EINVAL; 1327*0Sstevel@tonic-gate break; 1328*0Sstevel@tonic-gate } 1329*0Sstevel@tonic-gate ptn = (union ppptun_name *)mp->b_cont->b_rptr; 1330*0Sstevel@tonic-gate i = ptn->ptn_index; 1331*0Sstevel@tonic-gate tll = TO_TLL(tunll_list.q_forw); 1332*0Sstevel@tonic-gate while (--i >= 0 && tll != TO_TLL(&tunll_list)) 1333*0Sstevel@tonic-gate tll = TO_TLL(tll->tll_next); 1334*0Sstevel@tonic-gate if (tll != TO_TLL(&tunll_list)) { 1335*0Sstevel@tonic-gate bcopy(tll->tll_name, ptn->ptn_name, 1336*0Sstevel@tonic-gate sizeof (ptn->ptn_name)); 1337*0Sstevel@tonic-gate } else { 1338*0Sstevel@tonic-gate bzero(ptn, sizeof (*ptn)); 1339*0Sstevel@tonic-gate } 1340*0Sstevel@tonic-gate len = sizeof (*ptn); 1341*0Sstevel@tonic-gate break; 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate case PPPTUN_LCLADDR: 1344*0Sstevel@tonic-gate /* This is done on the *module* (lower level) side. */ 1345*0Sstevel@tonic-gate if (tll == NULL || mp->b_cont == NULL) { 1346*0Sstevel@tonic-gate rc = EINVAL; 1347*0Sstevel@tonic-gate break; 1348*0Sstevel@tonic-gate } 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate pap = &tll->tll_lcladdr; 1351*0Sstevel@tonic-gate len = tll->tll_alen; 1352*0Sstevel@tonic-gate if (len == 0 || len > iop->ioc_count) { 1353*0Sstevel@tonic-gate rc = EINVAL; 1354*0Sstevel@tonic-gate break; 1355*0Sstevel@tonic-gate } 1356*0Sstevel@tonic-gate bcopy(mp->b_cont->b_rptr, pap, len); 1357*0Sstevel@tonic-gate len = 0; 1358*0Sstevel@tonic-gate break; 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate case PPPTUN_SPEER: 1361*0Sstevel@tonic-gate /* Client (device) side only; before SDATA */ 1362*0Sstevel@tonic-gate if (tcl == NULL || mp->b_cont == NULL || 1363*0Sstevel@tonic-gate iop->ioc_count != sizeof (*ptp)) { 1364*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad speer ioctl")); 1365*0Sstevel@tonic-gate rc = EINVAL; 1366*0Sstevel@tonic-gate break; 1367*0Sstevel@tonic-gate } 1368*0Sstevel@tonic-gate if (tcl->tcl_data_tll != NULL) { 1369*0Sstevel@tonic-gate DBGERROR((CE_CONT, "data link already set")); 1370*0Sstevel@tonic-gate rc = EINVAL; 1371*0Sstevel@tonic-gate break; 1372*0Sstevel@tonic-gate } 1373*0Sstevel@tonic-gate ptp = (struct ppptun_peer *)mp->b_cont->b_rptr; 1374*0Sstevel@tonic-gate /* Once set, the style cannot change. */ 1375*0Sstevel@tonic-gate if (tcl->tcl_style != PTS_NONE && 1376*0Sstevel@tonic-gate tcl->tcl_style != ptp->ptp_style) { 1377*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad style; %d != %d", 1378*0Sstevel@tonic-gate tcl->tcl_style, ptp->ptp_style)); 1379*0Sstevel@tonic-gate rc = EINVAL; 1380*0Sstevel@tonic-gate break; 1381*0Sstevel@tonic-gate } 1382*0Sstevel@tonic-gate if (ptp->ptp_flags & PTPF_DAEMON) { 1383*0Sstevel@tonic-gate /* User requests registration for tunnel 0 */ 1384*0Sstevel@tonic-gate if ((tcl->tcl_flags & TCLF_SPEER_DONE) || 1385*0Sstevel@tonic-gate ptp->ptp_ltunid != 0 || ptp->ptp_rtunid != 0 || 1386*0Sstevel@tonic-gate ptp->ptp_lsessid != 0 || ptp->ptp_rsessid != 0) { 1387*0Sstevel@tonic-gate rc = EINVAL; 1388*0Sstevel@tonic-gate break; 1389*0Sstevel@tonic-gate } 1390*0Sstevel@tonic-gate tcl->tcl_flags |= TCLF_DAEMON; 1391*0Sstevel@tonic-gate } else { 1392*0Sstevel@tonic-gate /* Normal client connection */ 1393*0Sstevel@tonic-gate if (tcl->tcl_flags & TCLF_DAEMON) { 1394*0Sstevel@tonic-gate DBGERROR((CE_CONT, "can't change to daemon")); 1395*0Sstevel@tonic-gate rc = EINVAL; 1396*0Sstevel@tonic-gate break; 1397*0Sstevel@tonic-gate } 1398*0Sstevel@tonic-gate if (ptp->ptp_lsessid != 0 && 1399*0Sstevel@tonic-gate ptp->ptp_lsessid != tcl->tcl_lsessid) { 1400*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad lsessid; %d != %d", 1401*0Sstevel@tonic-gate ptp->ptp_lsessid, tcl->tcl_lsessid)); 1402*0Sstevel@tonic-gate rc = EINVAL; 1403*0Sstevel@tonic-gate break; 1404*0Sstevel@tonic-gate } 1405*0Sstevel@tonic-gate /* 1406*0Sstevel@tonic-gate * If we're reassigning the peer data, then 1407*0Sstevel@tonic-gate * the previous assignment must have been for 1408*0Sstevel@tonic-gate * a client control connection. Check that. 1409*0Sstevel@tonic-gate */ 1410*0Sstevel@tonic-gate if ((tcl->tcl_flags & TCLF_SPEER_DONE) && 1411*0Sstevel@tonic-gate ((tcl->tcl_ltunid != 0 && 1412*0Sstevel@tonic-gate tcl->tcl_ltunid != ptp->ptp_ltunid) || 1413*0Sstevel@tonic-gate (tcl->tcl_rtunid != 0 && 1414*0Sstevel@tonic-gate tcl->tcl_rtunid != ptp->ptp_rtunid) || 1415*0Sstevel@tonic-gate (tcl->tcl_rsessid != 0 && 1416*0Sstevel@tonic-gate tcl->tcl_rsessid != ptp->ptp_rsessid))) { 1417*0Sstevel@tonic-gate DBGERROR((CE_CONT, "can't change parameters")); 1418*0Sstevel@tonic-gate rc = EINVAL; 1419*0Sstevel@tonic-gate break; 1420*0Sstevel@tonic-gate } 1421*0Sstevel@tonic-gate if ((tcl->tcl_ltunid = ptp->ptp_ltunid) == 0 && 1422*0Sstevel@tonic-gate tcl->tcl_style == PTS_L2FTP) 1423*0Sstevel@tonic-gate tcl->tcl_ltunid = ptp->ptp_lsessid; 1424*0Sstevel@tonic-gate tcl->tcl_rtunid = ptp->ptp_rtunid; 1425*0Sstevel@tonic-gate tcl->tcl_rsessid = ptp->ptp_rsessid; 1426*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "set session ID to %d", 1427*0Sstevel@tonic-gate tcl->tcl_rsessid)); 1428*0Sstevel@tonic-gate } 1429*0Sstevel@tonic-gate tcl->tcl_flags |= TCLF_SPEER_DONE; 1430*0Sstevel@tonic-gate tcl->tcl_style = ptp->ptp_style; 1431*0Sstevel@tonic-gate tcl->tcl_address = ptp->ptp_address; 1432*0Sstevel@tonic-gate goto fill_in_peer; 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate case PPPTUN_GPEER: 1435*0Sstevel@tonic-gate /* Client (device) side only */ 1436*0Sstevel@tonic-gate if (tcl == NULL) { 1437*0Sstevel@tonic-gate rc = EINVAL; 1438*0Sstevel@tonic-gate break; 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate if (mp->b_cont != NULL) 1441*0Sstevel@tonic-gate freemsg(mp->b_cont); 1442*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (*ptp), BPRI_HI); 1443*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 1444*0Sstevel@tonic-gate rc = ENOSR; 1445*0Sstevel@tonic-gate break; 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate ptp = (struct ppptun_peer *)mp->b_cont->b_rptr; 1448*0Sstevel@tonic-gate fill_in_peer: 1449*0Sstevel@tonic-gate ptp->ptp_style = tcl->tcl_style; 1450*0Sstevel@tonic-gate ptp->ptp_flags = (tcl->tcl_flags & TCLF_DAEMON) ? PTPF_DAEMON : 1451*0Sstevel@tonic-gate 0; 1452*0Sstevel@tonic-gate ptp->ptp_ltunid = tcl->tcl_ltunid; 1453*0Sstevel@tonic-gate ptp->ptp_rtunid = tcl->tcl_rtunid; 1454*0Sstevel@tonic-gate ptp->ptp_lsessid = tcl->tcl_lsessid; 1455*0Sstevel@tonic-gate ptp->ptp_rsessid = tcl->tcl_rsessid; 1456*0Sstevel@tonic-gate ptp->ptp_address = tcl->tcl_address; 1457*0Sstevel@tonic-gate len = sizeof (*ptp); 1458*0Sstevel@tonic-gate break; 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate case PPPTUN_SDATA: 1461*0Sstevel@tonic-gate case PPPTUN_SCTL: 1462*0Sstevel@tonic-gate /* Client (device) side only; must do SPEER first */ 1463*0Sstevel@tonic-gate if (tcl == NULL || mp->b_cont == NULL || 1464*0Sstevel@tonic-gate iop->ioc_count != sizeof (*ptn) || 1465*0Sstevel@tonic-gate *mp->b_cont->b_rptr == '\0') { 1466*0Sstevel@tonic-gate DBGERROR((CE_CONT, "bad ioctl data")); 1467*0Sstevel@tonic-gate rc = EINVAL; 1468*0Sstevel@tonic-gate break; 1469*0Sstevel@tonic-gate } 1470*0Sstevel@tonic-gate if (!(tcl->tcl_flags & TCLF_SPEER_DONE)) { 1471*0Sstevel@tonic-gate DBGERROR((CE_CONT, "speer not yet done")); 1472*0Sstevel@tonic-gate rc = EINVAL; 1473*0Sstevel@tonic-gate break; 1474*0Sstevel@tonic-gate } 1475*0Sstevel@tonic-gate ptn = (union ppptun_name *)mp->b_cont->b_rptr; 1476*0Sstevel@tonic-gate ptn->ptn_name[sizeof (ptn->ptn_name) - 1] = '\0'; 1477*0Sstevel@tonic-gate tll = tll_lookup_on_name(ptn->ptn_name); 1478*0Sstevel@tonic-gate if (tll == NULL) { 1479*0Sstevel@tonic-gate DBGERROR((CE_CONT, "cannot locate \"%s\"", 1480*0Sstevel@tonic-gate ptn->ptn_name)); 1481*0Sstevel@tonic-gate rc = ESRCH; 1482*0Sstevel@tonic-gate break; 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate if (tll->tll_style != tcl->tcl_style) { 1485*0Sstevel@tonic-gate DBGERROR((CE_CONT, "user style %d doesn't match lower" 1486*0Sstevel@tonic-gate " style %d", tcl->tcl_style, tll->tll_style)); 1487*0Sstevel@tonic-gate rc = ENXIO; 1488*0Sstevel@tonic-gate break; 1489*0Sstevel@tonic-gate } 1490*0Sstevel@tonic-gate if (iop->ioc_cmd == PPPTUN_SDATA) { 1491*0Sstevel@tonic-gate if (tcl->tcl_data_tll != NULL) { 1492*0Sstevel@tonic-gate DBGERROR((CE_CONT, "data link already set")); 1493*0Sstevel@tonic-gate rc = EEXIST; 1494*0Sstevel@tonic-gate break; 1495*0Sstevel@tonic-gate } 1496*0Sstevel@tonic-gate /* server daemons cannot use regular data */ 1497*0Sstevel@tonic-gate if (tcl->tcl_flags & TCLF_DAEMON) { 1498*0Sstevel@tonic-gate DBGERROR((CE_CONT, "daemon has no data")); 1499*0Sstevel@tonic-gate rc = EINVAL; 1500*0Sstevel@tonic-gate break; 1501*0Sstevel@tonic-gate } 1502*0Sstevel@tonic-gate tcl->tcl_data_tll = tll; 1503*0Sstevel@tonic-gate } else if (tcl->tcl_flags & TCLF_DAEMON) { 1504*0Sstevel@tonic-gate if (tll->tll_defcl != NULL && tll->tll_defcl != tcl) { 1505*0Sstevel@tonic-gate DBGERROR((CE_CONT, 1506*0Sstevel@tonic-gate "control link already set")); 1507*0Sstevel@tonic-gate rc = EEXIST; 1508*0Sstevel@tonic-gate break; 1509*0Sstevel@tonic-gate } 1510*0Sstevel@tonic-gate tll->tll_defcl = tcl; 1511*0Sstevel@tonic-gate if (tcl->tcl_ctrl_tll != NULL) { 1512*0Sstevel@tonic-gate KDECR(tcl->tcl_ctrl_tll, tll_kstats, 1513*0Sstevel@tonic-gate lks_clients); 1514*0Sstevel@tonic-gate } 1515*0Sstevel@tonic-gate tcl->tcl_ctrl_tll = tll; 1516*0Sstevel@tonic-gate } else { 1517*0Sstevel@tonic-gate if (tcl->tcl_ctrl_tll != NULL) { 1518*0Sstevel@tonic-gate DBGERROR((CE_CONT, 1519*0Sstevel@tonic-gate "control link already set")); 1520*0Sstevel@tonic-gate rc = EEXIST; 1521*0Sstevel@tonic-gate break; 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate tcl->tcl_ctrl_tll = tll; 1524*0Sstevel@tonic-gate } 1525*0Sstevel@tonic-gate KLINCR(lks_clients); 1526*0Sstevel@tonic-gate break; 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate case PPPTUN_GDATA: 1529*0Sstevel@tonic-gate case PPPTUN_GCTL: 1530*0Sstevel@tonic-gate /* Client (device) side only */ 1531*0Sstevel@tonic-gate if (tcl == NULL) { 1532*0Sstevel@tonic-gate rc = EINVAL; 1533*0Sstevel@tonic-gate break; 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate if (mp->b_cont != NULL) 1536*0Sstevel@tonic-gate freemsg(mp->b_cont); 1537*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (*ptn), BPRI_HI); 1538*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 1539*0Sstevel@tonic-gate rc = ENOSR; 1540*0Sstevel@tonic-gate break; 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate ptn = (union ppptun_name *)mp->b_cont->b_rptr; 1543*0Sstevel@tonic-gate if (iop->ioc_cmd == PPPTUN_GDATA) 1544*0Sstevel@tonic-gate tll = tcl->tcl_data_tll; 1545*0Sstevel@tonic-gate else 1546*0Sstevel@tonic-gate tll = tcl->tcl_ctrl_tll; 1547*0Sstevel@tonic-gate if (tll == NULL) 1548*0Sstevel@tonic-gate bzero(ptn, sizeof (*ptn)); 1549*0Sstevel@tonic-gate else 1550*0Sstevel@tonic-gate bcopy(tll->tll_name, ptn->ptn_name, 1551*0Sstevel@tonic-gate sizeof (ptn->ptn_name)); 1552*0Sstevel@tonic-gate len = sizeof (*ptn); 1553*0Sstevel@tonic-gate break; 1554*0Sstevel@tonic-gate 1555*0Sstevel@tonic-gate case PPPTUN_DCTL: 1556*0Sstevel@tonic-gate /* Client (device) side daemon mode only */ 1557*0Sstevel@tonic-gate if (tcl == NULL || mp->b_cont == NULL || 1558*0Sstevel@tonic-gate iop->ioc_count != sizeof (*ptn) || 1559*0Sstevel@tonic-gate !(tcl->tcl_flags & TCLF_DAEMON)) { 1560*0Sstevel@tonic-gate rc = EINVAL; 1561*0Sstevel@tonic-gate break; 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate ptn = (union ppptun_name *)mp->b_cont->b_rptr; 1564*0Sstevel@tonic-gate ptn->ptn_name[sizeof (ptn->ptn_name) - 1] = '\0'; 1565*0Sstevel@tonic-gate tll = tll_lookup_on_name(ptn->ptn_name); 1566*0Sstevel@tonic-gate if (tll == NULL || tll->tll_defcl != tcl) { 1567*0Sstevel@tonic-gate DBGERROR((CE_CONT, "cannot locate \"%s\"", 1568*0Sstevel@tonic-gate ptn->ptn_name)); 1569*0Sstevel@tonic-gate rc = ESRCH; 1570*0Sstevel@tonic-gate break; 1571*0Sstevel@tonic-gate } 1572*0Sstevel@tonic-gate tll->tll_defcl = NULL; 1573*0Sstevel@tonic-gate break; 1574*0Sstevel@tonic-gate 1575*0Sstevel@tonic-gate default: 1576*0Sstevel@tonic-gate /* Caller should already have checked command value */ 1577*0Sstevel@tonic-gate ASSERT(0); 1578*0Sstevel@tonic-gate } 1579*0Sstevel@tonic-gate if (rc != 0) { 1580*0Sstevel@tonic-gate DBGERROR((CE_CONT, "error %d for ioctl %X", rc, iop->ioc_cmd)); 1581*0Sstevel@tonic-gate miocnak(q, mp, 0, rc); 1582*0Sstevel@tonic-gate } else { 1583*0Sstevel@tonic-gate if (len > 0) 1584*0Sstevel@tonic-gate mp->b_cont->b_wptr = mp->b_cont->b_rptr + len; 1585*0Sstevel@tonic-gate miocack(q, mp, len, 0); 1586*0Sstevel@tonic-gate } 1587*0Sstevel@tonic-gate } 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gate /* 1590*0Sstevel@tonic-gate * sppptun_ioctl() 1591*0Sstevel@tonic-gate * 1592*0Sstevel@tonic-gate * MT-Perimeters: 1593*0Sstevel@tonic-gate * shared inner, shared outer. 1594*0Sstevel@tonic-gate * 1595*0Sstevel@tonic-gate * Description: 1596*0Sstevel@tonic-gate * Called by sppptun_uwput as the result of receiving a M_IOCTL command. 1597*0Sstevel@tonic-gate */ 1598*0Sstevel@tonic-gate static void 1599*0Sstevel@tonic-gate sppptun_ioctl(queue_t *q, mblk_t *mp) 1600*0Sstevel@tonic-gate { 1601*0Sstevel@tonic-gate struct iocblk *iop; 1602*0Sstevel@tonic-gate int rc = 0; 1603*0Sstevel@tonic-gate int len = 0; 1604*0Sstevel@tonic-gate uint32_t val = 0; 1605*0Sstevel@tonic-gate tunll_t *tll; 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate ASSERT(q != NULL); 1608*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 1609*0Sstevel@tonic-gate ASSERT(mp != NULL); 1610*0Sstevel@tonic-gate ASSERT(mp->b_rptr != NULL); 1611*0Sstevel@tonic-gate 1612*0Sstevel@tonic-gate iop = (struct iocblk *)mp->b_rptr; 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "got ioctl %X\n", iop->ioc_cmd)); 1615*0Sstevel@tonic-gate switch (iop->ioc_cmd) { 1616*0Sstevel@tonic-gate case PPPIO_DEBUG: 1617*0Sstevel@tonic-gate case PPPIO_GETSTAT: 1618*0Sstevel@tonic-gate case PPPIO_GETSTAT64: 1619*0Sstevel@tonic-gate case PPPTUN_SNAME: 1620*0Sstevel@tonic-gate case PPPTUN_GNAME: 1621*0Sstevel@tonic-gate case PPPTUN_SINFO: 1622*0Sstevel@tonic-gate case PPPTUN_GINFO: 1623*0Sstevel@tonic-gate case PPPTUN_GNNAME: 1624*0Sstevel@tonic-gate case PPPTUN_LCLADDR: 1625*0Sstevel@tonic-gate case PPPTUN_SPEER: 1626*0Sstevel@tonic-gate case PPPTUN_GPEER: 1627*0Sstevel@tonic-gate case PPPTUN_SDATA: 1628*0Sstevel@tonic-gate case PPPTUN_GDATA: 1629*0Sstevel@tonic-gate case PPPTUN_SCTL: 1630*0Sstevel@tonic-gate case PPPTUN_GCTL: 1631*0Sstevel@tonic-gate case PPPTUN_DCTL: 1632*0Sstevel@tonic-gate qwriter(q, mp, sppptun_inner_ioctl, PERIM_INNER); 1633*0Sstevel@tonic-gate return; 1634*0Sstevel@tonic-gate 1635*0Sstevel@tonic-gate case PPPIO_GCLEAN: /* always clean */ 1636*0Sstevel@tonic-gate val = RCV_B7_1 | RCV_B7_0 | RCV_ODDP | RCV_EVNP; 1637*0Sstevel@tonic-gate len = sizeof (uint32_t); 1638*0Sstevel@tonic-gate break; 1639*0Sstevel@tonic-gate 1640*0Sstevel@tonic-gate case PPPIO_GTYPE: /* we look like an async driver. */ 1641*0Sstevel@tonic-gate val = PPPTYP_AHDLC; 1642*0Sstevel@tonic-gate len = sizeof (uint32_t); 1643*0Sstevel@tonic-gate break; 1644*0Sstevel@tonic-gate 1645*0Sstevel@tonic-gate case PPPIO_CFLAGS: /* never compress headers */ 1646*0Sstevel@tonic-gate val = 0; 1647*0Sstevel@tonic-gate len = sizeof (uint32_t); 1648*0Sstevel@tonic-gate break; 1649*0Sstevel@tonic-gate 1650*0Sstevel@tonic-gate /* quietly ack PPP things we don't need to do. */ 1651*0Sstevel@tonic-gate case PPPIO_XFCS: 1652*0Sstevel@tonic-gate case PPPIO_RFCS: 1653*0Sstevel@tonic-gate case PPPIO_XACCM: 1654*0Sstevel@tonic-gate case PPPIO_RACCM: 1655*0Sstevel@tonic-gate case PPPIO_LASTMOD: 1656*0Sstevel@tonic-gate case PPPIO_MUX: 1657*0Sstevel@tonic-gate case I_PLINK: 1658*0Sstevel@tonic-gate case I_PUNLINK: 1659*0Sstevel@tonic-gate case I_LINK: 1660*0Sstevel@tonic-gate case I_UNLINK: 1661*0Sstevel@tonic-gate break; 1662*0Sstevel@tonic-gate 1663*0Sstevel@tonic-gate default: 1664*0Sstevel@tonic-gate tll = (tunll_t *)q->q_ptr; 1665*0Sstevel@tonic-gate if (!(tll->tll_flags & TLLF_NOTLOWER)) { 1666*0Sstevel@tonic-gate /* module side; pass this through. */ 1667*0Sstevel@tonic-gate putnext(q, mp); 1668*0Sstevel@tonic-gate return; 1669*0Sstevel@tonic-gate } 1670*0Sstevel@tonic-gate rc = EINVAL; 1671*0Sstevel@tonic-gate break; 1672*0Sstevel@tonic-gate } 1673*0Sstevel@tonic-gate if (rc == 0 && len == sizeof (uint32_t)) { 1674*0Sstevel@tonic-gate if (mp->b_cont != NULL) 1675*0Sstevel@tonic-gate freemsg(mp->b_cont); 1676*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (uint32_t), BPRI_HI); 1677*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 1678*0Sstevel@tonic-gate rc = ENOSR; 1679*0Sstevel@tonic-gate } else { 1680*0Sstevel@tonic-gate *(uint32_t *)mp->b_cont->b_wptr = val; 1681*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (uint32_t); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate } 1684*0Sstevel@tonic-gate if (rc == 0) { 1685*0Sstevel@tonic-gate miocack(q, mp, len, 0); 1686*0Sstevel@tonic-gate } else { 1687*0Sstevel@tonic-gate DBGERROR((CE_CONT, "error %d for ioctl %X", rc, iop->ioc_cmd)); 1688*0Sstevel@tonic-gate miocnak(q, mp, 0, rc); 1689*0Sstevel@tonic-gate } 1690*0Sstevel@tonic-gate } 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate /* 1693*0Sstevel@tonic-gate * sppptun_inner_mctl() 1694*0Sstevel@tonic-gate * 1695*0Sstevel@tonic-gate * MT-Perimeters: 1696*0Sstevel@tonic-gate * exclusive inner, shared outer. 1697*0Sstevel@tonic-gate * 1698*0Sstevel@tonic-gate * Description: 1699*0Sstevel@tonic-gate * Called by qwriter (via sppptun_uwput) as the result of receiving 1700*0Sstevel@tonic-gate * an M_CTL. Called only on the client (driver) side. 1701*0Sstevel@tonic-gate */ 1702*0Sstevel@tonic-gate static void 1703*0Sstevel@tonic-gate sppptun_inner_mctl(queue_t *q, mblk_t *mp) 1704*0Sstevel@tonic-gate { 1705*0Sstevel@tonic-gate int msglen; 1706*0Sstevel@tonic-gate tuncl_t *tcl; 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate ASSERT(q != NULL && mp != NULL); 1709*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL && mp->b_rptr != NULL); 1710*0Sstevel@tonic-gate 1711*0Sstevel@tonic-gate tcl = (tuncl_t *)q->q_ptr; 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate if (!(tcl->tcl_flags & TCLF_ISCLIENT)) { 1714*0Sstevel@tonic-gate freemsg(mp); 1715*0Sstevel@tonic-gate return; 1716*0Sstevel@tonic-gate } 1717*0Sstevel@tonic-gate 1718*0Sstevel@tonic-gate msglen = MBLKL(mp); 1719*0Sstevel@tonic-gate switch (*mp->b_rptr) { 1720*0Sstevel@tonic-gate case PPPCTL_UNIT: 1721*0Sstevel@tonic-gate if (msglen == 2) 1722*0Sstevel@tonic-gate tcl->tcl_unit = mp->b_rptr[1]; 1723*0Sstevel@tonic-gate else if (msglen == 8) 1724*0Sstevel@tonic-gate tcl->tcl_unit = ((uint32_t *)mp->b_rptr)[1]; 1725*0Sstevel@tonic-gate break; 1726*0Sstevel@tonic-gate } 1727*0Sstevel@tonic-gate freemsg(mp); 1728*0Sstevel@tonic-gate } 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate /* 1731*0Sstevel@tonic-gate * sppptun_uwput() 1732*0Sstevel@tonic-gate * 1733*0Sstevel@tonic-gate * MT-Perimeters: 1734*0Sstevel@tonic-gate * shared inner, shared outer. 1735*0Sstevel@tonic-gate * 1736*0Sstevel@tonic-gate * Description: 1737*0Sstevel@tonic-gate * Regular output data and controls pass through here. 1738*0Sstevel@tonic-gate */ 1739*0Sstevel@tonic-gate static void 1740*0Sstevel@tonic-gate sppptun_uwput(queue_t *q, mblk_t *mp) 1741*0Sstevel@tonic-gate { 1742*0Sstevel@tonic-gate queue_t *nextq; 1743*0Sstevel@tonic-gate tuncl_t *tcl; 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate ASSERT(q != NULL); 1746*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 1747*0Sstevel@tonic-gate ASSERT(mp != NULL); 1748*0Sstevel@tonic-gate ASSERT(mp->b_rptr != NULL); 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate DBGENTRY((CE_CONT, "sppptun_uwput as %s", DBGQSIDE(q))); 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate switch (MTYPE(mp)) { 1753*0Sstevel@tonic-gate case M_DATA: 1754*0Sstevel@tonic-gate case M_PROTO: 1755*0Sstevel@tonic-gate case M_PCPROTO: 1756*0Sstevel@tonic-gate if (q->q_first == NULL && 1757*0Sstevel@tonic-gate (nextq = sppptun_outpkt(q, &mp)) != NULL) { 1758*0Sstevel@tonic-gate putnext(nextq, mp); 1759*0Sstevel@tonic-gate } else if (mp != NULL && !putq(q, mp)) { 1760*0Sstevel@tonic-gate freemsg(mp); 1761*0Sstevel@tonic-gate } 1762*0Sstevel@tonic-gate break; 1763*0Sstevel@tonic-gate case M_IOCTL: 1764*0Sstevel@tonic-gate sppptun_ioctl(q, mp); 1765*0Sstevel@tonic-gate break; 1766*0Sstevel@tonic-gate case M_CTL: 1767*0Sstevel@tonic-gate qwriter(q, mp, sppptun_inner_mctl, PERIM_INNER); 1768*0Sstevel@tonic-gate break; 1769*0Sstevel@tonic-gate default: 1770*0Sstevel@tonic-gate tcl = (tuncl_t *)q->q_ptr; 1771*0Sstevel@tonic-gate /* 1772*0Sstevel@tonic-gate * If we're the driver, then discard unknown junk. 1773*0Sstevel@tonic-gate * Otherwise, if we're the module, then forward along. 1774*0Sstevel@tonic-gate */ 1775*0Sstevel@tonic-gate if (tcl->tcl_flags & TCLF_ISCLIENT) 1776*0Sstevel@tonic-gate freemsg(mp); 1777*0Sstevel@tonic-gate else 1778*0Sstevel@tonic-gate putnext(q, mp); 1779*0Sstevel@tonic-gate break; 1780*0Sstevel@tonic-gate } 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate /* 1784*0Sstevel@tonic-gate * Send a DLPI/TPI control message to the driver but make sure there 1785*0Sstevel@tonic-gate * is only one outstanding message. Uses tll_msg_pending to tell when 1786*0Sstevel@tonic-gate * it must queue. sppptun_urput calls message_done() when an ACK or a 1787*0Sstevel@tonic-gate * NAK is received to process the next queued message. 1788*0Sstevel@tonic-gate */ 1789*0Sstevel@tonic-gate static void 1790*0Sstevel@tonic-gate message_send(tunll_t *tll, mblk_t *mp) 1791*0Sstevel@tonic-gate { 1792*0Sstevel@tonic-gate mblk_t **mpp; 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate if (tll->tll_msg_pending) { 1795*0Sstevel@tonic-gate /* Must queue message. Tail insertion */ 1796*0Sstevel@tonic-gate mpp = &tll->tll_msg_deferred; 1797*0Sstevel@tonic-gate while (*mpp != NULL) 1798*0Sstevel@tonic-gate mpp = &((*mpp)->b_next); 1799*0Sstevel@tonic-gate *mpp = mp; 1800*0Sstevel@tonic-gate return; 1801*0Sstevel@tonic-gate } 1802*0Sstevel@tonic-gate tll->tll_msg_pending = 1; 1803*0Sstevel@tonic-gate putnext(tll->tll_wq, mp); 1804*0Sstevel@tonic-gate } 1805*0Sstevel@tonic-gate 1806*0Sstevel@tonic-gate /* 1807*0Sstevel@tonic-gate * Called when an DLPI/TPI control message has been acked or nacked to 1808*0Sstevel@tonic-gate * send down the next queued message (if any). 1809*0Sstevel@tonic-gate */ 1810*0Sstevel@tonic-gate static void 1811*0Sstevel@tonic-gate message_done(tunll_t *tll) 1812*0Sstevel@tonic-gate { 1813*0Sstevel@tonic-gate mblk_t *mp; 1814*0Sstevel@tonic-gate 1815*0Sstevel@tonic-gate ASSERT(tll->tll_msg_pending); 1816*0Sstevel@tonic-gate tll->tll_msg_pending = 0; 1817*0Sstevel@tonic-gate mp = tll->tll_msg_deferred; 1818*0Sstevel@tonic-gate if (mp != NULL) { 1819*0Sstevel@tonic-gate tll->tll_msg_deferred = mp->b_next; 1820*0Sstevel@tonic-gate mp->b_next = NULL; 1821*0Sstevel@tonic-gate tll->tll_msg_pending = 1; 1822*0Sstevel@tonic-gate putnext(tll->tll_wq, mp); 1823*0Sstevel@tonic-gate } 1824*0Sstevel@tonic-gate } 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate /* 1827*0Sstevel@tonic-gate * Send down queued "close" messages to lower stream. These were 1828*0Sstevel@tonic-gate * enqueued right after the stream was originally allocated, when the 1829*0Sstevel@tonic-gate * tll_style was set by PPPTUN_SINFO. 1830*0Sstevel@tonic-gate */ 1831*0Sstevel@tonic-gate static int 1832*0Sstevel@tonic-gate tll_close_req(tunll_t *tll) 1833*0Sstevel@tonic-gate { 1834*0Sstevel@tonic-gate mblk_t *mb, *mbnext; 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate if ((mb = tll->tll_onclose) == NULL) 1837*0Sstevel@tonic-gate tll->tll_flags |= TLLF_SHUTDOWN_DONE; 1838*0Sstevel@tonic-gate else { 1839*0Sstevel@tonic-gate tll->tll_onclose = NULL; 1840*0Sstevel@tonic-gate while (mb != NULL) { 1841*0Sstevel@tonic-gate mbnext = mb->b_next; 1842*0Sstevel@tonic-gate mb->b_next = NULL; 1843*0Sstevel@tonic-gate message_send(tll, mb); 1844*0Sstevel@tonic-gate mb = mbnext; 1845*0Sstevel@tonic-gate } 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate return (0); 1848*0Sstevel@tonic-gate } 1849*0Sstevel@tonic-gate 1850*0Sstevel@tonic-gate /* 1851*0Sstevel@tonic-gate * sppptun_uwsrv() 1852*0Sstevel@tonic-gate * 1853*0Sstevel@tonic-gate * MT-Perimeters: 1854*0Sstevel@tonic-gate * exclusive inner, shared outer. 1855*0Sstevel@tonic-gate * 1856*0Sstevel@tonic-gate * Description: 1857*0Sstevel@tonic-gate * Upper write-side service procedure. In addition to the usual 1858*0Sstevel@tonic-gate * STREAMS queue service handling, this routine also handles the 1859*0Sstevel@tonic-gate * transmission of the unbind/detach messages to the lower stream 1860*0Sstevel@tonic-gate * driver when a lower stream is being closed. (See the use of 1861*0Sstevel@tonic-gate * qenable/qwait in sppptun_close().) 1862*0Sstevel@tonic-gate */ 1863*0Sstevel@tonic-gate static int 1864*0Sstevel@tonic-gate sppptun_uwsrv(queue_t *q) 1865*0Sstevel@tonic-gate { 1866*0Sstevel@tonic-gate tuncl_t *tcl; 1867*0Sstevel@tonic-gate mblk_t *mp; 1868*0Sstevel@tonic-gate queue_t *nextq; 1869*0Sstevel@tonic-gate 1870*0Sstevel@tonic-gate ASSERT(q != NULL); 1871*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 1872*0Sstevel@tonic-gate 1873*0Sstevel@tonic-gate tcl = (tuncl_t *)q->q_ptr; 1874*0Sstevel@tonic-gate if (!(tcl->tcl_flags & TCLF_ISCLIENT)) { 1875*0Sstevel@tonic-gate tunll_t *tll = (tunll_t *)tcl; 1876*0Sstevel@tonic-gate if ((tll->tll_flags & (TLLF_CLOSING|TLLF_CLOSE_DONE)) == 1877*0Sstevel@tonic-gate TLLF_CLOSING) { 1878*0Sstevel@tonic-gate DBGPLUMB((CE_CONT, "sending close req\n")); 1879*0Sstevel@tonic-gate tll->tll_error = tll_close_req(tll); 1880*0Sstevel@tonic-gate tll->tll_flags |= TLLF_CLOSE_DONE; 1881*0Sstevel@tonic-gate } 1882*0Sstevel@tonic-gate return (0); 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate 1885*0Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 1886*0Sstevel@tonic-gate if ((nextq = sppptun_outpkt(q, &mp)) != NULL) { 1887*0Sstevel@tonic-gate putnext(nextq, mp); 1888*0Sstevel@tonic-gate } else if (mp != NULL) { 1889*0Sstevel@tonic-gate (void) putbq(q, mp); 1890*0Sstevel@tonic-gate break; 1891*0Sstevel@tonic-gate } 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate return (0); 1894*0Sstevel@tonic-gate } 1895*0Sstevel@tonic-gate 1896*0Sstevel@tonic-gate /* 1897*0Sstevel@tonic-gate * sppptun_lwput() 1898*0Sstevel@tonic-gate * 1899*0Sstevel@tonic-gate * MT-Perimeters: 1900*0Sstevel@tonic-gate * shared inner, shared outer. 1901*0Sstevel@tonic-gate * 1902*0Sstevel@tonic-gate * Description: 1903*0Sstevel@tonic-gate * Lower write-side put procedure. Nothing should be sending 1904*0Sstevel@tonic-gate * packets down this stream. 1905*0Sstevel@tonic-gate */ 1906*0Sstevel@tonic-gate static void 1907*0Sstevel@tonic-gate sppptun_lwput(queue_t *q, mblk_t *mp) 1908*0Sstevel@tonic-gate { 1909*0Sstevel@tonic-gate ASSERT(q != NULL); 1910*0Sstevel@tonic-gate ASSERT(mp != NULL); 1911*0Sstevel@tonic-gate DBGENTRY((CE_CONT, "sppptun_lwput as %s", DBGQSIDE(q))); 1912*0Sstevel@tonic-gate 1913*0Sstevel@tonic-gate switch (MTYPE(mp)) { 1914*0Sstevel@tonic-gate case M_PROTO: 1915*0Sstevel@tonic-gate putnext(q, mp); 1916*0Sstevel@tonic-gate break; 1917*0Sstevel@tonic-gate default: 1918*0Sstevel@tonic-gate freemsg(mp); 1919*0Sstevel@tonic-gate break; 1920*0Sstevel@tonic-gate } 1921*0Sstevel@tonic-gate } 1922*0Sstevel@tonic-gate 1923*0Sstevel@tonic-gate /* 1924*0Sstevel@tonic-gate * sppptun_lrput() 1925*0Sstevel@tonic-gate * 1926*0Sstevel@tonic-gate * MT-Perimeters: 1927*0Sstevel@tonic-gate * shared inner, shared outer. 1928*0Sstevel@tonic-gate * 1929*0Sstevel@tonic-gate * Description: 1930*0Sstevel@tonic-gate * Lower read-side put procedure. Nothing should arrive here. 1931*0Sstevel@tonic-gate */ 1932*0Sstevel@tonic-gate static void 1933*0Sstevel@tonic-gate sppptun_lrput(queue_t *q, mblk_t *mp) 1934*0Sstevel@tonic-gate { 1935*0Sstevel@tonic-gate tuncl_t *tcl; 1936*0Sstevel@tonic-gate 1937*0Sstevel@tonic-gate ASSERT(q != NULL); 1938*0Sstevel@tonic-gate ASSERT(mp != NULL); 1939*0Sstevel@tonic-gate 1940*0Sstevel@tonic-gate DBGENTRY((CE_CONT, "sppptun_lrput as %s", DBGQSIDE(q))); 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate switch (MTYPE(mp)) { 1943*0Sstevel@tonic-gate case M_IOCTL: 1944*0Sstevel@tonic-gate DBGERROR((CE_CONT, "unexpected lrput ioctl")); 1945*0Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL); 1946*0Sstevel@tonic-gate return; 1947*0Sstevel@tonic-gate case M_FLUSH: 1948*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 1949*0Sstevel@tonic-gate flushq(q, FLUSHDATA); 1950*0Sstevel@tonic-gate } 1951*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 1952*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHR; 1953*0Sstevel@tonic-gate qreply(q, mp); 1954*0Sstevel@tonic-gate } else { 1955*0Sstevel@tonic-gate freemsg(mp); 1956*0Sstevel@tonic-gate } 1957*0Sstevel@tonic-gate return; 1958*0Sstevel@tonic-gate } 1959*0Sstevel@tonic-gate /* 1960*0Sstevel@tonic-gate * Try to forward the message to the put procedure for the upper 1961*0Sstevel@tonic-gate * control stream for this lower stream. If there are already messages 1962*0Sstevel@tonic-gate * queued here, queue this one up to preserve message ordering. 1963*0Sstevel@tonic-gate */ 1964*0Sstevel@tonic-gate if ((tcl = (tuncl_t *)q->q_ptr) == NULL || tcl->tcl_rq == NULL) { 1965*0Sstevel@tonic-gate freemsg(mp); 1966*0Sstevel@tonic-gate return; 1967*0Sstevel@tonic-gate } 1968*0Sstevel@tonic-gate if (queclass(mp) == QPCTL || 1969*0Sstevel@tonic-gate (q->q_first == NULL && canput(tcl->tcl_rq))) { 1970*0Sstevel@tonic-gate put(tcl->tcl_rq, mp); 1971*0Sstevel@tonic-gate } else { 1972*0Sstevel@tonic-gate if (!putq(q, mp)) 1973*0Sstevel@tonic-gate freemsg(mp); 1974*0Sstevel@tonic-gate } 1975*0Sstevel@tonic-gate } 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gate /* 1978*0Sstevel@tonic-gate * MT-Perimeters: 1979*0Sstevel@tonic-gate * shared inner, shared outer. 1980*0Sstevel@tonic-gate * 1981*0Sstevel@tonic-gate * Handle non-data DLPI messages. Used with PPPoE, which runs over 1982*0Sstevel@tonic-gate * Ethernet only. 1983*0Sstevel@tonic-gate */ 1984*0Sstevel@tonic-gate static void 1985*0Sstevel@tonic-gate urput_dlpi(queue_t *q, mblk_t *mp) 1986*0Sstevel@tonic-gate { 1987*0Sstevel@tonic-gate int err; 1988*0Sstevel@tonic-gate union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr; 1989*0Sstevel@tonic-gate tunll_t *tll = (tunll_t *)q->q_ptr; 1990*0Sstevel@tonic-gate 1991*0Sstevel@tonic-gate DBGNORMAL((CE_CONT, "received DLPI primitive %d\n", 1992*0Sstevel@tonic-gate dlp->dl_primitive)); 1993*0Sstevel@tonic-gate switch (dlp->dl_primitive) { 1994*0Sstevel@tonic-gate case DL_UDERROR_IND: 1995*0Sstevel@tonic-gate DBGERROR((CE_CONT, "uderror: unix %d, dlpi %d\n", 1996*0Sstevel@tonic-gate dlp->uderror_ind.dl_unix_errno, 1997*0Sstevel@tonic-gate dlp->uderror_ind.dl_errno)); 1998*0Sstevel@tonic-gate break; 1999*0Sstevel@tonic-gate 2000*0Sstevel@tonic-gate case DL_ERROR_ACK: 2001*0Sstevel@tonic-gate DBGERROR((CE_CONT, 2002*0Sstevel@tonic-gate "error-ack: unix %d, dlpi %d on primitive %d\n", 2003*0Sstevel@tonic-gate dlp->error_ack.dl_unix_errno, 2004*0Sstevel@tonic-gate dlp->error_ack.dl_errno, 2005*0Sstevel@tonic-gate dlp->error_ack.dl_error_primitive)); 2006*0Sstevel@tonic-gate err = dlp->error_ack.dl_unix_errno ? 2007*0Sstevel@tonic-gate dlp->error_ack.dl_unix_errno : ENXIO; 2008*0Sstevel@tonic-gate switch (dlp->error_ack.dl_error_primitive) { 2009*0Sstevel@tonic-gate case DL_UNBIND_REQ: 2010*0Sstevel@tonic-gate message_done(tll); 2011*0Sstevel@tonic-gate break; 2012*0Sstevel@tonic-gate case DL_DETACH_REQ: 2013*0Sstevel@tonic-gate message_done(tll); 2014*0Sstevel@tonic-gate tll->tll_error = err; 2015*0Sstevel@tonic-gate DBGPLUMB((CE_CONT, "detach error %d; shutdown done\n", 2016*0Sstevel@tonic-gate err)); 2017*0Sstevel@tonic-gate tll->tll_flags |= TLLF_SHUTDOWN_DONE; 2018*0Sstevel@tonic-gate break; 2019*0Sstevel@tonic-gate case DL_PHYS_ADDR_REQ: 2020*0Sstevel@tonic-gate message_done(tll); 2021*0Sstevel@tonic-gate break; 2022*0Sstevel@tonic-gate case DL_INFO_REQ: 2023*0Sstevel@tonic-gate case DL_ATTACH_REQ: 2024*0Sstevel@tonic-gate case DL_BIND_REQ: 2025*0Sstevel@tonic-gate message_done(tll); 2026*0Sstevel@tonic-gate tll->tll_error = err; 2027*0Sstevel@tonic-gate DBGPLUMB((CE_CONT, "bind error %d\n", err)); 2028*0Sstevel@tonic-gate break; 2029*0Sstevel@tonic-gate } 2030*0Sstevel@tonic-gate break; 2031*0Sstevel@tonic-gate 2032*0Sstevel@tonic-gate case DL_INFO_ACK: 2033*0Sstevel@tonic-gate message_done(tll); 2034*0Sstevel@tonic-gate break; 2035*0Sstevel@tonic-gate 2036*0Sstevel@tonic-gate case DL_BIND_ACK: 2037*0Sstevel@tonic-gate message_done(tll); 2038*0Sstevel@tonic-gate DBGPLUMB((CE_CONT, "bind ack\n")); 2039*0Sstevel@tonic-gate break; 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate case DL_PHYS_ADDR_ACK: 2042*0Sstevel@tonic-gate break; 2043*0Sstevel@tonic-gate 2044*0Sstevel@tonic-gate case DL_OK_ACK: 2045*0Sstevel@tonic-gate switch (dlp->ok_ack.dl_correct_primitive) { 2046*0Sstevel@tonic-gate case DL_UNBIND_REQ: 2047*0Sstevel@tonic-gate message_done(tll); 2048*0Sstevel@tonic-gate break; 2049*0Sstevel@tonic-gate case DL_DETACH_REQ: 2050*0Sstevel@tonic-gate DBGPLUMB((CE_CONT, "detach ack; shutdown done\n")); 2051*0Sstevel@tonic-gate tll->tll_flags |= TLLF_SHUTDOWN_DONE; 2052*0Sstevel@tonic-gate break; 2053*0Sstevel@tonic-gate case DL_ATTACH_REQ: 2054*0Sstevel@tonic-gate message_done(tll); 2055*0Sstevel@tonic-gate DBGPLUMB((CE_CONT, "attach ack\n")); 2056*0Sstevel@tonic-gate break; 2057*0Sstevel@tonic-gate } 2058*0Sstevel@tonic-gate break; 2059*0Sstevel@tonic-gate } 2060*0Sstevel@tonic-gate freemsg(mp); 2061*0Sstevel@tonic-gate } 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate /* Search structure used with PPPoE only; see tclvm_pppoe_search(). */ 2064*0Sstevel@tonic-gate struct poedat { 2065*0Sstevel@tonic-gate uint_t sessid; 2066*0Sstevel@tonic-gate tunll_t *tll; 2067*0Sstevel@tonic-gate void *srcaddr; 2068*0Sstevel@tonic-gate int isdata; 2069*0Sstevel@tonic-gate tuncl_t *tcl; 2070*0Sstevel@tonic-gate }; 2071*0Sstevel@tonic-gate 2072*0Sstevel@tonic-gate /* 2073*0Sstevel@tonic-gate * This function is called by vmem_walk from within sppptun_recv. It 2074*0Sstevel@tonic-gate * iterates over a span of allocated minor node numbers to search for 2075*0Sstevel@tonic-gate * the appropriate lower stream, session ID, and peer MAC address. 2076*0Sstevel@tonic-gate * 2077*0Sstevel@tonic-gate * (This is necessary due to a design flaw in the PPPoE protocol 2078*0Sstevel@tonic-gate * itself. The protocol assigns session IDs from the server side 2079*0Sstevel@tonic-gate * only. Both server and client use the same number. Thus, if there 2080*0Sstevel@tonic-gate * are multiple clients on a single host, there can be session ID 2081*0Sstevel@tonic-gate * conflicts between servers and there's no way to detangle them 2082*0Sstevel@tonic-gate * except by looking at the remote MAC address.) 2083*0Sstevel@tonic-gate * 2084*0Sstevel@tonic-gate * (This could have been handled by linking together sessions that 2085*0Sstevel@tonic-gate * differ only in the remote MAC address. This isn't done because it 2086*0Sstevel@tonic-gate * would involve extra per-session storage and it's very unlikely that 2087*0Sstevel@tonic-gate * PPPoE would be used this way.) 2088*0Sstevel@tonic-gate */ 2089*0Sstevel@tonic-gate static void 2090*0Sstevel@tonic-gate tclvm_pppoe_search(void *arg, void *firstv, size_t numv) 2091*0Sstevel@tonic-gate { 2092*0Sstevel@tonic-gate struct poedat *poedat = (struct poedat *)arg; 2093*0Sstevel@tonic-gate int minorn = (int)(uintptr_t)firstv; 2094*0Sstevel@tonic-gate int minormax = minorn + numv; 2095*0Sstevel@tonic-gate tuncl_t *tcl; 2096*0Sstevel@tonic-gate 2097*0Sstevel@tonic-gate if (poedat->tcl != NULL) 2098*0Sstevel@tonic-gate return; 2099*0Sstevel@tonic-gate while (minorn < minormax) { 2100*0Sstevel@tonic-gate tcl = tcl_slots[minorn - 1]; 2101*0Sstevel@tonic-gate ASSERT(tcl != NULL); 2102*0Sstevel@tonic-gate if (tcl->tcl_rsessid == poedat->sessid && 2103*0Sstevel@tonic-gate ((!poedat->isdata && tcl->tcl_ctrl_tll == poedat->tll) || 2104*0Sstevel@tonic-gate (poedat->isdata && 2105*0Sstevel@tonic-gate tcl->tcl_data_tll == poedat->tll)) && 2106*0Sstevel@tonic-gate bcmp(tcl->tcl_address.pta_pppoe.ptma_mac, 2107*0Sstevel@tonic-gate poedat->srcaddr, 2108*0Sstevel@tonic-gate sizeof (tcl->tcl_address.pta_pppoe.ptma_mac)) == 0) { 2109*0Sstevel@tonic-gate poedat->tcl = tcl; 2110*0Sstevel@tonic-gate break; 2111*0Sstevel@tonic-gate } 2112*0Sstevel@tonic-gate minorn++; 2113*0Sstevel@tonic-gate } 2114*0Sstevel@tonic-gate } 2115*0Sstevel@tonic-gate 2116*0Sstevel@tonic-gate /* 2117*0Sstevel@tonic-gate * sppptun_recv() 2118*0Sstevel@tonic-gate * 2119*0Sstevel@tonic-gate * MT-Perimeters: 2120*0Sstevel@tonic-gate * shared inner, shared outer. 2121*0Sstevel@tonic-gate * 2122*0Sstevel@tonic-gate * Description: 2123*0Sstevel@tonic-gate * Receive function called by sppptun_urput, which is called when 2124*0Sstevel@tonic-gate * the lower read-side put or service procedure sends a message 2125*0Sstevel@tonic-gate * upstream to the a device user (PPP). It attempts to find an 2126*0Sstevel@tonic-gate * appropriate queue on the module above us (depending on what the 2127*0Sstevel@tonic-gate * associated upper stream for the protocol would be), and if not 2128*0Sstevel@tonic-gate * possible, it will find an upper control stream for the protocol. 2129*0Sstevel@tonic-gate * Returns a pointer to the upper queue_t, or NULL if the message 2130*0Sstevel@tonic-gate * has been discarded. 2131*0Sstevel@tonic-gate * 2132*0Sstevel@tonic-gate * About demultiplexing: 2133*0Sstevel@tonic-gate * 2134*0Sstevel@tonic-gate * All four protocols (L2F, PPTP, L2TP, and PPPoE) support a 2135*0Sstevel@tonic-gate * locally assigned ID for demultiplexing incoming traffic. For 2136*0Sstevel@tonic-gate * L2F, this is called the Client ID, for PPTP the Call ID, for 2137*0Sstevel@tonic-gate * L2TP the Session ID, and for PPPoE the SESSION_ID. This is a 2138*0Sstevel@tonic-gate * 16 bit number for all four protocols, and is used to directly 2139*0Sstevel@tonic-gate * index into a list of upper streams. With the upper stream in 2140*0Sstevel@tonic-gate * hand, we verify that this is the right stream and deliver the 2141*0Sstevel@tonic-gate * data. 2142*0Sstevel@tonic-gate * 2143*0Sstevel@tonic-gate * L2TP has a Tunnel ID, which represents a bundle of PPP 2144*0Sstevel@tonic-gate * sessions between the peers. Because we always assign unique 2145*0Sstevel@tonic-gate * session ID numbers, we merely check that the given ID matches 2146*0Sstevel@tonic-gate * the assigned ID for the upper stream. 2147*0Sstevel@tonic-gate * 2148*0Sstevel@tonic-gate * L2F has a Multiplex ID, which is unique per connection. It 2149*0Sstevel@tonic-gate * does not have L2TP's concept of multiple-connections-within- 2150*0Sstevel@tonic-gate * a-tunnel. The same checking is done. 2151*0Sstevel@tonic-gate * 2152*0Sstevel@tonic-gate * PPPoE is a horribly broken protocol. Only one ID is assigned 2153*0Sstevel@tonic-gate * per connection. The client must somehow demultiplex based on 2154*0Sstevel@tonic-gate * an ID number assigned by the server. It's not necessarily 2155*0Sstevel@tonic-gate * unique. The search is done based on {ID,peerEthernet} (using 2156*0Sstevel@tonic-gate * tcl_rsessid) for all packet types except PADI and PADS. 2157*0Sstevel@tonic-gate * 2158*0Sstevel@tonic-gate * Neither PPPoE nor PPTP supports additional ID numbers. 2159*0Sstevel@tonic-gate * 2160*0Sstevel@tonic-gate * Both L2F and L2TP come in over UDP. They are distinguished by 2161*0Sstevel@tonic-gate * looking at the GRE version field -- 001 for L2F and 010 for 2162*0Sstevel@tonic-gate * L2TP. 2163*0Sstevel@tonic-gate */ 2164*0Sstevel@tonic-gate static queue_t * 2165*0Sstevel@tonic-gate sppptun_recv(queue_t *q, mblk_t **mpp, void *destaddr, void *srcaddr) 2166*0Sstevel@tonic-gate { 2167*0Sstevel@tonic-gate mblk_t *mp; 2168*0Sstevel@tonic-gate tunll_t *tll; 2169*0Sstevel@tonic-gate tuncl_t *tcl; 2170*0Sstevel@tonic-gate int sessid; 2171*0Sstevel@tonic-gate int remlen; 2172*0Sstevel@tonic-gate int msglen; 2173*0Sstevel@tonic-gate int isdata; 2174*0Sstevel@tonic-gate int i; 2175*0Sstevel@tonic-gate ushort_t *usp; 2176*0Sstevel@tonic-gate uchar_t *ucp; 2177*0Sstevel@tonic-gate poep_t *poep; 2178*0Sstevel@tonic-gate mblk_t *mnew; 2179*0Sstevel@tonic-gate ppptun_atype *pap; 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate _NOTE(ARGUNUSED(destaddr)) 2182*0Sstevel@tonic-gate ASSERT(mpp != NULL); 2183*0Sstevel@tonic-gate mp = *mpp; 2184*0Sstevel@tonic-gate ASSERT(q != NULL); 2185*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 2186*0Sstevel@tonic-gate ASSERT(mp != NULL); 2187*0Sstevel@tonic-gate 2188*0Sstevel@tonic-gate tll = (tunll_t *)q->q_ptr; 2189*0Sstevel@tonic-gate ASSERT(!(tll->tll_flags & TLLF_NOTLOWER)); 2190*0Sstevel@tonic-gate 2191*0Sstevel@tonic-gate /* 2192*0Sstevel@tonic-gate * First, extract a session ID number. All protocols have 2193*0Sstevel@tonic-gate * this. 2194*0Sstevel@tonic-gate */ 2195*0Sstevel@tonic-gate usp = (ushort_t *)mp->b_rptr; 2196*0Sstevel@tonic-gate ucp = (uchar_t *)mp->b_rptr; 2197*0Sstevel@tonic-gate tcl = NULL; 2198*0Sstevel@tonic-gate switch (tll->tll_style) { 2199*0Sstevel@tonic-gate case PTS_PPPOE: 2200*0Sstevel@tonic-gate poep = (poep_t *)usp; 2201*0Sstevel@tonic-gate if (poep->poep_version_type != POE_VERSION) 2202*0Sstevel@tonic-gate break; 2203*0Sstevel@tonic-gate isdata = (poep->poep_code == POECODE_DATA); 2204*0Sstevel@tonic-gate sessid = ntohs(poep->poep_session_id); 2205*0Sstevel@tonic-gate remlen = sizeof (*poep); 2206*0Sstevel@tonic-gate msglen = ntohs(poep->poep_length); 2207*0Sstevel@tonic-gate i = poep->poep_code; 2208*0Sstevel@tonic-gate if (i == POECODE_PADI || i == POECODE_PADR) { 2209*0Sstevel@tonic-gate /* These go to the server daemon only. */ 2210*0Sstevel@tonic-gate tcl = tll->tll_defcl; 2211*0Sstevel@tonic-gate } else if (i == POECODE_PADO || i == POECODE_PADS) { 2212*0Sstevel@tonic-gate /* 2213*0Sstevel@tonic-gate * These go to a client only, and are demuxed 2214*0Sstevel@tonic-gate * by the Host-Uniq field (into which we stuff 2215*0Sstevel@tonic-gate * our local ID number when generating 2216*0Sstevel@tonic-gate * PADI/PADR). 2217*0Sstevel@tonic-gate */ 2218*0Sstevel@tonic-gate ucp += sizeof (*poep); 2219*0Sstevel@tonic-gate i = msglen; 2220*0Sstevel@tonic-gate while (i > POET_HDRLEN) { 2221*0Sstevel@tonic-gate if (POET_GET_TYPE(ucp) == POETT_END) { 2222*0Sstevel@tonic-gate i = 0; 2223*0Sstevel@tonic-gate break; 2224*0Sstevel@tonic-gate } 2225*0Sstevel@tonic-gate if (POET_GET_TYPE(ucp) == POETT_UNIQ && 2226*0Sstevel@tonic-gate POET_GET_LENG(ucp) >= sizeof (uint32_t)) 2227*0Sstevel@tonic-gate break; 2228*0Sstevel@tonic-gate i -= POET_GET_LENG(ucp) + POET_HDRLEN; 2229*0Sstevel@tonic-gate ucp = POET_NEXT(ucp); 2230*0Sstevel@tonic-gate } 2231*0Sstevel@tonic-gate if (i >= POET_HDRLEN + 4) 2232*0Sstevel@tonic-gate sessid = GETLONG(ucp + POET_HDRLEN); 2233*0Sstevel@tonic-gate tcl = tcl_by_minor((minor_t)sessid); 2234*0Sstevel@tonic-gate } else { 2235*0Sstevel@tonic-gate /* 2236*0Sstevel@tonic-gate * Try minor number as session ID first, since 2237*0Sstevel@tonic-gate * it's used that way on server side. It's 2238*0Sstevel@tonic-gate * not used that way on the client, though, so 2239*0Sstevel@tonic-gate * this might not work. If this isn't the 2240*0Sstevel@tonic-gate * right one, then try the tll cache. If 2241*0Sstevel@tonic-gate * neither is right, then search all open 2242*0Sstevel@tonic-gate * clients. Did I mention that the PPPoE 2243*0Sstevel@tonic-gate * protocol is badly designed? 2244*0Sstevel@tonic-gate */ 2245*0Sstevel@tonic-gate tcl = tcl_by_minor((minor_t)sessid); 2246*0Sstevel@tonic-gate if (tcl == NULL || 2247*0Sstevel@tonic-gate (!isdata && tcl->tcl_ctrl_tll != tll) || 2248*0Sstevel@tonic-gate (isdata && tcl->tcl_data_tll != tll) || 2249*0Sstevel@tonic-gate sessid != tcl->tcl_rsessid || 2250*0Sstevel@tonic-gate bcmp(srcaddr, tcl->tcl_address.pta_pppoe.ptma_mac, 2251*0Sstevel@tonic-gate sizeof (tcl->tcl_address.pta_pppoe.ptma_mac)) != 0) 2252*0Sstevel@tonic-gate tcl = tll->tll_lastcl; 2253*0Sstevel@tonic-gate if (tcl == NULL || 2254*0Sstevel@tonic-gate (!isdata && tcl->tcl_ctrl_tll != tll) || 2255*0Sstevel@tonic-gate (isdata && tcl->tcl_data_tll != tll) || 2256*0Sstevel@tonic-gate sessid != tcl->tcl_rsessid || 2257*0Sstevel@tonic-gate bcmp(srcaddr, tcl->tcl_address.pta_pppoe.ptma_mac, 2258*0Sstevel@tonic-gate sizeof (tcl->tcl_address.pta_pppoe.ptma_mac)) != 0) 2259*0Sstevel@tonic-gate tcl = NULL; 2260*0Sstevel@tonic-gate if (tcl == NULL && sessid != 0) { 2261*0Sstevel@tonic-gate struct poedat poedat; 2262*0Sstevel@tonic-gate 2263*0Sstevel@tonic-gate /* 2264*0Sstevel@tonic-gate * Slow mode. Too bad. If you don't like it, 2265*0Sstevel@tonic-gate * you can always choose a better protocol. 2266*0Sstevel@tonic-gate */ 2267*0Sstevel@tonic-gate poedat.sessid = sessid; 2268*0Sstevel@tonic-gate poedat.tll = tll; 2269*0Sstevel@tonic-gate poedat.srcaddr = srcaddr; 2270*0Sstevel@tonic-gate poedat.tcl = NULL; 2271*0Sstevel@tonic-gate poedat.isdata = isdata; 2272*0Sstevel@tonic-gate vmem_walk(tcl_minor_arena, VMEM_ALLOC, 2273*0Sstevel@tonic-gate tclvm_pppoe_search, &poedat); 2274*0Sstevel@tonic-gate KLINCR(lks_walks); 2275*0Sstevel@tonic-gate if ((tcl = poedat.tcl) != NULL) { 2276*0Sstevel@tonic-gate tll->tll_lastcl = tcl; 2277*0Sstevel@tonic-gate KCINCR(cks_walks); 2278*0Sstevel@tonic-gate } 2279*0Sstevel@tonic-gate } 2280*0Sstevel@tonic-gate } 2281*0Sstevel@tonic-gate break; 2282*0Sstevel@tonic-gate } 2283*0Sstevel@tonic-gate 2284*0Sstevel@tonic-gate if (tcl == NULL || tcl->tcl_rq == NULL) { 2285*0Sstevel@tonic-gate DBGERROR((CE_CONT, "discard; session %d %s", sessid, 2286*0Sstevel@tonic-gate tcl == NULL ? "not found" : "terminated")); 2287*0Sstevel@tonic-gate if (tcl == NULL) { 2288*0Sstevel@tonic-gate KLINCR(lks_in_nomatch); 2289*0Sstevel@tonic-gate } 2290*0Sstevel@tonic-gate if (isdata) { 2291*0Sstevel@tonic-gate KLINCR(lks_indata_drops); 2292*0Sstevel@tonic-gate if (tcl != NULL) 2293*0Sstevel@tonic-gate tcl->tcl_stats.ppp_ierrors++; 2294*0Sstevel@tonic-gate } else { 2295*0Sstevel@tonic-gate KLINCR(lks_inctrl_drops); 2296*0Sstevel@tonic-gate if (tcl != NULL) { 2297*0Sstevel@tonic-gate KCINCR(cks_inctrl_drops); 2298*0Sstevel@tonic-gate } 2299*0Sstevel@tonic-gate } 2300*0Sstevel@tonic-gate freemsg(mp); 2301*0Sstevel@tonic-gate return (NULL); 2302*0Sstevel@tonic-gate } 2303*0Sstevel@tonic-gate 2304*0Sstevel@tonic-gate if (tcl->tcl_data_tll == tll && isdata) { 2305*0Sstevel@tonic-gate if (!adjmsg(mp, remlen) || 2306*0Sstevel@tonic-gate (i = msgsize(mp)) < msglen || 2307*0Sstevel@tonic-gate (i > msglen && !adjmsg(mp, msglen - i))) { 2308*0Sstevel@tonic-gate KLINCR(lks_indata_drops); 2309*0Sstevel@tonic-gate tcl->tcl_stats.ppp_ierrors++; 2310*0Sstevel@tonic-gate freemsg(mp); 2311*0Sstevel@tonic-gate return (NULL); 2312*0Sstevel@tonic-gate } 2313*0Sstevel@tonic-gate /* XXX -- address/control handling in pppd needs help. */ 2314*0Sstevel@tonic-gate if (*mp->b_rptr != 0xFF) { 2315*0Sstevel@tonic-gate if ((mp = prependb(mp, 2, 1)) == NULL) { 2316*0Sstevel@tonic-gate KLINCR(lks_indata_drops); 2317*0Sstevel@tonic-gate tcl->tcl_stats.ppp_ierrors++; 2318*0Sstevel@tonic-gate return (NULL); 2319*0Sstevel@tonic-gate } 2320*0Sstevel@tonic-gate mp->b_rptr[0] = 0xFF; 2321*0Sstevel@tonic-gate mp->b_rptr[1] = 0x03; 2322*0Sstevel@tonic-gate } 2323*0Sstevel@tonic-gate MTYPE(mp) = M_DATA; 2324*0Sstevel@tonic-gate if (tcl->tcl_flags & TCLF_DEBUG) 2325*0Sstevel@tonic-gate sppp_dump_frame(tcl->tcl_unit, mp, "rcvd"); 2326*0Sstevel@tonic-gate tcl->tcl_stats.ppp_ibytes += msgsize(mp); 2327*0Sstevel@tonic-gate tcl->tcl_stats.ppp_ipackets++; 2328*0Sstevel@tonic-gate KLINCR(lks_indata); 2329*0Sstevel@tonic-gate } else { 2330*0Sstevel@tonic-gate if (isdata || tcl->tcl_ctrl_tll != tll || 2331*0Sstevel@tonic-gate (mnew = make_control(tcl, tll, PTCA_CONTROL, tcl)) == 2332*0Sstevel@tonic-gate NULL) { 2333*0Sstevel@tonic-gate KLINCR(lks_inctrl_drops); 2334*0Sstevel@tonic-gate KCINCR(cks_inctrl_drops); 2335*0Sstevel@tonic-gate freemsg(mp); 2336*0Sstevel@tonic-gate return (NULL); 2337*0Sstevel@tonic-gate } 2338*0Sstevel@tonic-gate if (tcl->tcl_flags & TCLF_DEBUG) 2339*0Sstevel@tonic-gate sppp_dump_frame(tcl->tcl_unit, mp, "rctl"); 2340*0Sstevel@tonic-gate /* Fix up source address; peer might not be set yet. */ 2341*0Sstevel@tonic-gate pap = &((struct ppptun_control *)mnew->b_rptr)->ptc_address; 2342*0Sstevel@tonic-gate bcopy(srcaddr, pap->pta_pppoe.ptma_mac, 2343*0Sstevel@tonic-gate sizeof (pap->pta_pppoe.ptma_mac)); 2344*0Sstevel@tonic-gate mnew->b_cont = mp; 2345*0Sstevel@tonic-gate mp = mnew; 2346*0Sstevel@tonic-gate KLINCR(lks_inctrls); 2347*0Sstevel@tonic-gate KCINCR(cks_inctrls); 2348*0Sstevel@tonic-gate } 2349*0Sstevel@tonic-gate *mpp = mp; 2350*0Sstevel@tonic-gate return (tcl->tcl_rq); 2351*0Sstevel@tonic-gate } 2352*0Sstevel@tonic-gate 2353*0Sstevel@tonic-gate /* 2354*0Sstevel@tonic-gate * sppptun_urput() 2355*0Sstevel@tonic-gate * 2356*0Sstevel@tonic-gate * MT-Perimeters: 2357*0Sstevel@tonic-gate * shared inner, shared outer. 2358*0Sstevel@tonic-gate * 2359*0Sstevel@tonic-gate * Description: 2360*0Sstevel@tonic-gate * Upper read-side put procedure. Messages from the underlying 2361*0Sstevel@tonic-gate * lower stream driver arrive here. See sppptun_recv for the 2362*0Sstevel@tonic-gate * demultiplexing logic. 2363*0Sstevel@tonic-gate */ 2364*0Sstevel@tonic-gate static void 2365*0Sstevel@tonic-gate sppptun_urput(queue_t *q, mblk_t *mp) 2366*0Sstevel@tonic-gate { 2367*0Sstevel@tonic-gate union DL_primitives *dlprim; 2368*0Sstevel@tonic-gate mblk_t *mpnext; 2369*0Sstevel@tonic-gate tunll_t *tll; 2370*0Sstevel@tonic-gate queue_t *nextq; 2371*0Sstevel@tonic-gate 2372*0Sstevel@tonic-gate DBGENTRY((CE_CONT, "sppptun_urput as %s", DBGQSIDE(q))); 2373*0Sstevel@tonic-gate 2374*0Sstevel@tonic-gate ASSERT(q != NULL); 2375*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 2376*0Sstevel@tonic-gate ASSERT(mp != NULL); 2377*0Sstevel@tonic-gate tll = (tunll_t *)q->q_ptr; 2378*0Sstevel@tonic-gate ASSERT(!(tll->tll_flags & TLLF_NOTLOWER)); 2379*0Sstevel@tonic-gate 2380*0Sstevel@tonic-gate switch (MTYPE(mp)) { 2381*0Sstevel@tonic-gate case M_DATA: 2382*0Sstevel@tonic-gate /* 2383*0Sstevel@tonic-gate * When we're bound over IP, data arrives here. The 2384*0Sstevel@tonic-gate * packet starts with the IP header itself. 2385*0Sstevel@tonic-gate */ 2386*0Sstevel@tonic-gate if ((nextq = sppptun_recv(q, &mp, NULL, NULL)) != NULL) 2387*0Sstevel@tonic-gate putnext(nextq, mp); 2388*0Sstevel@tonic-gate break; 2389*0Sstevel@tonic-gate 2390*0Sstevel@tonic-gate case M_PROTO: 2391*0Sstevel@tonic-gate case M_PCPROTO: 2392*0Sstevel@tonic-gate /* Data arrives here for UDP or raw Ethernet, not IP. */ 2393*0Sstevel@tonic-gate switch (tll->tll_style) { 2394*0Sstevel@tonic-gate /* PPTP control messages are over TCP only. */ 2395*0Sstevel@tonic-gate case PTS_PPTP: 2396*0Sstevel@tonic-gate default: 2397*0Sstevel@tonic-gate ASSERT(0); /* how'd that happen? */ 2398*0Sstevel@tonic-gate break; 2399*0Sstevel@tonic-gate 2400*0Sstevel@tonic-gate case PTS_PPPOE: /* DLPI message */ 2401*0Sstevel@tonic-gate dlprim = (union DL_primitives *)mp->b_rptr; 2402*0Sstevel@tonic-gate switch (dlprim->dl_primitive) { 2403*0Sstevel@tonic-gate case DL_UNITDATA_IND: 2404*0Sstevel@tonic-gate mpnext = mp->b_cont; 2405*0Sstevel@tonic-gate MTYPE(mpnext) = M_DATA; 2406*0Sstevel@tonic-gate nextq = sppptun_recv(q, &mpnext, 2407*0Sstevel@tonic-gate mp->b_rptr + 2408*0Sstevel@tonic-gate dlprim->unitdata_ind.dl_dest_addr_offset, 2409*0Sstevel@tonic-gate mp->b_rptr + 2410*0Sstevel@tonic-gate dlprim->unitdata_ind.dl_src_addr_offset); 2411*0Sstevel@tonic-gate if (nextq != NULL) 2412*0Sstevel@tonic-gate putnext(nextq, mpnext); 2413*0Sstevel@tonic-gate freeb(mp); 2414*0Sstevel@tonic-gate break; 2415*0Sstevel@tonic-gate 2416*0Sstevel@tonic-gate /* For loopback support. */ 2417*0Sstevel@tonic-gate case DL_UNITDATA_REQ: 2418*0Sstevel@tonic-gate mpnext = mp->b_cont; 2419*0Sstevel@tonic-gate MTYPE(mpnext) = M_DATA; 2420*0Sstevel@tonic-gate nextq = sppptun_recv(q, &mpnext, 2421*0Sstevel@tonic-gate mp->b_rptr + 2422*0Sstevel@tonic-gate dlprim->unitdata_req.dl_dest_addr_offset, 2423*0Sstevel@tonic-gate tll->tll_lcladdr.pta_pppoe.ptma_mac); 2424*0Sstevel@tonic-gate if (nextq != NULL) 2425*0Sstevel@tonic-gate putnext(nextq, mpnext); 2426*0Sstevel@tonic-gate freeb(mp); 2427*0Sstevel@tonic-gate break; 2428*0Sstevel@tonic-gate 2429*0Sstevel@tonic-gate default: 2430*0Sstevel@tonic-gate urput_dlpi(q, mp); 2431*0Sstevel@tonic-gate break; 2432*0Sstevel@tonic-gate } 2433*0Sstevel@tonic-gate break; 2434*0Sstevel@tonic-gate } 2435*0Sstevel@tonic-gate break; 2436*0Sstevel@tonic-gate 2437*0Sstevel@tonic-gate default: 2438*0Sstevel@tonic-gate freemsg(mp); 2439*0Sstevel@tonic-gate break; 2440*0Sstevel@tonic-gate } 2441*0Sstevel@tonic-gate } 2442*0Sstevel@tonic-gate 2443*0Sstevel@tonic-gate /* 2444*0Sstevel@tonic-gate * sppptun_ursrv() 2445*0Sstevel@tonic-gate * 2446*0Sstevel@tonic-gate * MT-Perimeters: 2447*0Sstevel@tonic-gate * exclusive inner, shared outer. 2448*0Sstevel@tonic-gate * 2449*0Sstevel@tonic-gate * Description: 2450*0Sstevel@tonic-gate * Upper read-side service procedure. This procedure services the 2451*0Sstevel@tonic-gate * client streams. We get here because the client (PPP) asserts 2452*0Sstevel@tonic-gate * flow control down to us. 2453*0Sstevel@tonic-gate */ 2454*0Sstevel@tonic-gate static int 2455*0Sstevel@tonic-gate sppptun_ursrv(queue_t *q) 2456*0Sstevel@tonic-gate { 2457*0Sstevel@tonic-gate mblk_t *mp; 2458*0Sstevel@tonic-gate 2459*0Sstevel@tonic-gate ASSERT(q != NULL); 2460*0Sstevel@tonic-gate ASSERT(q->q_ptr != NULL); 2461*0Sstevel@tonic-gate 2462*0Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 2463*0Sstevel@tonic-gate if (canputnext(q)) { 2464*0Sstevel@tonic-gate putnext(q, mp); 2465*0Sstevel@tonic-gate } else { 2466*0Sstevel@tonic-gate (void) putbq(q, mp); 2467*0Sstevel@tonic-gate break; 2468*0Sstevel@tonic-gate } 2469*0Sstevel@tonic-gate } 2470*0Sstevel@tonic-gate return (0); 2471*0Sstevel@tonic-gate } 2472*0Sstevel@tonic-gate 2473*0Sstevel@tonic-gate /* 2474*0Sstevel@tonic-gate * Dummy constructor/destructor functions for kmem_cache_create. 2475*0Sstevel@tonic-gate * We're just using kmem as an allocator of integers, not real 2476*0Sstevel@tonic-gate * storage. 2477*0Sstevel@tonic-gate */ 2478*0Sstevel@tonic-gate 2479*0Sstevel@tonic-gate /*ARGSUSED*/ 2480*0Sstevel@tonic-gate static int 2481*0Sstevel@tonic-gate tcl_constructor(void *maddr, void *arg, int kmflags) 2482*0Sstevel@tonic-gate { 2483*0Sstevel@tonic-gate return (0); 2484*0Sstevel@tonic-gate } 2485*0Sstevel@tonic-gate 2486*0Sstevel@tonic-gate /*ARGSUSED*/ 2487*0Sstevel@tonic-gate static void 2488*0Sstevel@tonic-gate tcl_destructor(void *maddr, void *arg) 2489*0Sstevel@tonic-gate { 2490*0Sstevel@tonic-gate } 2491*0Sstevel@tonic-gate 2492*0Sstevel@tonic-gate /* 2493*0Sstevel@tonic-gate * Total size occupied by one tunnel client. Each tunnel client 2494*0Sstevel@tonic-gate * consumes one pointer for tcl_slots array, one tuncl_t structure and 2495*0Sstevel@tonic-gate * two messages preallocated for close. 2496*0Sstevel@tonic-gate */ 2497*0Sstevel@tonic-gate #define TUNCL_SIZE (sizeof (tuncl_t) + sizeof (tuncl_t *) + \ 2498*0Sstevel@tonic-gate 2 * sizeof (dblk_t)) 2499*0Sstevel@tonic-gate 2500*0Sstevel@tonic-gate /* 2501*0Sstevel@tonic-gate * Clear all bits of x except the highest bit 2502*0Sstevel@tonic-gate */ 2503*0Sstevel@tonic-gate #define truncate(x) ((x) <= 2 ? (x) : (1 << (highbit(x) - 1))) 2504*0Sstevel@tonic-gate 2505*0Sstevel@tonic-gate /* 2506*0Sstevel@tonic-gate * This function initializes some well-known global variables inside 2507*0Sstevel@tonic-gate * the module. 2508*0Sstevel@tonic-gate * 2509*0Sstevel@tonic-gate * Called by sppptun_mod.c:_init() before installing the module. 2510*0Sstevel@tonic-gate */ 2511*0Sstevel@tonic-gate void 2512*0Sstevel@tonic-gate sppptun_init(void) 2513*0Sstevel@tonic-gate { 2514*0Sstevel@tonic-gate tunll_list.q_forw = tunll_list.q_back = &tunll_list; 2515*0Sstevel@tonic-gate } 2516*0Sstevel@tonic-gate 2517*0Sstevel@tonic-gate /* 2518*0Sstevel@tonic-gate * This function allocates the initial internal storage for the 2519*0Sstevel@tonic-gate * sppptun driver. 2520*0Sstevel@tonic-gate * 2521*0Sstevel@tonic-gate * Called by sppptun_mod.c:_init() after installing module. 2522*0Sstevel@tonic-gate */ 2523*0Sstevel@tonic-gate void 2524*0Sstevel@tonic-gate sppptun_tcl_init(void) 2525*0Sstevel@tonic-gate { 2526*0Sstevel@tonic-gate uint_t i, j; 2527*0Sstevel@tonic-gate 2528*0Sstevel@tonic-gate rw_init(&tcl_rwlock, NULL, RW_DRIVER, NULL); 2529*0Sstevel@tonic-gate rw_enter(&tcl_rwlock, RW_WRITER); 2530*0Sstevel@tonic-gate tcl_nslots = sppptun_init_cnt; 2531*0Sstevel@tonic-gate tcl_slots = kmem_zalloc(tcl_nslots * sizeof (tuncl_t *), KM_SLEEP); 2532*0Sstevel@tonic-gate 2533*0Sstevel@tonic-gate tcl_cache = kmem_cache_create("sppptun_map", sizeof (tuncl_t), 0, 2534*0Sstevel@tonic-gate tcl_constructor, tcl_destructor, NULL, NULL, NULL, 0); 2535*0Sstevel@tonic-gate 2536*0Sstevel@tonic-gate /* Allocate integer space for minor numbers */ 2537*0Sstevel@tonic-gate tcl_minor_arena = vmem_create("sppptun_minor", (void *)1, tcl_nslots, 2538*0Sstevel@tonic-gate 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER); 2539*0Sstevel@tonic-gate 2540*0Sstevel@tonic-gate /* 2541*0Sstevel@tonic-gate * Calculate available number of tunnels - how many tunnels 2542*0Sstevel@tonic-gate * can we allocate in sppptun_pctofmem % of available 2543*0Sstevel@tonic-gate * memory. The value is rounded up to the nearest power of 2. 2544*0Sstevel@tonic-gate */ 2545*0Sstevel@tonic-gate i = (sppptun_pctofmem * kmem_maxavail()) / (100 * TUNCL_SIZE); 2546*0Sstevel@tonic-gate j = truncate(i); /* i with non-high bits stripped */ 2547*0Sstevel@tonic-gate if (i != j) 2548*0Sstevel@tonic-gate j *= 2; 2549*0Sstevel@tonic-gate tcl_minormax = j; 2550*0Sstevel@tonic-gate rw_exit(&tcl_rwlock); 2551*0Sstevel@tonic-gate } 2552*0Sstevel@tonic-gate 2553*0Sstevel@tonic-gate /* 2554*0Sstevel@tonic-gate * This function checks that there are no plumbed streams or other users. 2555*0Sstevel@tonic-gate * 2556*0Sstevel@tonic-gate * Called by sppptun_mod.c:_fini(). Assumes that we're exclusive on 2557*0Sstevel@tonic-gate * both perimeters. 2558*0Sstevel@tonic-gate */ 2559*0Sstevel@tonic-gate int 2560*0Sstevel@tonic-gate sppptun_tcl_fintest(void) 2561*0Sstevel@tonic-gate { 2562*0Sstevel@tonic-gate if (tunll_list.q_forw != &tunll_list || tcl_inuse > 0) { 2563*0Sstevel@tonic-gate DBGERROR((CE_CONT, 2564*0Sstevel@tonic-gate "_fini: return busy; plumbed and %d in use\n", 2565*0Sstevel@tonic-gate tcl_inuse)); 2566*0Sstevel@tonic-gate return (EBUSY); 2567*0Sstevel@tonic-gate } 2568*0Sstevel@tonic-gate return (0); 2569*0Sstevel@tonic-gate } 2570*0Sstevel@tonic-gate 2571*0Sstevel@tonic-gate /* 2572*0Sstevel@tonic-gate * If no lower streams are plumbed, then this function deallocates all 2573*0Sstevel@tonic-gate * internal storage in preparation for unload. 2574*0Sstevel@tonic-gate * 2575*0Sstevel@tonic-gate * Called by sppptun_mod.c:_fini(). Assumes that we're exclusive on 2576*0Sstevel@tonic-gate * both perimeters. 2577*0Sstevel@tonic-gate */ 2578*0Sstevel@tonic-gate void 2579*0Sstevel@tonic-gate sppptun_tcl_fini(void) 2580*0Sstevel@tonic-gate { 2581*0Sstevel@tonic-gate if (tcl_minor_arena != NULL) { 2582*0Sstevel@tonic-gate vmem_destroy(tcl_minor_arena); 2583*0Sstevel@tonic-gate tcl_minor_arena = NULL; 2584*0Sstevel@tonic-gate } 2585*0Sstevel@tonic-gate if (tcl_cache != NULL) { 2586*0Sstevel@tonic-gate kmem_cache_destroy(tcl_cache); 2587*0Sstevel@tonic-gate tcl_cache = NULL; 2588*0Sstevel@tonic-gate } 2589*0Sstevel@tonic-gate kmem_free(tcl_slots, tcl_nslots * sizeof (tuncl_t *)); 2590*0Sstevel@tonic-gate tcl_slots = NULL; 2591*0Sstevel@tonic-gate rw_destroy(&tcl_rwlock); 2592*0Sstevel@tonic-gate ASSERT(tcl_slots == NULL); 2593*0Sstevel@tonic-gate ASSERT(tcl_cache == NULL); 2594*0Sstevel@tonic-gate ASSERT(tcl_minor_arena == NULL); 2595*0Sstevel@tonic-gate } 2596