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.
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.
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]
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
29 #include <sys/mdb_modapi.h>
30 #include <mdb/mdb_ctf.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <netsmb/smb_conn.h>
35 #include <netsmb/smb_rq.h>
36 #include <netsmb/smb_pass.h>
38 #define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */
39 #define OPT_RECURSE 0x0002 /* recursive display */
42 * We need to read in a private copy
43 * of every string we want to print out.
46 print_str(uintptr_t addr
)
49 int len
, mx
= sizeof (buf
) - 4;
51 if ((len
= mdb_readstr(buf
, sizeof (buf
), addr
)) <= 0) {
52 mdb_printf(" (%p)", addr
);
55 strcpy(&buf
[mx
], "...");
56 mdb_printf(" %s", buf
);
62 * Walker for smb_connobj_t structures, including
63 * smb_vc_t and smb_share_t which "inherit" from it.
64 * Tricky: Exploit the "inheritance" of smb_connobj_t
65 * with common functions for walk_init, walk_next.
67 typedef struct smb_co_walk_data
{
69 int level
; /* SMBL_SM, SMBL_VC, SMBL_SHARE */
70 int size
; /* sizeof (union member) */
72 smb_connobj_t co
; /* copy of the list element */
79 * Common walk_init for walking structs inherited
80 * from smb_connobj_t (smb_vc_t, smb_share_t)
83 smb_co_walk_init(mdb_walk_state_t
*wsp
, int level
)
85 smb_co_walk_data_t
*smbw
;
88 if (wsp
->walk_addr
== (uintptr_t)NULL
)
91 smbw
= mdb_alloc(sizeof (*smbw
), UM_SLEEP
| UM_GC
);
92 wsp
->walk_data
= smbw
;
95 * Save the parent pointer for later checks, and
96 * the level so we know which union member it is.
97 * Also the size of this union member.
99 smbw
->pp
= wsp
->walk_addr
;
103 smbw
->size
= sizeof (smbw
->u
.co
);
106 smbw
->size
= sizeof (smbw
->u
.vc
);
109 smbw
->size
= sizeof (smbw
->u
.ss
);
112 smbw
->size
= sizeof (smbw
->u
);
117 * Read in the parent object. Just need the
118 * invariant part (smb_connobj_t) so we can
119 * get the list of children below it.
121 psz
= sizeof (smbw
->u
.co
);
122 if (mdb_vread(&smbw
->u
.co
, psz
, smbw
->pp
) != psz
) {
123 mdb_warn("cannot read connobj from %p", smbw
->pp
);
128 * Finally, setup to walk the list of children.
130 wsp
->walk_addr
= (uintptr_t)smbw
->u
.co
.co_children
.slh_first
;
136 * Walk the (global) VC list.
139 smb_vc_walk_init(mdb_walk_state_t
*wsp
)
143 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
144 mdb_warn("::walk smb_vc only supports global walks\n");
148 /* Locate the VC list head. */
149 if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym
)) {
150 mdb_warn("failed to lookup `smb_vclist'\n");
153 wsp
->walk_addr
= sym
.st_value
;
155 return (smb_co_walk_init(wsp
, SMBL_VC
));
159 * Walk the share list below some VC.
162 smb_ss_walk_init(mdb_walk_state_t
*wsp
)
166 * Initial walk_addr is address of parent (VC)
168 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
169 mdb_warn("::walk smb_ss does not support global walks\n");
173 return (smb_co_walk_init(wsp
, SMBL_SHARE
));
177 * Common walk_step for walking structs inherited
178 * from smb_connobj_t (smb_vc_t, smb_share_t)
181 smb_co_walk_step(mdb_walk_state_t
*wsp
)
183 smb_co_walk_data_t
*smbw
= wsp
->walk_data
;
186 if (wsp
->walk_addr
== (uintptr_t)NULL
)
189 if (mdb_vread(&smbw
->u
, smbw
->size
, wsp
->walk_addr
)
191 mdb_warn("cannot read connobj from %p", wsp
->walk_addr
);
195 /* XXX: Sanity check level? parent pointer? */
197 status
= wsp
->walk_callback(wsp
->walk_addr
, &smbw
->u
,
200 wsp
->walk_addr
= (uintptr_t)smbw
->u
.co
.co_next
.sle_next
;
207 * Dcmd (and callback function) to print a summary of
208 * all VCs, and optionally all shares under each VC.
211 typedef struct smb_co_cbdata
{
212 int flags
; /* OPT_... */
218 * Call-back function for walking a share list.
221 smb_ss_cb(uintptr_t addr
, const void *data
, void *arg
)
223 const smb_share_t
*ssp
= data
;
224 smb_co_cbdata_t
*cbd
= arg
;
226 mdb_printf(" %-p\t%s\n", addr
, ssp
->ss_name
);
228 if (cbd
->flags
& OPT_VERBOSE
) {
230 /* Anything wanted here? */
238 vcstate_str(smb_co_cbdata_t
*cbd
, int stval
)
240 static const char prefix
[] = "SMBIOD_ST_";
241 int prefix_len
= sizeof (prefix
) - 1;
242 mdb_ctf_id_t vcst_enum
;
245 /* Got this in smb_vc_dcmd. */
246 vcst_enum
= cbd
->ctf_id
;
248 /* Get the name for the enum value. */
249 if ((cp
= mdb_ctf_enum_name(vcst_enum
, stval
)) == NULL
)
252 /* Skip the prefix part. */
253 if (strncmp(cp
, prefix
, prefix_len
) == 0)
260 * Call-back function for walking the VC list.
263 smb_vc_cb(uintptr_t addr
, const void *data
, void *arg
)
265 const smb_vc_t
*vcp
= data
;
266 smb_co_cbdata_t
*cbd
= arg
;
268 if (cbd
->printed_header
== 0) {
269 cbd
->printed_header
= 1;
270 mdb_printf("// smb_vc_t uid server \tuser\t\tstate\n");
273 mdb_printf("%-p", addr
);
274 mdb_printf(" %7d", vcp
->vc_owner
);
276 switch (vcp
->vc_srvaddr
.sa
.sa_family
) {
278 mdb_printf(" %I", vcp
->vc_srvaddr
.sin
.sin_addr
);
281 mdb_printf(" %N", &vcp
->vc_srvaddr
.sin6
.sin6_addr
);
284 mdb_printf(" %15s", "(bad af)");
288 if (vcp
->vc_username
[0] != '\0')
289 mdb_printf("\t%s", vcp
->vc_username
);
291 mdb_printf("\t%s", "(?)");
293 if (vcp
->vc_domain
[0] != '\0')
294 mdb_printf("@%s", vcp
->vc_domain
);
296 mdb_printf("\t%s\n", vcstate_str(cbd
, vcp
->vc_state
));
298 if (cbd
->flags
& OPT_RECURSE
) {
300 if (mdb_pwalk("nsmb_ss", smb_ss_cb
, cbd
, addr
) < 0) {
301 mdb_warn("failed to walk 'nsmb_ss'");
302 /* Don't: return (WALK_ERR); */
311 smb_vc_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
317 memset(&cbd
, 0, sizeof (cbd
));
319 if (mdb_getopts(argc
, argv
,
320 'r', MDB_OPT_SETBITS
, OPT_RECURSE
, &cbd
.flags
,
321 'v', MDB_OPT_SETBITS
, OPT_VERBOSE
, &cbd
.flags
,
326 if (mdb_ctf_lookup_by_name("enum smbiod_state", &cbd
.ctf_id
) == -1) {
327 mdb_warn("Could not find enum smbiod_state");
330 if (!(flags
& DCMD_ADDRSPEC
)) {
331 if (mdb_walk("nsmb_vc", smb_vc_cb
, &cbd
) == -1) {
332 mdb_warn("failed to walk 'nsmb_vc'");
338 vcsz
= sizeof (*vcp
);
339 vcp
= mdb_alloc(vcsz
, UM_SLEEP
| UM_GC
);
340 if (mdb_vread(vcp
, vcsz
, addr
) != vcsz
) {
341 mdb_warn("cannot read VC from %p", addr
);
344 smb_vc_cb(addr
, vcp
, &cbd
);
352 mdb_printf("Options:\n"
353 " -r recursive display of share lists\n"
354 " -v be verbose when displaying smb_vc\n");
358 * Walker for the request list on a VC,
359 * and dcmd to show a summary.
362 rqlist_walk_init(mdb_walk_state_t
*wsp
)
364 struct smb_rqhead rqh
;
368 * Initial walk_addr is the address of the VC.
369 * Add offsetof(iod_rqlist) to get the rqhead.
371 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
372 mdb_warn("::walk smb_ss does not support global walks\n");
375 addr
= wsp
->walk_addr
;
376 addr
+= OFFSETOF(smb_vc_t
, iod_rqlist
);
378 if (mdb_vread(&rqh
, sizeof (rqh
), addr
) == -1) {
379 mdb_warn("failed to read smb_rqhead at %p", addr
);
382 wsp
->walk_addr
= (uintptr_t)rqh
.tqh_first
;
388 rqlist_walk_step(mdb_walk_state_t
*wsp
)
393 if (wsp
->walk_addr
== (uintptr_t)NULL
)
396 if (mdb_vread(&rq
, sizeof (rq
), wsp
->walk_addr
) == -1) {
397 mdb_warn("cannot read smb_rq from %p", wsp
->walk_addr
);
401 status
= wsp
->walk_callback(wsp
->walk_addr
, &rq
,
404 wsp
->walk_addr
= (uintptr_t)rq
.sr_link
.tqe_next
;
409 typedef struct rqlist_cbdata
{
411 uintptr_t uid
; /* optional filtering by UID */
415 rqlist_cb(uintptr_t addr
, const void *data
, void *arg
)
417 const smb_rq_t
*rq
= data
;
418 rqlist_cbdata_t
*cbd
= arg
;
420 if (cbd
->printed_header
== 0) {
421 cbd
->printed_header
= 1;
422 mdb_printf("// smb_rq_t MID cmd sr_state sr_flags\n");
425 mdb_printf(" %-p", addr
); /* smb_rq_t */
426 mdb_printf(" x%04x", rq
->sr_mid
);
427 mdb_printf(" x%02x", rq
->sr_cmd
);
428 mdb_printf(" %d", rq
->sr_state
);
429 mdb_printf(" x%x", rq
->sr_flags
);
437 rqlist_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
441 memset(&cbd
, 0, sizeof (cbd
));
444 * Initial walk_addr is address of parent (VC)
446 if (!(flags
& DCMD_ADDRSPEC
)) {
447 mdb_warn("address required\n");
451 if (mdb_pwalk("nsmb_rqlist", rqlist_cb
, &cbd
, addr
) == -1) {
452 mdb_warn("failed to walk 'nsmb_rqlist'");
461 * AVL walker for the passwords AVL tree,
462 * and dcmd to show a summary.
465 pwtree_walk_init(mdb_walk_state_t
*wsp
)
469 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
470 mdb_warn("pwtree walk only supports global walks\n");
474 if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym
) == -1) {
475 mdb_warn("failed to find symbol 'smb_ptd'");
479 wsp
->walk_addr
= (uintptr_t)sym
.st_value
;
481 if (mdb_layered_walk("avl", wsp
) == -1) {
482 mdb_warn("failed to walk 'avl'\n");
490 pwtree_walk_step(mdb_walk_state_t
*wsp
)
494 if (mdb_vread(&ptnode
, sizeof (ptnode
), wsp
->walk_addr
) == -1) {
495 mdb_warn("failed to read smb_passid_t at %p", wsp
->walk_addr
);
499 return (wsp
->walk_callback(wsp
->walk_addr
, &ptnode
, wsp
->walk_cbdata
));
502 typedef struct pwtree_cbdata
{
504 uid_t uid
; /* optional filtering by UID */
508 pwtree_cb(uintptr_t addr
, const void *data
, void *arg
)
510 const smb_passid_t
*ptn
= data
;
511 pwtree_cbdata_t
*cbd
= arg
;
513 /* Optional filtering by UID. */
514 if (cbd
->uid
!= (uid_t
)-1 && cbd
->uid
!= ptn
->uid
) {
518 if (cbd
->printed_header
== 0) {
519 cbd
->printed_header
= 1;
520 mdb_printf("// smb_passid_t UID domain user\n");
523 mdb_printf(" %-p", addr
); /* smb_passid_t */
524 mdb_printf(" %d", (uintptr_t)ptn
->uid
);
525 print_str((uintptr_t)ptn
->srvdom
);
526 print_str((uintptr_t)ptn
->username
);
534 pwtree_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
537 char *uid_str
= NULL
;
540 memset(&cbd
, 0, sizeof (cbd
));
542 if (mdb_getopts(argc
, argv
,
543 'u', MDB_OPT_STR
, &uid_str
, NULL
) != argc
) {
548 * Want the the default radix to be 10 here.
549 * If the string has some kind of radix prefix,
550 * just use that as-is, otherwise prepend "0t".
551 * Cheating on the "not a digit" test, but
552 * mdb_strtoull will do a real syntax check.
554 if (uid_str
[0] == '0' && uid_str
[1] > '9') {
555 cbd
.uid
= (uid_t
)mdb_strtoull(uid_str
);
558 strlcat(buf
, uid_str
, sizeof (buf
));
559 cbd
.uid
= (uid_t
)mdb_strtoull(buf
);
564 if (flags
& DCMD_ADDRSPEC
) {
565 mdb_warn("address not allowed\n");
569 if (mdb_pwalk("nsmb_pwtree", pwtree_cb
, &cbd
, 0) == -1) {
570 mdb_warn("failed to walk 'nsmb_pwtree'");
580 mdb_printf("Options:\n"
581 " -u uid show only entries belonging to uid (decimal)\n");
585 static const mdb_dcmd_t dcmds
[] = {
586 { "nsmb_vc", "?[-rv]",
587 "show smb_vc (or list)",
588 smb_vc_dcmd
, smb_vc_help
},
589 { "nsmb_rqlist", ":",
590 "show smb_rq list on a VC",
592 { "nsmb_pwtree", "?[-u uid]",
593 "list smb_passid_t (password tree)",
594 pwtree_dcmd
, pwtree_help
},
598 static const mdb_walker_t walkers
[] = {
599 { "nsmb_vc", "walk nsmb VC list",
600 smb_vc_walk_init
, smb_co_walk_step
, NULL
},
601 { "nsmb_ss", "walk nsmb share list for some VC",
602 smb_ss_walk_init
, smb_co_walk_step
, NULL
},
603 { "nsmb_rqlist", "walk request list for some VC",
604 rqlist_walk_init
, rqlist_walk_step
, NULL
},
605 { "nsmb_pwtree", "walk passord AVL tree",
606 pwtree_walk_init
, pwtree_walk_step
, NULL
},
610 static const mdb_modinfo_t modinfo
= {
616 const mdb_modinfo_t
*