1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <sys/types.h> 32*0Sstevel@tonic-gate #include <sys/stat.h> 33*0Sstevel@tonic-gate #include <unistd.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <strings.h> 36*0Sstevel@tonic-gate #include <string.h> 37*0Sstevel@tonic-gate #include <fcntl.h> 38*0Sstevel@tonic-gate #include <assert.h> 39*0Sstevel@tonic-gate #include <libipp.h> 40*0Sstevel@tonic-gate #include <libnvpair.h> 41*0Sstevel@tonic-gate #include <ipp/ippctl.h> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate /* 44*0Sstevel@tonic-gate * Debug macros 45*0Sstevel@tonic-gate */ 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #if defined(DEBUG) && !defined(lint) 48*0Sstevel@tonic-gate uint32_t ipp_debug_flags = 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * DBG_IO | 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate DBG_ERR | 53*0Sstevel@tonic-gate 0; 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #define DBG0(flags, fmt) \ 56*0Sstevel@tonic-gate do { \ 57*0Sstevel@tonic-gate if (flags & ipp_debug_flags) \ 58*0Sstevel@tonic-gate fprintf(stderr, "libipp: " __FN__ ": " fmt); \ 59*0Sstevel@tonic-gate } while (0) 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #define DBG1(flags, fmt, a) \ 62*0Sstevel@tonic-gate do { \ 63*0Sstevel@tonic-gate if (flags & ipp_debug_flags) \ 64*0Sstevel@tonic-gate fprintf(stderr, "libipp: " __FN__ ": " fmt, a); \ 65*0Sstevel@tonic-gate } while (0) 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate #define DBG2(flags, fmt, a, b) \ 68*0Sstevel@tonic-gate do { \ 69*0Sstevel@tonic-gate if (flags & ipp_debug_flags) \ 70*0Sstevel@tonic-gate fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \ 71*0Sstevel@tonic-gate b); \ 72*0Sstevel@tonic-gate } while (0) 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #define DBG3(flags, fmt, a, b, c) \ 75*0Sstevel@tonic-gate do { \ 76*0Sstevel@tonic-gate if (flags & ipp_debug_flags) \ 77*0Sstevel@tonic-gate fprintf(stderr, "libipp: " __FN__ ": " fmt, a, \ 78*0Sstevel@tonic-gate b, c); \ 79*0Sstevel@tonic-gate } while (0) 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #else /* defined(DEBUG) && !defined(lint) */ 82*0Sstevel@tonic-gate #define DBG0(flags, fmt) 83*0Sstevel@tonic-gate #define DBG1(flags, fmt, a) 84*0Sstevel@tonic-gate #define DBG2(flags, fmt, a, b) 85*0Sstevel@tonic-gate #define DBG3(flags, fmt, a, b, c) 86*0Sstevel@tonic-gate #endif /* defined(DEBUG) && !defined(lint) */ 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * Control device node 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate #define IPPCTL_DEVICE "/devices/pseudo/ippctl@0:ctl" 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Structures. 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate typedef struct array_desc_t { 99*0Sstevel@tonic-gate char *name; 100*0Sstevel@tonic-gate char **array; 101*0Sstevel@tonic-gate int nelt; 102*0Sstevel@tonic-gate } array_desc_t; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* 105*0Sstevel@tonic-gate * Prototypes 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate static int nvlist_callback(nvlist_t *, void *); 109*0Sstevel@tonic-gate static int string_callback(nvlist_t *, void *); 110*0Sstevel@tonic-gate static int string_array_callback(nvlist_t *, void *); 111*0Sstevel@tonic-gate static int dispatch(nvlist_t **, int (*)(nvlist_t *, void *), void *); 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * API functions 115*0Sstevel@tonic-gate */ 116*0Sstevel@tonic-gate #define __FN__ "ipp_action_create" 117*0Sstevel@tonic-gate int 118*0Sstevel@tonic-gate ipp_action_create( 119*0Sstevel@tonic-gate const char *modname, 120*0Sstevel@tonic-gate const char *aname, 121*0Sstevel@tonic-gate nvlist_t **nvlpp, 122*0Sstevel@tonic-gate ipp_flags_t flags) 123*0Sstevel@tonic-gate { 124*0Sstevel@tonic-gate nvlist_t *nvlp; 125*0Sstevel@tonic-gate int rc; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * Sanity check the arguments. 129*0Sstevel@tonic-gate */ 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate if (nvlpp == NULL || modname == NULL || aname == NULL) { 132*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument\n"); 133*0Sstevel@tonic-gate errno = EINVAL; 134*0Sstevel@tonic-gate return (-1); 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* 138*0Sstevel@tonic-gate * Add our data to the nvlist. (This information will be removed for 139*0Sstevel@tonic-gate * use by ippctl). 140*0Sstevel@tonic-gate */ 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate nvlp = *nvlpp; 143*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 144*0Sstevel@tonic-gate IPPCTL_OP_ACTION_CREATE)) != 0) { 145*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 146*0Sstevel@tonic-gate goto failed; 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_MODNAME, 150*0Sstevel@tonic-gate (char *)modname)) != 0) { 151*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", 152*0Sstevel@tonic-gate IPPCTL_MODNAME); 153*0Sstevel@tonic-gate goto failed; 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 157*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 158*0Sstevel@tonic-gate goto failed; 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 162*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 163*0Sstevel@tonic-gate goto failed; 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * Talk to the kernel. 168*0Sstevel@tonic-gate */ 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate return (dispatch(nvlpp, nvlist_callback, (void *)nvlpp)); 171*0Sstevel@tonic-gate failed: 172*0Sstevel@tonic-gate errno = rc; 173*0Sstevel@tonic-gate return (-1); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate #undef __FN__ 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate #define __FN__ "ipp_action_destroy" 178*0Sstevel@tonic-gate int 179*0Sstevel@tonic-gate ipp_action_destroy( 180*0Sstevel@tonic-gate const char *aname, 181*0Sstevel@tonic-gate ipp_flags_t flags) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate nvlist_t *nvlp; 184*0Sstevel@tonic-gate int rc; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* 187*0Sstevel@tonic-gate * Sanity check the arguments. 188*0Sstevel@tonic-gate */ 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate if (aname == NULL) { 191*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument\n"); 192*0Sstevel@tonic-gate errno = EINVAL; 193*0Sstevel@tonic-gate return (-1); 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate /* 197*0Sstevel@tonic-gate * Create an nvlist for our data as none is passed into the function. 198*0Sstevel@tonic-gate */ 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 201*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to allocate nvlist\n"); 202*0Sstevel@tonic-gate nvlp = NULL; 203*0Sstevel@tonic-gate goto failed; 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 207*0Sstevel@tonic-gate IPPCTL_OP_ACTION_DESTROY)) != 0) { 208*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 209*0Sstevel@tonic-gate goto failed; 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 213*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 214*0Sstevel@tonic-gate goto failed; 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 218*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 219*0Sstevel@tonic-gate goto failed; 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * Talk to the kernel. 224*0Sstevel@tonic-gate */ 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate return (dispatch(&nvlp, NULL, NULL)); 227*0Sstevel@tonic-gate failed: 228*0Sstevel@tonic-gate if (nvlp != NULL) 229*0Sstevel@tonic-gate nvlist_free(nvlp); 230*0Sstevel@tonic-gate errno = rc; 231*0Sstevel@tonic-gate return (-1); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate #undef __FN__ 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate #define __FN__ "ipp_action_modify" 236*0Sstevel@tonic-gate int 237*0Sstevel@tonic-gate ipp_action_modify( 238*0Sstevel@tonic-gate const char *aname, 239*0Sstevel@tonic-gate nvlist_t **nvlpp, 240*0Sstevel@tonic-gate ipp_flags_t flags) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate nvlist_t *nvlp; 243*0Sstevel@tonic-gate int rc; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* 246*0Sstevel@tonic-gate * Sanity check the arguments. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if (nvlpp == NULL || aname == NULL) { 250*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument\n"); 251*0Sstevel@tonic-gate errno = EINVAL; 252*0Sstevel@tonic-gate return (-1); 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * Add our data to the nvlist. 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate nvlp = *nvlpp; 260*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 261*0Sstevel@tonic-gate IPPCTL_OP_ACTION_MODIFY)) != 0) { 262*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 263*0Sstevel@tonic-gate goto failed; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 267*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 268*0Sstevel@tonic-gate goto failed; 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 272*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 273*0Sstevel@tonic-gate goto failed; 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * Talk to the kernel. 278*0Sstevel@tonic-gate */ 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate return (dispatch(nvlpp, nvlist_callback, (void *)nvlpp)); 281*0Sstevel@tonic-gate failed: 282*0Sstevel@tonic-gate errno = rc; 283*0Sstevel@tonic-gate return (-1); 284*0Sstevel@tonic-gate } 285*0Sstevel@tonic-gate #undef __FN__ 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate #define __FN__ "ipp_action_info" 288*0Sstevel@tonic-gate int 289*0Sstevel@tonic-gate ipp_action_info( 290*0Sstevel@tonic-gate const char *aname, 291*0Sstevel@tonic-gate int (*fn)(nvlist_t *, void *), 292*0Sstevel@tonic-gate void *arg, 293*0Sstevel@tonic-gate ipp_flags_t flags) 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate nvlist_t *nvlp; 296*0Sstevel@tonic-gate int rc; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * Sanity check the arguments. 300*0Sstevel@tonic-gate */ 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate if (aname == NULL || fn == NULL) { 303*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument\n"); 304*0Sstevel@tonic-gate errno = EINVAL; 305*0Sstevel@tonic-gate return (-1); 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * Create an nvlist for our data. 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 313*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to allocate nvlist\n"); 314*0Sstevel@tonic-gate nvlp = NULL; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 318*0Sstevel@tonic-gate IPPCTL_OP_ACTION_INFO)) != 0) { 319*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 320*0Sstevel@tonic-gate goto failed; 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 324*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 325*0Sstevel@tonic-gate goto failed; 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate if ((rc = nvlist_add_uint32(nvlp, IPPCTL_FLAGS, flags)) != 0) { 329*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_FLAGS); 330*0Sstevel@tonic-gate goto failed; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * Talk to the kernel. 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate return (dispatch(&nvlp, fn, arg)); 338*0Sstevel@tonic-gate failed: 339*0Sstevel@tonic-gate if (nvlp != NULL) 340*0Sstevel@tonic-gate nvlist_free(nvlp); 341*0Sstevel@tonic-gate errno = rc; 342*0Sstevel@tonic-gate return (-1); 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate #undef __FN__ 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate #define __FN__ "ipp_action_mod" 347*0Sstevel@tonic-gate int 348*0Sstevel@tonic-gate ipp_action_mod( 349*0Sstevel@tonic-gate const char *aname, 350*0Sstevel@tonic-gate char **modnamep) 351*0Sstevel@tonic-gate { 352*0Sstevel@tonic-gate nvlist_t *nvlp; 353*0Sstevel@tonic-gate int rc; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate /* 356*0Sstevel@tonic-gate * Sanity check the arguments. 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (aname == NULL || modnamep == NULL) { 360*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument\n"); 361*0Sstevel@tonic-gate errno = EINVAL; 362*0Sstevel@tonic-gate return (-1); 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* 366*0Sstevel@tonic-gate * Create an nvlist for our data. 367*0Sstevel@tonic-gate */ 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 370*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to allocate nvlist\n"); 371*0Sstevel@tonic-gate nvlp = NULL; 372*0Sstevel@tonic-gate goto failed; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 376*0Sstevel@tonic-gate IPPCTL_OP_ACTION_MOD)) != 0) { 377*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 378*0Sstevel@tonic-gate goto failed; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_ANAME, (char *)aname)) != 0) { 382*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_ANAME); 383*0Sstevel@tonic-gate goto failed; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * Talk to the kernel. 388*0Sstevel@tonic-gate */ 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate return (dispatch(&nvlp, string_callback, (void *)modnamep)); 391*0Sstevel@tonic-gate failed: 392*0Sstevel@tonic-gate if (nvlp != NULL) 393*0Sstevel@tonic-gate nvlist_free(nvlp); 394*0Sstevel@tonic-gate errno = rc; 395*0Sstevel@tonic-gate return (-1); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate #undef __FN__ 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate #define __FN__ "ipp_list_mods" 400*0Sstevel@tonic-gate int 401*0Sstevel@tonic-gate ipp_list_mods( 402*0Sstevel@tonic-gate char ***modname_arrayp, 403*0Sstevel@tonic-gate int *neltp) 404*0Sstevel@tonic-gate { 405*0Sstevel@tonic-gate nvlist_t *nvlp; 406*0Sstevel@tonic-gate array_desc_t ad; 407*0Sstevel@tonic-gate int rc; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * Sanity check the arguments. 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate if (modname_arrayp == NULL || neltp == NULL) { 414*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument"); 415*0Sstevel@tonic-gate errno = EINVAL; 416*0Sstevel@tonic-gate return (-1); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * Create an nvlist for our data. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 424*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to allocate nvlist\n"); 425*0Sstevel@tonic-gate nvlp = NULL; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 429*0Sstevel@tonic-gate IPPCTL_OP_LIST_MODS)) != 0) { 430*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 431*0Sstevel@tonic-gate goto failed; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * Talk to the kernel. 436*0Sstevel@tonic-gate */ 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate ad.name = IPPCTL_MODNAME_ARRAY; 439*0Sstevel@tonic-gate ad.array = NULL; 440*0Sstevel@tonic-gate ad.nelt = 0; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate if ((rc = dispatch(&nvlp, string_array_callback, (void *)&ad)) == 0) { 443*0Sstevel@tonic-gate *modname_arrayp = ad.array; 444*0Sstevel@tonic-gate *neltp = ad.nelt; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate return (rc); 448*0Sstevel@tonic-gate failed: 449*0Sstevel@tonic-gate if (nvlp != NULL) 450*0Sstevel@tonic-gate nvlist_free(nvlp); 451*0Sstevel@tonic-gate errno = rc; 452*0Sstevel@tonic-gate return (-1); 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate #undef __FN__ 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate #define __FN__ "ipp_mod_list_actions" 457*0Sstevel@tonic-gate int 458*0Sstevel@tonic-gate ipp_mod_list_actions( 459*0Sstevel@tonic-gate const char *modname, 460*0Sstevel@tonic-gate char ***aname_arrayp, 461*0Sstevel@tonic-gate int *neltp) 462*0Sstevel@tonic-gate { 463*0Sstevel@tonic-gate nvlist_t *nvlp; 464*0Sstevel@tonic-gate array_desc_t ad; 465*0Sstevel@tonic-gate int rc; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * Sanity check the arguments. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate if (modname == NULL || aname_arrayp == NULL || neltp == NULL) { 472*0Sstevel@tonic-gate DBG0(DBG_ERR, "bad argument"); 473*0Sstevel@tonic-gate errno = EINVAL; 474*0Sstevel@tonic-gate return (-1); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate /* 478*0Sstevel@tonic-gate * Create an nvlist for our data. 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, 0)) != 0) { 482*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to allocate nvlist\n"); 483*0Sstevel@tonic-gate nvlp = NULL; 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if ((rc = nvlist_add_byte(nvlp, IPPCTL_OP, 487*0Sstevel@tonic-gate IPPCTL_OP_MOD_LIST_ACTIONS)) != 0) { 488*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_OP); 489*0Sstevel@tonic-gate goto failed; 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate if ((rc = nvlist_add_string(nvlp, IPPCTL_MODNAME, 493*0Sstevel@tonic-gate (char *)modname)) != 0) { 494*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to add '%s' to nvlist\n", IPPCTL_MODNAME); 495*0Sstevel@tonic-gate goto failed; 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate /* 499*0Sstevel@tonic-gate * Talk to the kernel. 500*0Sstevel@tonic-gate */ 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate ad.name = IPPCTL_ANAME_ARRAY; 503*0Sstevel@tonic-gate ad.array = NULL; 504*0Sstevel@tonic-gate ad.nelt = 0; 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if ((rc = dispatch(&nvlp, string_array_callback, (void *)&ad)) == 0) { 507*0Sstevel@tonic-gate *aname_arrayp = ad.array; 508*0Sstevel@tonic-gate *neltp = ad.nelt; 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate return (rc); 512*0Sstevel@tonic-gate failed: 513*0Sstevel@tonic-gate if (nvlp != NULL) 514*0Sstevel@tonic-gate nvlist_free(nvlp); 515*0Sstevel@tonic-gate errno = rc; 516*0Sstevel@tonic-gate return (-1); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate #undef __FN__ 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate #define __FN__ "ipp_free" 521*0Sstevel@tonic-gate void 522*0Sstevel@tonic-gate ipp_free( 523*0Sstevel@tonic-gate char *buf) 524*0Sstevel@tonic-gate { 525*0Sstevel@tonic-gate free(buf); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate #undef __FN__ 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate #define __FN__ "ipp_free_array" 530*0Sstevel@tonic-gate void 531*0Sstevel@tonic-gate ipp_free_array( 532*0Sstevel@tonic-gate char **array, 533*0Sstevel@tonic-gate int nelt) 534*0Sstevel@tonic-gate { 535*0Sstevel@tonic-gate int i; 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate assert(array[nelt] == NULL); 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate for (i = 0; i < nelt; i++) 540*0Sstevel@tonic-gate free(array[i]); 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate free(array); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate #undef __FN__ 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate #define __FN__ "nvlist_callback" 547*0Sstevel@tonic-gate static int 548*0Sstevel@tonic-gate nvlist_callback( 549*0Sstevel@tonic-gate nvlist_t *nvlp, 550*0Sstevel@tonic-gate void *arg) 551*0Sstevel@tonic-gate { 552*0Sstevel@tonic-gate nvlist_t **nvlpp = (nvlist_t **)arg; 553*0Sstevel@tonic-gate int rc; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate /* 556*0Sstevel@tonic-gate * Callback function used by ipp_action_create() and 557*0Sstevel@tonic-gate * ipp_action_modify() 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate DBG0(DBG_IO, "called\n"); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate assert(nvlpp != NULL); 563*0Sstevel@tonic-gate assert(*nvlpp == NULL); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * Duplicate the nvlist and set the given pointer to point at the new 567*0Sstevel@tonic-gate * copy. 568*0Sstevel@tonic-gate */ 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate if ((rc = nvlist_dup(nvlp, nvlpp, 0)) != 0) { 571*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to dup nvlist\n"); 572*0Sstevel@tonic-gate errno = rc; 573*0Sstevel@tonic-gate return (-1); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate return (0); 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate #undef __FN__ 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate #define __FN__ "string_callback" 581*0Sstevel@tonic-gate static int 582*0Sstevel@tonic-gate string_callback( 583*0Sstevel@tonic-gate nvlist_t *nvlp, 584*0Sstevel@tonic-gate void *arg) 585*0Sstevel@tonic-gate { 586*0Sstevel@tonic-gate char **namep = (char **)arg; 587*0Sstevel@tonic-gate char *name; 588*0Sstevel@tonic-gate char *ptr; 589*0Sstevel@tonic-gate int rc; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate /* 592*0Sstevel@tonic-gate * Callback function used by ipp_action_mod() 593*0Sstevel@tonic-gate */ 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate DBG0(DBG_IO, "called\n"); 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate assert(namep != NULL); 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * Look up the module name from the nvlist. 601*0Sstevel@tonic-gate */ 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, IPPCTL_MODNAME, &ptr)) != 0) { 604*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to find string\n"); 605*0Sstevel@tonic-gate errno = rc; 606*0Sstevel@tonic-gate return (-1); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate /* 610*0Sstevel@tonic-gate * Allocate a duplicate string. 611*0Sstevel@tonic-gate */ 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate if ((name = strdup(ptr)) == NULL) { 614*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to duplicate string\n"); 615*0Sstevel@tonic-gate return (-1); 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* 619*0Sstevel@tonic-gate * Set the given pointer to point at the string. 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate *namep = name; 623*0Sstevel@tonic-gate return (0); 624*0Sstevel@tonic-gate } 625*0Sstevel@tonic-gate #undef __FN__ 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate #define __FN__ "string_array_callback" 628*0Sstevel@tonic-gate static int 629*0Sstevel@tonic-gate string_array_callback( 630*0Sstevel@tonic-gate nvlist_t *nvlp, 631*0Sstevel@tonic-gate void *arg) 632*0Sstevel@tonic-gate { 633*0Sstevel@tonic-gate array_desc_t *adp = (array_desc_t *)arg; 634*0Sstevel@tonic-gate char **dst; 635*0Sstevel@tonic-gate char **src; 636*0Sstevel@tonic-gate uint_t nelt; 637*0Sstevel@tonic-gate int i; 638*0Sstevel@tonic-gate int rc; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate /* 641*0Sstevel@tonic-gate * Callback function used by ipp_list_mods() 642*0Sstevel@tonic-gate */ 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate DBG0(DBG_IO, "called\n"); 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate assert(adp != NULL); 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * Look up the module name from the nvlist. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate if ((rc = nvlist_lookup_string_array(nvlp, adp->name, &src, 653*0Sstevel@tonic-gate &nelt)) != 0) { 654*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to find array\n"); 655*0Sstevel@tonic-gate errno = rc; 656*0Sstevel@tonic-gate return (-1); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate /* 660*0Sstevel@tonic-gate * Allocate an array. 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate if ((dst = malloc((nelt + 1) * sizeof (char *))) == NULL) { 664*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to allocate new array\n"); 665*0Sstevel@tonic-gate return (-1); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate /* 669*0Sstevel@tonic-gate * For each string in the array, allocate a new buffer and copy 670*0Sstevel@tonic-gate * the string into it. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate for (i = 0; i < nelt; i++) { 674*0Sstevel@tonic-gate if ((dst[i] = strdup(src[i])) == NULL) { 675*0Sstevel@tonic-gate while (--i >= 0) { 676*0Sstevel@tonic-gate free(dst[i]); 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate free(dst); 679*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to duplicate array\n"); 680*0Sstevel@tonic-gate return (-1); 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate dst[nelt] = NULL; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate /* 686*0Sstevel@tonic-gate * Set the information to be passed back. 687*0Sstevel@tonic-gate */ 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate adp->array = dst; 690*0Sstevel@tonic-gate adp->nelt = nelt; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate return (0); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate #undef __FN__ 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate #define __FN__ "dispatch" 697*0Sstevel@tonic-gate static int 698*0Sstevel@tonic-gate dispatch( 699*0Sstevel@tonic-gate nvlist_t **nvlpp, 700*0Sstevel@tonic-gate int (*fn)(nvlist_t *, void *), 701*0Sstevel@tonic-gate void *arg) 702*0Sstevel@tonic-gate { 703*0Sstevel@tonic-gate char *cbuf = NULL; 704*0Sstevel@tonic-gate char *dbuf = NULL; 705*0Sstevel@tonic-gate size_t cbuflen = 0; 706*0Sstevel@tonic-gate size_t dbuflen = 0; 707*0Sstevel@tonic-gate size_t thisbuflen = 0; 708*0Sstevel@tonic-gate size_t nextbuflen = 0; 709*0Sstevel@tonic-gate int rc; 710*0Sstevel@tonic-gate ippctl_ioctl_t iioc; 711*0Sstevel@tonic-gate int fd; 712*0Sstevel@tonic-gate nvlist_t *cnvlp; 713*0Sstevel@tonic-gate nvlist_t *dnvlp = NULL; 714*0Sstevel@tonic-gate int count; 715*0Sstevel@tonic-gate int rval; 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate /* 718*0Sstevel@tonic-gate * Sanity check the 'command' nvlist. 719*0Sstevel@tonic-gate */ 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate cnvlp = *nvlpp; 722*0Sstevel@tonic-gate if (cnvlp == NULL) { 723*0Sstevel@tonic-gate rc = EINVAL; 724*0Sstevel@tonic-gate return (-1); 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate /* 728*0Sstevel@tonic-gate * Pack the nvlist and then free the original. 729*0Sstevel@tonic-gate */ 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate if ((rc = nvlist_pack(cnvlp, &cbuf, &cbuflen, NV_ENCODE_NATIVE, 732*0Sstevel@tonic-gate 0)) != 0) { 733*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to pack nvlist\n"); 734*0Sstevel@tonic-gate nvlist_free(cnvlp); 735*0Sstevel@tonic-gate errno = rc; 736*0Sstevel@tonic-gate return (-1); 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate nvlist_free(cnvlp); 739*0Sstevel@tonic-gate *nvlpp = NULL; 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate /* 742*0Sstevel@tonic-gate * Open the control device node. 743*0Sstevel@tonic-gate */ 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate DBG1(DBG_IO, "opening %s\n", IPPCTL_DEVICE); 746*0Sstevel@tonic-gate if ((fd = open(IPPCTL_DEVICE, O_RDWR | O_NOCTTY)) == -1) { 747*0Sstevel@tonic-gate DBG1(DBG_ERR, "failed to open %s\n", IPPCTL_DEVICE); 748*0Sstevel@tonic-gate goto command_failed; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate /* 752*0Sstevel@tonic-gate * Set up an ioctl structure to point at the packed nvlist. 753*0Sstevel@tonic-gate */ 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate iioc.ii_buf = cbuf; 756*0Sstevel@tonic-gate iioc.ii_buflen = cbuflen; 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate /* 759*0Sstevel@tonic-gate * Issue a command ioctl, passing the ioctl structure. 760*0Sstevel@tonic-gate */ 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate DBG0(DBG_IO, "command\n"); 763*0Sstevel@tonic-gate if ((rc = ioctl(fd, IPPCTL_CMD, &iioc)) < 0) { 764*0Sstevel@tonic-gate DBG0(DBG_ERR, "command ioctl failed\n"); 765*0Sstevel@tonic-gate goto command_failed; 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate /* 769*0Sstevel@tonic-gate * Get back the length of the first data buffer. 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate if ((nextbuflen = (size_t)rc) == 0) { 773*0Sstevel@tonic-gate DBG0(DBG_ERR, "no data buffer\n"); 774*0Sstevel@tonic-gate errno = EPROTO; 775*0Sstevel@tonic-gate goto command_failed; 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate /* 779*0Sstevel@tonic-gate * Try to re-use the command buffer as the first data buffer. 780*0Sstevel@tonic-gate */ 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate dbuf = cbuf; 783*0Sstevel@tonic-gate thisbuflen = cbuflen; 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate count = 0; 786*0Sstevel@tonic-gate while (nextbuflen != 0) { 787*0Sstevel@tonic-gate dbuflen = nextbuflen; 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate /* 790*0Sstevel@tonic-gate * Check whether the buffer we have is long enough for the 791*0Sstevel@tonic-gate * next lot of data. If it isn't, allocate a new one of 792*0Sstevel@tonic-gate * the appropriate length. 793*0Sstevel@tonic-gate */ 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate if (nextbuflen > thisbuflen) { 796*0Sstevel@tonic-gate if ((dbuf = realloc(dbuf, nextbuflen)) == NULL) { 797*0Sstevel@tonic-gate DBG0(DBG_ERR, 798*0Sstevel@tonic-gate "failed to allocate data buffer\n"); 799*0Sstevel@tonic-gate goto data_failed; 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate thisbuflen = nextbuflen; 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate /* 805*0Sstevel@tonic-gate * Set up an ioctl structure to point at the data buffer. 806*0Sstevel@tonic-gate */ 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate iioc.ii_buf = dbuf; 809*0Sstevel@tonic-gate iioc.ii_buflen = dbuflen; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate /* 812*0Sstevel@tonic-gate * Issue a data ioctl, passing the ioctl structure. 813*0Sstevel@tonic-gate */ 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate DBG2(DBG_IO, "data[%d]: length = %d\n", count, dbuflen); 816*0Sstevel@tonic-gate if ((rc = ioctl(fd, IPPCTL_DATA, &iioc)) < 0) { 817*0Sstevel@tonic-gate DBG0(DBG_ERR, "data ioctl failed\n"); 818*0Sstevel@tonic-gate goto data_failed; 819*0Sstevel@tonic-gate } 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * Get the length of the *next* data buffer, if there is 823*0Sstevel@tonic-gate * one. 824*0Sstevel@tonic-gate */ 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate nextbuflen = (size_t)rc; 827*0Sstevel@tonic-gate DBG1(DBG_IO, "nextbuflen = %d\n", nextbuflen); 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate /* 830*0Sstevel@tonic-gate * Unpack the nvlist that the current data buffer should 831*0Sstevel@tonic-gate * now contain. 832*0Sstevel@tonic-gate */ 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate if ((rc = nvlist_unpack(dbuf, dbuflen, &dnvlp, 0)) != 0) { 835*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to unpack nvlist\n"); 836*0Sstevel@tonic-gate errno = rc; 837*0Sstevel@tonic-gate goto data_failed; 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate /* 841*0Sstevel@tonic-gate * The first data buffer should contain the kernel function's 842*0Sstevel@tonic-gate * return code. Subsequent buffers contain nvlists which 843*0Sstevel@tonic-gate * should be passed to the given callback function. 844*0Sstevel@tonic-gate */ 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate if (count == 0) { 847*0Sstevel@tonic-gate if ((rc = nvlist_lookup_int32(dnvlp, IPPCTL_RC, 848*0Sstevel@tonic-gate &rval)) != 0) { 849*0Sstevel@tonic-gate DBG0(DBG_ERR, "failed to find return code\n"); 850*0Sstevel@tonic-gate nvlist_free(dnvlp); 851*0Sstevel@tonic-gate errno = rc; 852*0Sstevel@tonic-gate goto data_failed; 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate } else { 855*0Sstevel@tonic-gate if (fn != NULL) 856*0Sstevel@tonic-gate if (fn(dnvlp, arg) != 0) { 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate /* 859*0Sstevel@tonic-gate * The callback function returned 860*0Sstevel@tonic-gate * a non-zero value. Abort any further 861*0Sstevel@tonic-gate * data collection. 862*0Sstevel@tonic-gate */ 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate nvlist_free(dnvlp); 865*0Sstevel@tonic-gate free(dbuf); 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate /* 870*0Sstevel@tonic-gate * Free the nvlist now that we have extracted the return 871*0Sstevel@tonic-gate * code or called the callback function. 872*0Sstevel@tonic-gate */ 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate nvlist_free(dnvlp); 875*0Sstevel@tonic-gate dnvlp = NULL; 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate count++; 878*0Sstevel@tonic-gate } 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate /* 881*0Sstevel@tonic-gate * Free the data buffer as data collection is now complete. 882*0Sstevel@tonic-gate */ 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate free(dbuf); 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate /* 887*0Sstevel@tonic-gate * Close the control device. 888*0Sstevel@tonic-gate */ 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate (void) close(fd); 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate /* 893*0Sstevel@tonic-gate * If the kernel returned an error, we should return an error. 894*0Sstevel@tonic-gate * and set errno. 895*0Sstevel@tonic-gate */ 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate if (rval != 0) { 898*0Sstevel@tonic-gate DBG1(DBG_IO, "kernel return code = %d\n", rval); 899*0Sstevel@tonic-gate errno = rval; 900*0Sstevel@tonic-gate return (-1); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate return (0); 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate command_failed: 906*0Sstevel@tonic-gate free(cbuf); 907*0Sstevel@tonic-gate if (fd != -1) 908*0Sstevel@tonic-gate (void) close(fd); 909*0Sstevel@tonic-gate return (-1); 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate data_failed: 912*0Sstevel@tonic-gate if (dbuf != NULL) 913*0Sstevel@tonic-gate free(dbuf); 914*0Sstevel@tonic-gate (void) close(fd); 915*0Sstevel@tonic-gate return (-1); 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate #undef __FN__ 918