Home | History | Annotate | Download | only in sppp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  *  You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/stropts.h>
     28 #include <sys/stream.h>
     29 #include <sys/socket.h>
     30 #include <net/if.h>
     31 #define	SOL2
     32 #include <net/ppp_defs.h>
     33 #include <net/pppio.h>
     34 #include <net/sppptun.h>
     35 #include <netinet/in.h>
     36 #include <netinet/ip6.h>
     37 #include <inet/common.h>
     38 #include <inet/mib2.h>
     39 #include <inet/ip.h>
     40 #include <inet/ip6.h>
     41 #include <sppp/sppp.h>
     42 #include <sppptun/sppptun_impl.h>
     43 
     44 #include <mdb/mdb_modapi.h>
     45 #include <mdb/mdb_ks.h>
     46 #include <stdio.h>
     47 
     48 /* ****************** sppp ****************** */
     49 
     50 static int
     51 sppp_walk_init(mdb_walk_state_t *wsp)
     52 {
     53 	if (mdb_readvar(&wsp->walk_addr, "sps_list") == -1) {
     54 		mdb_warn("failed to read sps_list");
     55 		return (WALK_ERR);
     56 	}
     57 
     58 	return (WALK_NEXT);
     59 }
     60 
     61 static int
     62 sppp_walk_step(mdb_walk_state_t *wsp)
     63 {
     64 	spppstr_t sps;
     65 	int status;
     66 
     67 	if (wsp->walk_addr == NULL)
     68 		return (WALK_DONE);
     69 
     70 	if (mdb_vread(&sps, sizeof (sps), wsp->walk_addr) == -1) {
     71 		mdb_warn("can't read spppstr_t at %p", wsp->walk_addr);
     72 		return (WALK_ERR);
     73 	}
     74 
     75 	status = (wsp->walk_callback(wsp->walk_addr, &sps, wsp->walk_cbdata));
     76 
     77 	wsp->walk_addr = (uintptr_t)sps.sps_nextmn;
     78 	return (status);
     79 }
     80 
     81 static int
     82 sps_format(uintptr_t addr, const spppstr_t *sps, uint_t *qfmt)
     83 {
     84 	sppa_t ppa;
     85 	queue_t upq;
     86 	uintptr_t upaddr, illaddr;
     87 	ill_t ill;
     88 	ipif_t ipif;
     89 
     90 	mdb_printf("%?p ", addr);
     91 	if (*qfmt)
     92 		mdb_printf("%?p ", sps->sps_rq);
     93 	if (sps->sps_ppa == NULL) {
     94 		mdb_printf("?       unset     ");
     95 	} else if (mdb_vread(&ppa, sizeof (ppa), (uintptr_t)sps->sps_ppa) ==
     96 	    -1) {
     97 		mdb_printf("?      ?%p ", sps->sps_ppa);
     98 	} else {
     99 		mdb_printf("%-6d sppp%-5d ", ppa.ppa_zoneid, ppa.ppa_ppa_id);
    100 	}
    101 	if (IS_SPS_CONTROL(sps)) {
    102 		mdb_printf("Control\n");
    103 	} else if (IS_SPS_PIOATTACH(sps)) {
    104 		mdb_printf("Stats\n");
    105 	} else if (sps->sps_dlstate == DL_UNATTACHED) {
    106 		mdb_printf("Unknown\n");
    107 	} else if (sps->sps_dlstate != DL_IDLE) {
    108 		mdb_printf("DLPI Unbound\n");
    109 	} else {
    110 		upaddr = (uintptr_t)sps->sps_rq;
    111 		upq.q_ptr = NULL;
    112 		illaddr = 0;
    113 		while (upaddr != NULL) {
    114 			if (mdb_vread(&upq, sizeof (upq), upaddr) == -1) {
    115 				upq.q_ptr = NULL;
    116 				break;
    117 			}
    118 			if ((upaddr = (uintptr_t)upq.q_next) != 0)
    119 				illaddr = (uintptr_t)upq.q_ptr;
    120 		}
    121 		if (illaddr != 0) {
    122 			if (mdb_vread(&ill, sizeof (ill), illaddr) == -1 ||
    123 			    mdb_vread(&ipif, sizeof (ipif),
    124 			    (uintptr_t)ill.ill_ipif) == -1) {
    125 				illaddr = 0;
    126 			}
    127 		}
    128 
    129 		switch (sps->sps_req_sap) {
    130 		case ETHERTYPE_IP:
    131 			mdb_printf("DLPI IPv4 ");
    132 			if (*qfmt) {
    133 				mdb_printf("\n");
    134 			} else if (illaddr == 0) {
    135 				mdb_printf("(no addresses)\n");
    136 			} else {
    137 				/*
    138 				 * SCCS oddity here -- % <capital> %
    139 				 * suffers from keyword replacement.
    140 				 * Avoid that by using ANSI string
    141 				 * pasting.
    142 				 */
    143 				mdb_printf("%I:%I" "%s\n",
    144 				    ipif.ipif_lcl_addr, ipif.ipif_pp_dst_addr,
    145 				    (ipif.ipif_next ? " ..." : ""));
    146 			}
    147 			break;
    148 		case ETHERTYPE_IPV6:
    149 			mdb_printf("DLPI IPv6 ");
    150 			if (*qfmt) {
    151 				mdb_printf("\n");
    152 				break;
    153 			}
    154 			if (illaddr == 0) {
    155 				mdb_printf("(no addresses)\n");
    156 				break;
    157 			}
    158 			mdb_printf("%N\n%?s%21s", &ipif.ipif_v6lcl_addr,
    159 			    "", "");
    160 			mdb_printf("%N\n", &ipif.ipif_v6pp_dst_addr);
    161 			break;
    162 		case ETHERTYPE_ALLSAP:
    163 			mdb_printf("DLPI Snoop\n");
    164 			break;
    165 		default:
    166 			mdb_printf("DLPI SAP 0x%04X\n", sps->sps_req_sap);
    167 			break;
    168 		}
    169 	}
    170 
    171 	return (WALK_NEXT);
    172 }
    173 
    174 static int
    175 sppp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    176 {
    177 	uint_t qfmt = FALSE;
    178 	spppstr_t sps;
    179 
    180 	if (mdb_getopts(argc, argv, 'q', MDB_OPT_SETBITS, TRUE, &qfmt, NULL) !=
    181 	    argc)
    182 		return (DCMD_USAGE);
    183 
    184 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
    185 		if (qfmt) {
    186 			mdb_printf("%<u>%?s %?s %-6s %-9s %s%</u>\n", "Address",
    187 			    "RecvQ", "ZoneID", "Interface", "Type");
    188 		} else {
    189 			mdb_printf("%<u>%?s %-6s %-9s %s%</u>\n", "Address",
    190 			    "ZoneID", "Interface", "Type");
    191 		}
    192 	}
    193 
    194 	if (flags & DCMD_ADDRSPEC) {
    195 		(void) mdb_vread(&sps, sizeof (sps), addr);
    196 		(void) sps_format(addr, &sps, &qfmt);
    197 	} else if (mdb_walk("sppp", (mdb_walk_cb_t)sps_format, &qfmt) == -1) {
    198 		mdb_warn("failed to walk sps_list");
    199 		return (DCMD_ERR);
    200 	}
    201 
    202 	return (DCMD_OK);
    203 }
    204 
    205 static int
    206 sppa_walk_init(mdb_walk_state_t *wsp)
    207 {
    208 	if (mdb_readvar(&wsp->walk_addr, "ppa_list") == -1) {
    209 		mdb_warn("failed to read ppa_list");
    210 		return (WALK_ERR);
    211 	}
    212 
    213 	return (WALK_NEXT);
    214 }
    215 
    216 static int
    217 sppa_walk_step(mdb_walk_state_t *wsp)
    218 {
    219 	sppa_t ppa;
    220 	int status;
    221 
    222 	if (wsp->walk_addr == NULL)
    223 		return (WALK_DONE);
    224 
    225 	if (mdb_vread(&ppa, sizeof (ppa), wsp->walk_addr) == -1) {
    226 		mdb_warn("can't read spppstr_t at %p", wsp->walk_addr);
    227 		return (WALK_ERR);
    228 	}
    229 
    230 	status = (wsp->walk_callback(wsp->walk_addr, &ppa, wsp->walk_cbdata));
    231 
    232 	wsp->walk_addr = (uintptr_t)ppa.ppa_nextppa;
    233 	return (status);
    234 }
    235 
    236 /* ARGSUSED */
    237 static int
    238 ppa_format(uintptr_t addr, const sppa_t *ppa, uint_t *qfmt)
    239 {
    240 	mdb_printf("%?p %-6d sppp%-5d %?p %?p\n", addr, ppa->ppa_zoneid,
    241 	    ppa->ppa_ppa_id, ppa->ppa_ctl, ppa->ppa_lower_wq);
    242 
    243 	return (WALK_NEXT);
    244 }
    245 
    246 /* ARGSUSED */
    247 static int
    248 sppa(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    249 {
    250 	uint_t qfmt = FALSE;
    251 	sppa_t ppa;
    252 
    253 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
    254 		mdb_printf("%<u>%?s %-6s %-9s %?s %?s%</u>\n", "Address",
    255 		    "ZoneID", "Interface", "Control", "LowerQ");
    256 	}
    257 
    258 	if (flags & DCMD_ADDRSPEC) {
    259 		(void) mdb_vread(&ppa, sizeof (ppa), addr);
    260 		(void) ppa_format(addr, &ppa, &qfmt);
    261 	} else if (mdb_walk("sppa", (mdb_walk_cb_t)ppa_format, &qfmt) == -1) {
    262 		mdb_warn("failed to walk ppa_list");
    263 		return (DCMD_ERR);
    264 	}
    265 
    266 	return (DCMD_OK);
    267 }
    268 
    269 static void
    270 sppp_qinfo(const queue_t *q, char *buf, size_t nbytes)
    271 {
    272 	spppstr_t sps;
    273 	sppa_t ppa;
    274 
    275 	if (mdb_vread(&sps, sizeof (sps), (uintptr_t)q->q_ptr) ==
    276 	    sizeof (sps)) {
    277 		if (sps.sps_ppa == NULL ||
    278 		    mdb_vread(&ppa, sizeof (ppa), (uintptr_t)sps.sps_ppa) ==
    279 		    -1) {
    280 			(void) mdb_snprintf(buf, nbytes, "minor %d",
    281 			    sps.sps_mn_id);
    282 		} else {
    283 			(void) mdb_snprintf(buf, nbytes, "sppp%d",
    284 			    ppa.ppa_ppa_id);
    285 		}
    286 	}
    287 }
    288 
    289 static uintptr_t
    290 sppp_rnext(const queue_t *q)
    291 {
    292 	spppstr_t sps;
    293 
    294 	if (mdb_vread(&sps, sizeof (sps), (uintptr_t)q->q_ptr) == sizeof (sps))
    295 		return ((uintptr_t)sps.sps_rq);
    296 
    297 	return (NULL);
    298 }
    299 
    300 static uintptr_t
    301 sppp_wnext(const queue_t *q)
    302 {
    303 	spppstr_t sps;
    304 	sppa_t ppa;
    305 
    306 	if (mdb_vread(&sps, sizeof (sps), (uintptr_t)q->q_ptr) != sizeof (sps))
    307 		return (NULL);
    308 
    309 	if (sps.sps_ppa != NULL &&
    310 	    mdb_vread(&ppa, sizeof (ppa), (uintptr_t)sps.sps_ppa) ==
    311 	    sizeof (ppa))
    312 		return ((uintptr_t)ppa.ppa_lower_wq);
    313 
    314 	return (NULL);
    315 }
    316 
    317 /* ****************** sppptun ****************** */
    318 
    319 struct tcl_walk_data {
    320 	size_t tcl_nslots;
    321 	size_t walkpos;
    322 	tuncl_t *tcl_slots[1];
    323 };
    324 
    325 static void
    326 tuncl_walk_fini(mdb_walk_state_t *wsp)
    327 {
    328 	struct tcl_walk_data *twd;
    329 
    330 	if (wsp != NULL && wsp->walk_addr != 0) {
    331 		twd = (struct tcl_walk_data *)wsp->walk_addr;
    332 		mdb_free(twd, sizeof (*twd) + ((twd->tcl_nslots - 1) *
    333 		    sizeof (twd->tcl_slots[0])));
    334 		wsp->walk_addr = 0;
    335 	}
    336 }
    337 
    338 static int
    339 tuncl_walk_init(mdb_walk_state_t *wsp)
    340 {
    341 	size_t tcl_nslots;
    342 	tuncl_t **tcl_slots;
    343 	struct tcl_walk_data *twd;
    344 
    345 	if (wsp == NULL)
    346 		return (WALK_ERR);
    347 
    348 	if (wsp->walk_addr != 0)
    349 		tuncl_walk_fini(wsp);
    350 
    351 	if (mdb_readvar(&tcl_nslots, "tcl_nslots") == -1) {
    352 		mdb_warn("failed to read tcl_nslots");
    353 		return (WALK_ERR);
    354 	}
    355 
    356 	if (tcl_nslots == 0)
    357 		return (WALK_DONE);
    358 
    359 	if (mdb_readvar(&tcl_slots, "tcl_slots") == -1) {
    360 		mdb_warn("failed to read tcl_slots");
    361 		return (WALK_ERR);
    362 	}
    363 
    364 	twd = (struct tcl_walk_data *)mdb_alloc(sizeof (*twd) +
    365 	    (tcl_nslots - 1) * sizeof (*tcl_slots), UM_NOSLEEP);
    366 	if (twd == NULL)
    367 		return (WALK_ERR);
    368 	twd->tcl_nslots = tcl_nslots;
    369 	twd->walkpos = 0;
    370 	wsp->walk_addr = (uintptr_t)twd;
    371 
    372 	if (mdb_vread(twd->tcl_slots, tcl_nslots * sizeof (twd->tcl_slots[0]),
    373 	    (uintptr_t)tcl_slots) == -1) {
    374 		mdb_warn("can't read tcl_slots at %p", tcl_slots);
    375 		tuncl_walk_fini(wsp);
    376 		return (WALK_ERR);
    377 	}
    378 
    379 	return (WALK_NEXT);
    380 }
    381 
    382 static int
    383 tuncl_walk_step(mdb_walk_state_t *wsp)
    384 {
    385 	tuncl_t tcl;
    386 	int status;
    387 	struct tcl_walk_data *twd;
    388 	uintptr_t addr;
    389 
    390 	if (wsp == NULL || wsp->walk_addr == NULL)
    391 		return (WALK_DONE);
    392 
    393 	twd = (struct tcl_walk_data *)wsp->walk_addr;
    394 
    395 	while (twd->walkpos < twd->tcl_nslots &&
    396 	    twd->tcl_slots[twd->walkpos] == NULL)
    397 		twd->walkpos++;
    398 	if (twd->walkpos >= twd->tcl_nslots)
    399 		return (WALK_DONE);
    400 
    401 	addr = (uintptr_t)twd->tcl_slots[twd->walkpos];
    402 	if (mdb_vread(&tcl, sizeof (tcl), addr) == -1) {
    403 		mdb_warn("can't read tuncl_t at %p", addr);
    404 		return (WALK_ERR);
    405 	}
    406 
    407 	status = wsp->walk_callback(addr, &tcl, wsp->walk_cbdata);
    408 
    409 	twd->walkpos++;
    410 	return (status);
    411 }
    412 
    413 /* ARGSUSED */
    414 static int
    415 tuncl_format(uintptr_t addr, const tuncl_t *tcl, uint_t *qfmt)
    416 {
    417 	mdb_printf("%?p %-6d %?p %?p", addr, tcl->tcl_zoneid, tcl->tcl_data_tll,
    418 	    tcl->tcl_ctrl_tll);
    419 	mdb_printf(" %-2d %04X %04X ", tcl->tcl_style,
    420 	    tcl->tcl_lsessid, tcl->tcl_rsessid);
    421 	if (tcl->tcl_flags & TCLF_DAEMON) {
    422 		mdb_printf("<daemon>\n");
    423 	} else {
    424 		mdb_printf("sppp%d\n", tcl->tcl_unit);
    425 	}
    426 
    427 	return (WALK_NEXT);
    428 }
    429 
    430 /* ARGSUSED */
    431 static int
    432 tuncl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    433 {
    434 	uint_t qfmt = FALSE;
    435 	tuncl_t tcl;
    436 
    437 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
    438 		mdb_printf("%<u>%?s %-6s %?s %?s Ty LSes RSes %s%</u>\n",
    439 		    "Address", "ZoneID", "Data", "Control", "Interface");
    440 	}
    441 
    442 	if (flags & DCMD_ADDRSPEC) {
    443 		if (mdb_vread(&tcl, sizeof (tcl), addr) == -1)
    444 			mdb_warn("failed to read tuncl_t at %p", addr);
    445 		else
    446 			tuncl_format(addr, &tcl, &qfmt);
    447 	} else if (mdb_walk("tuncl", (mdb_walk_cb_t)tuncl_format, &qfmt) ==
    448 	    -1) {
    449 		mdb_warn("failed to walk tcl_slots");
    450 		return (DCMD_ERR);
    451 	}
    452 
    453 	return (DCMD_OK);
    454 }
    455 
    456 struct tll_walk_data {
    457 	void *listhead;
    458 	void *next;
    459 };
    460 
    461 static void
    462 tunll_walk_fini(mdb_walk_state_t *wsp)
    463 {
    464 	struct tll_walk_data *twd;
    465 
    466 	if (wsp != NULL && wsp->walk_addr != 0) {
    467 		twd = (struct tll_walk_data *)wsp->walk_addr;
    468 		mdb_free(twd, sizeof (*twd));
    469 		wsp->walk_addr = 0;
    470 	}
    471 }
    472 
    473 static int
    474 tunll_walk_init(mdb_walk_state_t *wsp)
    475 {
    476 	GElf_Sym sym;
    477 	struct tll_walk_data *twd;
    478 	struct qelem tunll_list;
    479 
    480 	if (wsp->walk_addr != 0)
    481 		tunll_walk_fini(wsp);
    482 
    483 	if (mdb_lookup_by_obj("sppptun", "tunll_list", &sym) != 0) {
    484 		mdb_warn("failed to find tunll_list");
    485 		return (WALK_ERR);
    486 	}
    487 
    488 	if (mdb_vread(&tunll_list, sizeof (tunll_list),
    489 	    (uintptr_t)sym.st_value) == -1) {
    490 		mdb_warn("can't read tunll_list at %p",
    491 		    (uintptr_t)sym.st_value);
    492 		return (WALK_ERR);
    493 	}
    494 
    495 	twd = (struct tll_walk_data *)mdb_alloc(sizeof (*twd), UM_NOSLEEP);
    496 	if (twd == NULL)
    497 		return (WALK_ERR);
    498 	twd->listhead = (void *)(uintptr_t)sym.st_value;
    499 	twd->next = (void *)tunll_list.q_forw;
    500 	wsp->walk_addr = (uintptr_t)twd;
    501 
    502 	return (WALK_NEXT);
    503 }
    504 
    505 static int
    506 tunll_walk_step(mdb_walk_state_t *wsp)
    507 {
    508 	struct tll_walk_data *twd;
    509 	tunll_t tll;
    510 	int status;
    511 	uintptr_t addr;
    512 
    513 	if (wsp == NULL || wsp->walk_addr == 0)
    514 		return (WALK_DONE);
    515 
    516 	twd = (struct tll_walk_data *)wsp->walk_addr;
    517 	if (twd->next == NULL || twd->next == twd->listhead)
    518 		return (WALK_DONE);
    519 
    520 	/* LINTED */
    521 	addr = (uintptr_t)TO_TLL(twd->next);
    522 	if (mdb_vread(&tll, sizeof (tll), addr) == -1) {
    523 		mdb_warn("can't read tunll_t at %p", addr);
    524 		return (WALK_ERR);
    525 	}
    526 
    527 	status = wsp->walk_callback(addr, &tll, wsp->walk_cbdata);
    528 
    529 	twd->next = (void *)tll.tll_next;
    530 	return (status);
    531 }
    532 
    533 /* ARGSUSED */
    534 static int
    535 tunll_format(uintptr_t addr, const tunll_t *tll, uint_t *qfmt)
    536 {
    537 	mdb_printf("%?p %-6d %-14s %?p", addr, tll->tll_zoneid, tll->tll_name,
    538 	    tll->tll_defcl);
    539 	if (tll->tll_style == PTS_PPPOE) {
    540 		mdb_printf(" %x:%x:%x:%x:%x:%x",
    541 		    tll->tll_lcladdr.pta_pppoe.ptma_mac[0],
    542 		    tll->tll_lcladdr.pta_pppoe.ptma_mac[1],
    543 		    tll->tll_lcladdr.pta_pppoe.ptma_mac[2],
    544 		    tll->tll_lcladdr.pta_pppoe.ptma_mac[3],
    545 		    tll->tll_lcladdr.pta_pppoe.ptma_mac[4],
    546 		    tll->tll_lcladdr.pta_pppoe.ptma_mac[5]);
    547 	}
    548 	mdb_printf("\n");
    549 
    550 	return (WALK_NEXT);
    551 }
    552 
    553 /* ARGSUSED */
    554 static int
    555 tunll(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    556 {
    557 	uint_t qfmt = FALSE;
    558 	tunll_t tll;
    559 
    560 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
    561 		mdb_printf("%<u>%?s %-6s %-14s %?s %s%</u>\n", "Address",
    562 		    "ZoneID", "Interface Name", "Daemon", "Local Address");
    563 	}
    564 
    565 	if (flags & DCMD_ADDRSPEC) {
    566 		if (mdb_vread(&tll, sizeof (tll), addr) == -1)
    567 			mdb_warn("failed to read tunll_t at %p", addr);
    568 		else
    569 			tunll_format(addr, &tll, &qfmt);
    570 	} else if (mdb_walk("tunll", (mdb_walk_cb_t)tunll_format, &qfmt) ==
    571 	    -1) {
    572 		mdb_warn("failed to walk tunll_list");
    573 		return (DCMD_ERR);
    574 	}
    575 
    576 	return (DCMD_OK);
    577 }
    578 
    579 union tun_state {
    580 	uint32_t tunflags;
    581 	tuncl_t tcl;
    582 	tunll_t tll;
    583 };
    584 
    585 static int
    586 tun_state_read(void *ptr, union tun_state *ts)
    587 {
    588 	/*
    589 	 * First, get the flags on this structure.  This is either a
    590 	 * tuncl_t or a tunll_t.
    591 	 */
    592 	if (mdb_vread(&ts->tunflags, sizeof (ts->tunflags), (uintptr_t)ptr) ==
    593 	    sizeof (ts->tunflags)) {
    594 		if (ts->tunflags & TCLF_ISCLIENT) {
    595 			if (mdb_vread(&ts->tcl, sizeof (ts->tcl),
    596 			    (uintptr_t)ptr) == sizeof (ts->tcl)) {
    597 				return (0);
    598 			}
    599 		} else {
    600 			if (mdb_vread(&ts->tll, sizeof (ts->tll),
    601 			    (uintptr_t)ptr) == sizeof (ts->tll)) {
    602 				return (0);
    603 			}
    604 		}
    605 	}
    606 	return (-1);
    607 }
    608 
    609 static void
    610 sppptun_qinfo(const queue_t *q, char *buf, size_t nbytes)
    611 {
    612 	union tun_state ts;
    613 
    614 	if (tun_state_read(q->q_ptr, &ts) == -1)
    615 		return;
    616 
    617 	if (ts.tcl.tcl_flags & TCLF_ISCLIENT)
    618 		mdb_snprintf(buf, nbytes, "sppp%d client %04X",
    619 		    ts.tcl.tcl_unit, ts.tcl.tcl_lsessid);
    620 	else
    621 		mdb_snprintf(buf, nbytes, "%s", ts.tll.tll_name);
    622 }
    623 
    624 static uintptr_t
    625 sppptun_rnext(const queue_t *q)
    626 {
    627 	union tun_state ts;
    628 
    629 	if (tun_state_read(q->q_ptr, &ts) == -1)
    630 		return (NULL);
    631 
    632 	if (ts.tcl.tcl_flags & TCLF_ISCLIENT) {
    633 		return ((uintptr_t)ts.tcl.tcl_rq);
    634 	} else {
    635 		/* Not quite right, but ... */
    636 		return ((uintptr_t)ts.tll.tll_defcl);
    637 	}
    638 }
    639 
    640 static uintptr_t
    641 sppptun_wnext(const queue_t *q)
    642 {
    643 	union tun_state ts;
    644 
    645 	if (tun_state_read(q->q_ptr, &ts) == -1)
    646 		return (NULL);
    647 
    648 	if (ts.tcl.tcl_flags & TCLF_ISCLIENT) {
    649 		if (ts.tcl.tcl_data_tll == NULL)
    650 			return (NULL);
    651 		if (mdb_vread(&ts.tll, sizeof (ts.tll),
    652 		    (uintptr_t)ts.tcl.tcl_data_tll) != sizeof (ts.tll)) {
    653 			return (NULL);
    654 		}
    655 	}
    656 	return ((uintptr_t)ts.tll.tll_wq);
    657 }
    658 
    659 static const mdb_dcmd_t dcmds[] = {
    660 	{ "sppp", "[-q]", "display PPP stream state structures", sppp },
    661 	{ "sppa", "", "display PPP attachment state structures", sppa },
    662 	{ "tuncl", "", "display sppptun client stream state structures",
    663 	    tuncl },
    664 	{ "tunll", "", "display sppptun lower stream state structures",
    665 	    tunll },
    666 	{ NULL }
    667 };
    668 
    669 static const mdb_walker_t walkers[] = {
    670 	{ "sppp", "walk active spppstr_t structures",
    671 	    sppp_walk_init, sppp_walk_step, NULL },
    672 	{ "sppa", "walk active sppa_t structures",
    673 	    sppa_walk_init, sppa_walk_step, NULL },
    674 	{ "tuncl", "walk active tuncl_t structures",
    675 	    tuncl_walk_init, tuncl_walk_step, tuncl_walk_fini },
    676 	{ "tunll", "walk active tunll_t structures",
    677 	    tunll_walk_init, tunll_walk_step, tunll_walk_fini },
    678 	{ NULL }
    679 };
    680 
    681 static const mdb_qops_t sppp_qops = { sppp_qinfo, sppp_rnext, sppp_wnext };
    682 static const mdb_qops_t sppptun_qops = {
    683 	sppptun_qinfo, sppptun_rnext, sppptun_wnext
    684 };
    685 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
    686 
    687 const mdb_modinfo_t *
    688 _mdb_init(void)
    689 {
    690 	GElf_Sym sym;
    691 
    692 	if (mdb_lookup_by_obj("sppp", "sppp_uwinit", &sym) == 0)
    693 		mdb_qops_install(&sppp_qops, (uintptr_t)sym.st_value);
    694 
    695 	if (mdb_lookup_by_obj("sppptun", "sppptun_uwinit", &sym) == 0)
    696 		mdb_qops_install(&sppptun_qops, (uintptr_t)sym.st_value);
    697 
    698 	return (&modinfo);
    699 }
    700 
    701 void
    702 _mdb_fini(void)
    703 {
    704 	GElf_Sym sym;
    705 
    706 	if (mdb_lookup_by_obj("sppptun", "sppptun_uwinit", &sym) == 0)
    707 		mdb_qops_remove(&sppptun_qops, (uintptr_t)sym.st_value);
    708 
    709 	if (mdb_lookup_by_obj("sppp", "sppp_uwinit", &sym) == 0)
    710 		mdb_qops_remove(&sppp_qops, (uintptr_t)sym.st_value);
    711 }
    712