17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55e1c24c3Sss150715 * Common Development and Distribution License (the "License"). 65e1c24c3Sss150715 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*c7e4935fSss150715 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Data-Link Provider Interface (Version 2) 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #include <stdio.h> 327c478bd9Sstevel@tonic-gate #include <stdlib.h> 337c478bd9Sstevel@tonic-gate #include <string.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/stat.h> 367c478bd9Sstevel@tonic-gate #include <fcntl.h> 377c478bd9Sstevel@tonic-gate #include <unistd.h> 387c478bd9Sstevel@tonic-gate #include <poll.h> 397c478bd9Sstevel@tonic-gate #include <stropts.h> 407c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 42*c7e4935fSss150715 #include <alloca.h> 437c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 447c478bd9Sstevel@tonic-gate #include <ctype.h> 457c478bd9Sstevel@tonic-gate #include <libdlpi.h> 46*c7e4935fSss150715 #include <libintl.h> 47*c7e4935fSss150715 #include <libinetutil.h> 487c478bd9Sstevel@tonic-gate 49*c7e4935fSss150715 #include "libdlpi_impl.h" 507c478bd9Sstevel@tonic-gate 51*c7e4935fSss150715 static int i_dlpi_open(const char *, int *, uint_t); 52*c7e4935fSss150715 static int i_dlpi_style1_open(dlpi_impl_t *); 53*c7e4935fSss150715 static int i_dlpi_style2_open(dlpi_impl_t *); 54*c7e4935fSss150715 static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t); 55*c7e4935fSss150715 static int i_dlpi_remove_ppa(char *); 56*c7e4935fSss150715 static int i_dlpi_attach(dlpi_impl_t *); 57*c7e4935fSss150715 static void i_dlpi_passive(dlpi_impl_t *); 587c478bd9Sstevel@tonic-gate 59*c7e4935fSss150715 static int i_dlpi_strputmsg(int, const dlpi_msg_t *, const void *, size_t, int); 60*c7e4935fSss150715 static int i_dlpi_strgetmsg(int, int, dlpi_msg_t *, t_uscalar_t, t_uscalar_t, 61*c7e4935fSss150715 size_t, void *, size_t *, size_t *); 62*c7e4935fSss150715 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *, 63*c7e4935fSss150715 size_t, int); 647c478bd9Sstevel@tonic-gate 65*c7e4935fSss150715 static size_t i_dlpi_getprimsize(t_uscalar_t); 66*c7e4935fSss150715 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t); 67*c7e4935fSss150715 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t); 68*c7e4935fSss150715 static uint_t i_dlpi_buildsap(uint8_t *, uint_t); 69*c7e4935fSss150715 static void i_dlpi_writesap(void *, uint_t, uint_t); 70*c7e4935fSss150715 71*c7e4935fSss150715 int 72*c7e4935fSss150715 dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags) 73*c7e4935fSss150715 { 74*c7e4935fSss150715 int retval; 75*c7e4935fSss150715 int cnt; 76*c7e4935fSss150715 ifspec_t ifsp; 77*c7e4935fSss150715 dlpi_impl_t *dip; 78*c7e4935fSss150715 79*c7e4935fSss150715 /* 80*c7e4935fSss150715 * Validate linkname, fail if logical unit number (lun) is specified, 81*c7e4935fSss150715 * otherwise decompose the contents into ifsp. 82*c7e4935fSss150715 */ 83*c7e4935fSss150715 if (linkname == NULL || (strchr(linkname, ':') != NULL) || 84*c7e4935fSss150715 !ifparse_ifspec(linkname, &ifsp)) 85*c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 86*c7e4935fSss150715 87*c7e4935fSss150715 /* Allocate a new dlpi_impl_t. */ 88*c7e4935fSss150715 if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL) 89*c7e4935fSss150715 return (DL_SYSERR); 90*c7e4935fSss150715 91*c7e4935fSss150715 /* Fill in known/default libdlpi handle values. */ 92*c7e4935fSss150715 dip->dli_timeout = DLPI_DEF_TIMEOUT; 93*c7e4935fSss150715 dip->dli_ppa = ifsp.ifsp_ppa; 94*c7e4935fSss150715 dip->dli_mod_cnt = ifsp.ifsp_modcnt; 95*c7e4935fSss150715 dip->dli_oflags = flags; 96*c7e4935fSss150715 97*c7e4935fSss150715 for (cnt = 0; cnt != dip->dli_mod_cnt; cnt++) { 98*c7e4935fSss150715 (void) strlcpy(dip->dli_modlist[cnt], ifsp.ifsp_mods[cnt], 99*c7e4935fSss150715 DLPI_LINKNAME_MAX); 100*c7e4935fSss150715 } 101*c7e4935fSss150715 102*c7e4935fSss150715 /* Copy linkname provided to the function. */ 103*c7e4935fSss150715 if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >= 104*c7e4935fSss150715 sizeof (dip->dli_linkname)) { 105*c7e4935fSss150715 free(dip); 106*c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 107*c7e4935fSss150715 } 108*c7e4935fSss150715 109*c7e4935fSss150715 /* Copy provider name. */ 110*c7e4935fSss150715 (void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm, 111*c7e4935fSss150715 sizeof (dip->dli_provider)); 112*c7e4935fSss150715 113*c7e4935fSss150715 /* 114*c7e4935fSss150715 * Special case: DLPI_SERIAL flag is set to indicate a synchronous 115*c7e4935fSss150715 * serial line interface (see syncinit(1M), syncstat(1M), 116*c7e4935fSss150715 * syncloop(1M)), which is not a DLPI link. 117*c7e4935fSss150715 */ 118*c7e4935fSss150715 if (dip->dli_oflags & DLPI_SERIAL) { 119*c7e4935fSss150715 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) { 120*c7e4935fSss150715 free(dip); 121*c7e4935fSss150715 return (retval); 122*c7e4935fSss150715 } 123*c7e4935fSss150715 124*c7e4935fSss150715 *dhp = (dlpi_handle_t)dip; 125*c7e4935fSss150715 return (retval); 126*c7e4935fSss150715 } 127*c7e4935fSss150715 128*c7e4935fSss150715 if (i_dlpi_style1_open(dip) != DLPI_SUCCESS) { 129*c7e4935fSss150715 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) { 130*c7e4935fSss150715 free(dip); 131*c7e4935fSss150715 return (retval); 132*c7e4935fSss150715 } 133*c7e4935fSss150715 } 134*c7e4935fSss150715 135*c7e4935fSss150715 if (dip->dli_oflags & DLPI_PASSIVE) 136*c7e4935fSss150715 i_dlpi_passive(dip); 137*c7e4935fSss150715 138*c7e4935fSss150715 if ((dip->dli_oflags & DLPI_RAW) && 139*c7e4935fSss150715 ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) { 140*c7e4935fSss150715 dlpi_close((dlpi_handle_t)dip); 141*c7e4935fSss150715 return (DLPI_ERAWNOTSUP); 142*c7e4935fSss150715 } 143*c7e4935fSss150715 144*c7e4935fSss150715 /* 145*c7e4935fSss150715 * We intentionally do not care if this request fails, as this 146*c7e4935fSss150715 * indicates the underlying DLPI device does not support Native mode 147*c7e4935fSss150715 * (pre-GLDV3 device drivers). 148*c7e4935fSss150715 */ 149*c7e4935fSss150715 if (dip->dli_oflags & DLPI_NATIVE) { 150*c7e4935fSss150715 if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0) 151*c7e4935fSss150715 dip->dli_mactype = retval; 152*c7e4935fSss150715 } 153*c7e4935fSss150715 154*c7e4935fSss150715 *dhp = (dlpi_handle_t)dip; 155*c7e4935fSss150715 return (DLPI_SUCCESS); 156*c7e4935fSss150715 } 157*c7e4935fSss150715 158*c7e4935fSss150715 void 159*c7e4935fSss150715 dlpi_close(dlpi_handle_t dh) 160*c7e4935fSss150715 { 161*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 162*c7e4935fSss150715 163*c7e4935fSss150715 if (dip != NULL) { 164*c7e4935fSss150715 (void) close(dip->dli_fd); 165*c7e4935fSss150715 free(dip); 166*c7e4935fSss150715 } 167*c7e4935fSss150715 } 168*c7e4935fSss150715 169*c7e4935fSss150715 /* 170*c7e4935fSss150715 * NOTE: The opt argument must be zero and is reserved for future use to extend 171*c7e4935fSss150715 * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)). 172*c7e4935fSss150715 */ 173*c7e4935fSss150715 int 174*c7e4935fSss150715 dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt) 175*c7e4935fSss150715 { 176*c7e4935fSss150715 int retval; 177*c7e4935fSss150715 dlpi_msg_t req, ack; 178*c7e4935fSss150715 dl_info_ack_t *infoackp; 179*c7e4935fSss150715 uint8_t *sapp, *addrp; 180*c7e4935fSss150715 caddr_t ackendp, datap; 181*c7e4935fSss150715 t_uscalar_t dataoff, datalen; 182*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 183*c7e4935fSss150715 184*c7e4935fSss150715 if (dip == NULL) 185*c7e4935fSss150715 return (DLPI_EINHANDLE); 186*c7e4935fSss150715 187*c7e4935fSss150715 if (infop == NULL || opt != 0) 188*c7e4935fSss150715 return (DLPI_EINVAL); 189*c7e4935fSss150715 190*c7e4935fSss150715 (void) memset(infop, 0, sizeof (dlpi_info_t)); 191*c7e4935fSss150715 192*c7e4935fSss150715 /* Set QoS range parameters to default unsupported value. */ 193*c7e4935fSss150715 infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN; 194*c7e4935fSss150715 infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN; 195*c7e4935fSss150715 infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN; 196*c7e4935fSss150715 infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN; 197*c7e4935fSss150715 infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN; 198*c7e4935fSss150715 infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN; 199*c7e4935fSss150715 infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN; 200*c7e4935fSss150715 infop->di_qos_range.dl_residual_error = DL_UNKNOWN; 201*c7e4935fSss150715 202*c7e4935fSss150715 /* Set QoS parameters to default unsupported value. */ 203*c7e4935fSss150715 infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN; 204*c7e4935fSss150715 infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN; 205*c7e4935fSss150715 infop->di_qos_sel.dl_priority = DL_UNKNOWN; 206*c7e4935fSss150715 infop->di_qos_sel.dl_protection = DL_UNKNOWN; 207*c7e4935fSss150715 infop->di_qos_sel.dl_residual_error = DL_UNKNOWN; 208*c7e4935fSss150715 209*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_INFO_REQ); 210*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_INFO_ACK); 211*c7e4935fSss150715 212*c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI); 213*c7e4935fSss150715 if (retval != DLPI_SUCCESS) 214*c7e4935fSss150715 return (retval); 215*c7e4935fSss150715 216*c7e4935fSss150715 infoackp = &(ack.dlm_msg->info_ack); 217*c7e4935fSss150715 if (infoackp->dl_version != DL_VERSION_2) 218*c7e4935fSss150715 return (DLPI_EVERNOTSUP); 219*c7e4935fSss150715 220*c7e4935fSss150715 if (infoackp->dl_service_mode != DL_CLDLS) 221*c7e4935fSss150715 return (DLPI_EMODENOTSUP); 222*c7e4935fSss150715 223*c7e4935fSss150715 dip->dli_style = infoackp->dl_provider_style; 224*c7e4935fSss150715 dip->dli_mactype = infoackp->dl_mac_type; 225*c7e4935fSss150715 226*c7e4935fSss150715 ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz; 227*c7e4935fSss150715 228*c7e4935fSss150715 /* Check and save QoS selection information, if any. */ 229*c7e4935fSss150715 datalen = infoackp->dl_qos_length; 230*c7e4935fSss150715 dataoff = infoackp->dl_qos_offset; 231*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 232*c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 233*c7e4935fSss150715 if (datalen > sizeof (dl_qos_cl_sel1_t) || 234*c7e4935fSss150715 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 235*c7e4935fSss150715 return (DLPI_EBADMSG); 236*c7e4935fSss150715 237*c7e4935fSss150715 (void) memcpy(&infop->di_qos_sel, datap, datalen); 238*c7e4935fSss150715 if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1) 239*c7e4935fSss150715 return (DLPI_EMODENOTSUP); 240*c7e4935fSss150715 } 241*c7e4935fSss150715 242*c7e4935fSss150715 /* Check and save QoS range information, if any. */ 243*c7e4935fSss150715 datalen = infoackp->dl_qos_range_length; 244*c7e4935fSss150715 dataoff = infoackp->dl_qos_range_offset; 245*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 246*c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 247*c7e4935fSss150715 if (datalen > sizeof (dl_qos_cl_range1_t) || 248*c7e4935fSss150715 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 249*c7e4935fSss150715 return (DLPI_EBADMSG); 250*c7e4935fSss150715 251*c7e4935fSss150715 (void) memcpy(&infop->di_qos_range, datap, datalen); 252*c7e4935fSss150715 if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1) 253*c7e4935fSss150715 return (DLPI_EMODENOTSUP); 254*c7e4935fSss150715 } 255*c7e4935fSss150715 256*c7e4935fSss150715 /* Check and save physical address and SAP information. */ 257*c7e4935fSss150715 dip->dli_saplen = abs(infoackp->dl_sap_length); 258*c7e4935fSss150715 dip->dli_sapbefore = (infoackp->dl_sap_length > 0); 259*c7e4935fSss150715 infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen; 260*c7e4935fSss150715 261*c7e4935fSss150715 if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX || 262*c7e4935fSss150715 dip->dli_saplen > DLPI_SAPLEN_MAX) 263*c7e4935fSss150715 return (DL_BADADDR); 264*c7e4935fSss150715 265*c7e4935fSss150715 dataoff = infoackp->dl_addr_offset; 266*c7e4935fSss150715 datalen = infoackp->dl_addr_length; 267*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 268*c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 269*c7e4935fSss150715 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 270*c7e4935fSss150715 return (DLPI_EBADMSG); 271*c7e4935fSss150715 272*c7e4935fSss150715 sapp = addrp = (uint8_t *)datap; 273*c7e4935fSss150715 if (dip->dli_sapbefore) 274*c7e4935fSss150715 addrp += dip->dli_saplen; 275*c7e4935fSss150715 else 276*c7e4935fSss150715 sapp += infop->di_physaddrlen; 277*c7e4935fSss150715 278*c7e4935fSss150715 (void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen); 279*c7e4935fSss150715 infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen); 280*c7e4935fSss150715 } 281*c7e4935fSss150715 282*c7e4935fSss150715 /* Check and save broadcast address information, if any. */ 283*c7e4935fSss150715 datalen = infoackp->dl_brdcst_addr_length; 284*c7e4935fSss150715 dataoff = infoackp->dl_brdcst_addr_offset; 285*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 286*c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 287*c7e4935fSss150715 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 288*c7e4935fSss150715 return (DLPI_EBADMSG); 289*c7e4935fSss150715 if (datalen != infop->di_physaddrlen) 290*c7e4935fSss150715 return (DL_BADADDR); 291*c7e4935fSss150715 292*c7e4935fSss150715 infop->di_bcastaddrlen = datalen; 293*c7e4935fSss150715 (void) memcpy(infop->di_bcastaddr, datap, datalen); 294*c7e4935fSss150715 } 295*c7e4935fSss150715 296*c7e4935fSss150715 infop->di_max_sdu = infoackp->dl_max_sdu; 297*c7e4935fSss150715 infop->di_min_sdu = infoackp->dl_min_sdu; 298*c7e4935fSss150715 infop->di_state = infoackp->dl_current_state; 299*c7e4935fSss150715 infop->di_mactype = infoackp->dl_mac_type; 300*c7e4935fSss150715 301*c7e4935fSss150715 /* Information retrieved from the handle. */ 302*c7e4935fSss150715 (void) strlcpy(infop->di_linkname, dip->dli_linkname, 303*c7e4935fSss150715 sizeof (infop->di_linkname)); 304*c7e4935fSss150715 infop->di_timeout = dip->dli_timeout; 305*c7e4935fSss150715 306*c7e4935fSss150715 return (DLPI_SUCCESS); 307*c7e4935fSss150715 } 308*c7e4935fSss150715 309*c7e4935fSss150715 /* 310*c7e4935fSss150715 * This function parses 'linkname' and stores the 'provider' name and 'PPA'. 311*c7e4935fSss150715 */ 312*c7e4935fSss150715 int 313*c7e4935fSss150715 dlpi_parselink(const char *linkname, char *provider, uint_t *ppa) 314*c7e4935fSss150715 { 315*c7e4935fSss150715 ifspec_t ifsp; 316*c7e4935fSss150715 317*c7e4935fSss150715 if (linkname == NULL || !ifparse_ifspec(linkname, &ifsp)) 318*c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 319*c7e4935fSss150715 320*c7e4935fSss150715 if (provider != NULL) 321*c7e4935fSss150715 (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 322*c7e4935fSss150715 323*c7e4935fSss150715 if (ppa != NULL) 324*c7e4935fSss150715 *ppa = ifsp.ifsp_ppa; 325*c7e4935fSss150715 326*c7e4935fSss150715 return (DLPI_SUCCESS); 327*c7e4935fSss150715 } 328*c7e4935fSss150715 329*c7e4935fSss150715 /* 330*c7e4935fSss150715 * This function takes a provider name and a PPA and stores a full linkname 331*c7e4935fSss150715 * as 'linkname'. If 'provider' already is a full linkname 'provider' name 332*c7e4935fSss150715 * is stored in 'linkname'. 333*c7e4935fSss150715 */ 334*c7e4935fSss150715 int 335*c7e4935fSss150715 dlpi_makelink(char *linkname, const char *provider, uint_t ppa) 336*c7e4935fSss150715 { 337*c7e4935fSss150715 int provlen = strlen(provider); 338*c7e4935fSss150715 339*c7e4935fSss150715 if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX) 340*c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 341*c7e4935fSss150715 342*c7e4935fSss150715 if (!isdigit(provider[provlen - 1])) { 343*c7e4935fSss150715 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider, 344*c7e4935fSss150715 ppa); 345*c7e4935fSss150715 } else { 346*c7e4935fSss150715 (void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX); 347*c7e4935fSss150715 } 348*c7e4935fSss150715 349*c7e4935fSss150715 return (DLPI_SUCCESS); 350*c7e4935fSss150715 } 351*c7e4935fSss150715 352*c7e4935fSss150715 int 353*c7e4935fSss150715 dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap) 354*c7e4935fSss150715 { 355*c7e4935fSss150715 int retval; 356*c7e4935fSss150715 dlpi_msg_t req, ack; 357*c7e4935fSss150715 dl_bind_req_t *bindreqp; 358*c7e4935fSss150715 dl_bind_ack_t *bindackp; 359*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 360*c7e4935fSss150715 361*c7e4935fSss150715 if (dip == NULL) 362*c7e4935fSss150715 return (DLPI_EINHANDLE); 363*c7e4935fSss150715 364*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_BIND_REQ); 365*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_BIND_ACK); 366*c7e4935fSss150715 bindreqp = &(req.dlm_msg->bind_req); 367*c7e4935fSss150715 368*c7e4935fSss150715 /* 369*c7e4935fSss150715 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on 370*c7e4935fSss150715 * other interface types (SAP 0 has special significance on token ring). 371*c7e4935fSss150715 */ 372*c7e4935fSss150715 if (sap == DLPI_ANY_SAP) 373*c7e4935fSss150715 bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0); 374*c7e4935fSss150715 else 375*c7e4935fSss150715 bindreqp->dl_sap = sap; 376*c7e4935fSss150715 377*c7e4935fSss150715 bindreqp->dl_service_mode = DL_CLDLS; 378*c7e4935fSss150715 bindreqp->dl_conn_mgmt = 0; 379*c7e4935fSss150715 bindreqp->dl_max_conind = 0; 380*c7e4935fSss150715 bindreqp->dl_xidtest_flg = 0; 381*c7e4935fSss150715 382*c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0); 383*c7e4935fSss150715 if (retval != DLPI_SUCCESS) 384*c7e4935fSss150715 return (retval); 385*c7e4935fSss150715 386*c7e4935fSss150715 bindackp = &(ack.dlm_msg->bind_ack); 387*c7e4935fSss150715 /* 388*c7e4935fSss150715 * Received a DLPI_BIND_ACK, now verify that the bound SAP 389*c7e4935fSss150715 * is equal to the SAP requested. Some DLPI MAC type may bind 390*c7e4935fSss150715 * to a different SAP than requested, in this case 'boundsap' 391*c7e4935fSss150715 * returns the actual bound SAP. For the case where 'boundsap' 392*c7e4935fSss150715 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails. 393*c7e4935fSss150715 */ 394*c7e4935fSss150715 if (boundsap != NULL) { 395*c7e4935fSss150715 *boundsap = bindackp->dl_sap; 396*c7e4935fSss150715 } else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) { 397*c7e4935fSss150715 if (dlpi_unbind(dh) != DLPI_SUCCESS) 398*c7e4935fSss150715 return (DLPI_FAILURE); 399*c7e4935fSss150715 else 400*c7e4935fSss150715 return (DLPI_EUNAVAILSAP); 401*c7e4935fSss150715 } 402*c7e4935fSss150715 403*c7e4935fSss150715 dip->dli_sap = bindackp->dl_sap; /* save sap value in handle */ 404*c7e4935fSss150715 return (DLPI_SUCCESS); 405*c7e4935fSss150715 } 406*c7e4935fSss150715 407*c7e4935fSss150715 int 408*c7e4935fSss150715 dlpi_unbind(dlpi_handle_t dh) 409*c7e4935fSss150715 { 410*c7e4935fSss150715 dlpi_msg_t req, ack; 411*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 412*c7e4935fSss150715 413*c7e4935fSss150715 if (dip == NULL) 414*c7e4935fSss150715 return (DLPI_EINHANDLE); 415*c7e4935fSss150715 416*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_UNBIND_REQ); 417*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 418*c7e4935fSss150715 419*c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 420*c7e4935fSss150715 } 421*c7e4935fSss150715 422*c7e4935fSss150715 /* 423*c7e4935fSss150715 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and 424*c7e4935fSss150715 * based on the "op" value, multicast address is enabled/disabled. 425*c7e4935fSss150715 */ 426*c7e4935fSss150715 static int 427*c7e4935fSss150715 i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp, 428*c7e4935fSss150715 size_t addrlen) 429*c7e4935fSss150715 { 430*c7e4935fSss150715 dlpi_msg_t req, ack; 431*c7e4935fSss150715 dl_enabmulti_req_t *multireqp; 432*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 433*c7e4935fSss150715 434*c7e4935fSss150715 if (dip == NULL) 435*c7e4935fSss150715 return (DLPI_EINHANDLE); 436*c7e4935fSss150715 437*c7e4935fSss150715 if (addrlen > DLPI_PHYSADDR_MAX) 438*c7e4935fSss150715 return (DLPI_EINVAL); 439*c7e4935fSss150715 440*c7e4935fSss150715 DLPI_MSG_CREATE(req, op); 441*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 442*c7e4935fSss150715 443*c7e4935fSss150715 multireqp = &(req.dlm_msg->enabmulti_req); 444*c7e4935fSss150715 multireqp->dl_addr_length = addrlen; 445*c7e4935fSss150715 multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t); 446*c7e4935fSss150715 (void) memcpy(&multireqp[1], addrp, addrlen); 447*c7e4935fSss150715 448*c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 449*c7e4935fSss150715 } 450*c7e4935fSss150715 451*c7e4935fSss150715 int 452*c7e4935fSss150715 dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen) 453*c7e4935fSss150715 { 454*c7e4935fSss150715 return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen)); 455*c7e4935fSss150715 } 456*c7e4935fSss150715 457*c7e4935fSss150715 int 458*c7e4935fSss150715 dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen) 459*c7e4935fSss150715 { 460*c7e4935fSss150715 return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen)); 461*c7e4935fSss150715 } 462*c7e4935fSss150715 463*c7e4935fSss150715 /* 464*c7e4935fSss150715 * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based 465*c7e4935fSss150715 * on the value of 'op', promiscuous mode is turned on/off at the specified 466*c7e4935fSss150715 * 'level'. 467*c7e4935fSss150715 */ 468*c7e4935fSss150715 static int 469*c7e4935fSss150715 i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level) 470*c7e4935fSss150715 { 471*c7e4935fSss150715 dlpi_msg_t req, ack; 472*c7e4935fSss150715 dl_promiscon_req_t *promiscreqp; 473*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 474*c7e4935fSss150715 475*c7e4935fSss150715 if (dip == NULL) 476*c7e4935fSss150715 return (DLPI_EINHANDLE); 477*c7e4935fSss150715 478*c7e4935fSss150715 DLPI_MSG_CREATE(req, op); 479*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 480*c7e4935fSss150715 481*c7e4935fSss150715 promiscreqp = &(req.dlm_msg->promiscon_req); 482*c7e4935fSss150715 promiscreqp->dl_level = level; 483*c7e4935fSss150715 484*c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 485*c7e4935fSss150715 } 486*c7e4935fSss150715 487*c7e4935fSss150715 int 488*c7e4935fSss150715 dlpi_promiscon(dlpi_handle_t dh, uint_t level) 489*c7e4935fSss150715 { 490*c7e4935fSss150715 return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level)); 491*c7e4935fSss150715 } 492*c7e4935fSss150715 493*c7e4935fSss150715 int 494*c7e4935fSss150715 dlpi_promiscoff(dlpi_handle_t dh, uint_t level) 495*c7e4935fSss150715 { 496*c7e4935fSss150715 return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level)); 497*c7e4935fSss150715 } 498*c7e4935fSss150715 499*c7e4935fSss150715 int 500*c7e4935fSss150715 dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp) 501*c7e4935fSss150715 { 502*c7e4935fSss150715 int retval; 503*c7e4935fSss150715 dlpi_msg_t req, ack; 504*c7e4935fSss150715 dl_phys_addr_req_t *physreqp; 505*c7e4935fSss150715 dl_phys_addr_ack_t *physackp; 506*c7e4935fSss150715 t_uscalar_t dataoff, datalen; 507*c7e4935fSss150715 caddr_t datap, physackendp; 508*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 509*c7e4935fSss150715 510*c7e4935fSss150715 if (dip == NULL) 511*c7e4935fSss150715 return (DLPI_EINHANDLE); 512*c7e4935fSss150715 513*c7e4935fSss150715 if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX) 514*c7e4935fSss150715 return (DLPI_EINVAL); 515*c7e4935fSss150715 516*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ); 517*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK); 518*c7e4935fSss150715 519*c7e4935fSss150715 physreqp = &(req.dlm_msg->physaddr_req); 520*c7e4935fSss150715 physreqp->dl_addr_type = type; 521*c7e4935fSss150715 522*c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0); 523*c7e4935fSss150715 if (retval != DLPI_SUCCESS) 524*c7e4935fSss150715 return (retval); 525*c7e4935fSss150715 526*c7e4935fSss150715 /* Received DL_PHYS_ADDR_ACK, store the physical address and length. */ 527*c7e4935fSss150715 physackp = &(ack.dlm_msg->physaddr_ack); 528*c7e4935fSss150715 physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz; 529*c7e4935fSss150715 dataoff = physackp->dl_addr_offset; 530*c7e4935fSss150715 datalen = physackp->dl_addr_length; 531*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 532*c7e4935fSss150715 datap = (caddr_t)physackp + dataoff; 533*c7e4935fSss150715 if (datalen > DLPI_PHYSADDR_MAX) 534*c7e4935fSss150715 return (DL_BADADDR); 535*c7e4935fSss150715 if (dataoff < DL_PHYS_ADDR_ACK_SIZE || 536*c7e4935fSss150715 datap + datalen > physackendp) 537*c7e4935fSss150715 return (DLPI_EBADMSG); 538*c7e4935fSss150715 539*c7e4935fSss150715 *addrlenp = physackp->dl_addr_length; 540*c7e4935fSss150715 (void) memcpy(addrp, datap, datalen); 541*c7e4935fSss150715 } else { 542*c7e4935fSss150715 *addrlenp = datalen; 543*c7e4935fSss150715 } 544*c7e4935fSss150715 545*c7e4935fSss150715 return (DLPI_SUCCESS); 546*c7e4935fSss150715 } 547*c7e4935fSss150715 548*c7e4935fSss150715 int 549*c7e4935fSss150715 dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp, 550*c7e4935fSss150715 size_t addrlen) 551*c7e4935fSss150715 { 552*c7e4935fSss150715 dlpi_msg_t req, ack; 553*c7e4935fSss150715 dl_set_phys_addr_req_t *setphysreqp; 554*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 555*c7e4935fSss150715 556*c7e4935fSss150715 if (dip == NULL) 557*c7e4935fSss150715 return (DLPI_EINHANDLE); 558*c7e4935fSss150715 559*c7e4935fSss150715 if (addrp == NULL || type != DL_CURR_PHYS_ADDR || 560*c7e4935fSss150715 addrlen > DLPI_PHYSADDR_MAX) 561*c7e4935fSss150715 return (DLPI_EINVAL); 562*c7e4935fSss150715 563*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ); 564*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 565*c7e4935fSss150715 566*c7e4935fSss150715 setphysreqp = &(req.dlm_msg->set_physaddr_req); 567*c7e4935fSss150715 setphysreqp->dl_addr_length = addrlen; 568*c7e4935fSss150715 setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); 569*c7e4935fSss150715 (void) memcpy(&setphysreqp[1], addrp, addrlen); 570*c7e4935fSss150715 571*c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 572*c7e4935fSss150715 } 573*c7e4935fSss150715 574*c7e4935fSss150715 int 575*c7e4935fSss150715 dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen, 576*c7e4935fSss150715 const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp) 577*c7e4935fSss150715 { 578*c7e4935fSss150715 dlpi_msg_t req; 579*c7e4935fSss150715 dl_unitdata_req_t *udatareqp; 580*c7e4935fSss150715 uint_t sap; 581*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 582*c7e4935fSss150715 583*c7e4935fSss150715 if (dip == NULL) 584*c7e4935fSss150715 return (DLPI_EINHANDLE); 585*c7e4935fSss150715 586*c7e4935fSss150715 if (dip->dli_oflags & DLPI_RAW) 587*c7e4935fSss150715 return (i_dlpi_strputmsg(dip->dli_fd, NULL, msgbuf, msglen, 0)); 588*c7e4935fSss150715 589*c7e4935fSss150715 if (daddrp == NULL || daddrlen > DLPI_PHYSADDR_MAX) 590*c7e4935fSss150715 return (DLPI_EINVAL); 591*c7e4935fSss150715 592*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_UNITDATA_REQ); 593*c7e4935fSss150715 udatareqp = &(req.dlm_msg->unitdata_req); 594*c7e4935fSss150715 595*c7e4935fSss150715 /* Set priority to default priority range. */ 596*c7e4935fSss150715 udatareqp->dl_priority.dl_min = 0; 597*c7e4935fSss150715 udatareqp->dl_priority.dl_max = 0; 598*c7e4935fSss150715 599*c7e4935fSss150715 /* Use SAP value if specified otherwise use bound SAP value. */ 600*c7e4935fSss150715 if (sendp != NULL) { 601*c7e4935fSss150715 sap = sendp->dsi_sap; 602*c7e4935fSss150715 if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE) 603*c7e4935fSss150715 udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min; 604*c7e4935fSss150715 if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE) 605*c7e4935fSss150715 udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max; 606*c7e4935fSss150715 } else { 607*c7e4935fSss150715 sap = dip->dli_sap; 608*c7e4935fSss150715 } 609*c7e4935fSss150715 610*c7e4935fSss150715 udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen; 611*c7e4935fSss150715 udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE; 612*c7e4935fSss150715 613*c7e4935fSss150715 /* 614*c7e4935fSss150715 * Since `daddrp' only has the link-layer destination address, 615*c7e4935fSss150715 * we must prepend or append the SAP (according to dli_sapbefore) 616*c7e4935fSss150715 * to make a full DLPI address. 617*c7e4935fSss150715 */ 618*c7e4935fSss150715 if (dip->dli_sapbefore) { 619*c7e4935fSss150715 i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen); 620*c7e4935fSss150715 (void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen, 621*c7e4935fSss150715 daddrp, daddrlen); 622*c7e4935fSss150715 } else { 623*c7e4935fSss150715 (void) memcpy(&udatareqp[1], daddrp, daddrlen); 624*c7e4935fSss150715 i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap, 625*c7e4935fSss150715 dip->dli_saplen); 626*c7e4935fSss150715 } 627*c7e4935fSss150715 628*c7e4935fSss150715 return (i_dlpi_strputmsg(dip->dli_fd, &req, msgbuf, msglen, 0)); 629*c7e4935fSss150715 } 630*c7e4935fSss150715 631*c7e4935fSss150715 int 632*c7e4935fSss150715 dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf, 633*c7e4935fSss150715 size_t *msglenp, int msec, dlpi_recvinfo_t *recvp) 634*c7e4935fSss150715 { 635*c7e4935fSss150715 int retval; 636*c7e4935fSss150715 dlpi_msg_t ind; 637*c7e4935fSss150715 size_t totmsglen; 638*c7e4935fSss150715 dl_unitdata_ind_t *udatap; 639*c7e4935fSss150715 t_uscalar_t dataoff, datalen; 640*c7e4935fSss150715 caddr_t datap, indendp; 641*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 642*c7e4935fSss150715 643*c7e4935fSss150715 if (dip == NULL) 644*c7e4935fSss150715 return (DLPI_EINHANDLE); 645*c7e4935fSss150715 /* 646*c7e4935fSss150715 * If handle is in raw mode ignore everything except total message 647*c7e4935fSss150715 * length. 648*c7e4935fSss150715 */ 649*c7e4935fSss150715 if (dip->dli_oflags & DLPI_RAW) { 650*c7e4935fSss150715 retval = i_dlpi_strgetmsg(dip->dli_fd, msec, NULL, 0, 0, 0, 651*c7e4935fSss150715 msgbuf, msglenp, &totmsglen); 652*c7e4935fSss150715 653*c7e4935fSss150715 if (retval == DLPI_SUCCESS && recvp != NULL) 654*c7e4935fSss150715 recvp->dri_totmsglen = totmsglen; 655*c7e4935fSss150715 return (retval); 656*c7e4935fSss150715 } 657*c7e4935fSss150715 658*c7e4935fSss150715 DLPI_MSG_CREATE(ind, DL_UNITDATA_IND); 659*c7e4935fSss150715 udatap = &(ind.dlm_msg->unitdata_ind); 660*c7e4935fSss150715 indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz; 661*c7e4935fSss150715 662*c7e4935fSss150715 if ((retval = i_dlpi_strgetmsg(dip->dli_fd, msec, &ind, 663*c7e4935fSss150715 DL_UNITDATA_IND, DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, 664*c7e4935fSss150715 msgbuf, msglenp, &totmsglen)) != DLPI_SUCCESS) 665*c7e4935fSss150715 return (retval); 666*c7e4935fSss150715 667*c7e4935fSss150715 /* 668*c7e4935fSss150715 * If DLPI link provides source address, store source address in 669*c7e4935fSss150715 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0. 670*c7e4935fSss150715 */ 671*c7e4935fSss150715 if (saddrp != NULL && saddrlenp != NULL) { 672*c7e4935fSss150715 if (*saddrlenp < DLPI_PHYSADDR_MAX) 673*c7e4935fSss150715 return (DLPI_EINVAL); 674*c7e4935fSss150715 675*c7e4935fSss150715 dataoff = udatap->dl_src_addr_offset; 676*c7e4935fSss150715 datalen = udatap->dl_src_addr_length; 677*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 678*c7e4935fSss150715 datap = (caddr_t)udatap + dataoff; 679*c7e4935fSss150715 if (dataoff < DL_UNITDATA_IND_SIZE || 680*c7e4935fSss150715 datap + datalen > indendp) 681*c7e4935fSss150715 return (DLPI_EBADMSG); 682*c7e4935fSss150715 683*c7e4935fSss150715 *saddrlenp = datalen - dip->dli_saplen; 684*c7e4935fSss150715 if (*saddrlenp > DLPI_PHYSADDR_MAX) 685*c7e4935fSss150715 return (DL_BADADDR); 686*c7e4935fSss150715 687*c7e4935fSss150715 if (dip->dli_sapbefore) 688*c7e4935fSss150715 datap += dip->dli_saplen; 689*c7e4935fSss150715 (void) memcpy(saddrp, datap, *saddrlenp); 690*c7e4935fSss150715 } else { 691*c7e4935fSss150715 *saddrlenp = 0; 692*c7e4935fSss150715 } 693*c7e4935fSss150715 } 694*c7e4935fSss150715 695*c7e4935fSss150715 /* 696*c7e4935fSss150715 * If destination address requested, check and save destination 697*c7e4935fSss150715 * address, if any. 698*c7e4935fSss150715 */ 699*c7e4935fSss150715 if (recvp != NULL) { 700*c7e4935fSss150715 dataoff = udatap->dl_dest_addr_offset; 701*c7e4935fSss150715 datalen = udatap->dl_dest_addr_length; 702*c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 703*c7e4935fSss150715 datap = (caddr_t)udatap + dataoff; 704*c7e4935fSss150715 if (dataoff < DL_UNITDATA_IND_SIZE || 705*c7e4935fSss150715 datap + datalen > indendp) 706*c7e4935fSss150715 return (DLPI_EBADMSG); 707*c7e4935fSss150715 708*c7e4935fSss150715 recvp->dri_destaddrlen = datalen - dip->dli_saplen; 709*c7e4935fSss150715 if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX) 710*c7e4935fSss150715 return (DL_BADADDR); 711*c7e4935fSss150715 712*c7e4935fSss150715 if (dip->dli_sapbefore) 713*c7e4935fSss150715 datap += dip->dli_saplen; 714*c7e4935fSss150715 (void) memcpy(recvp->dri_destaddr, datap, 715*c7e4935fSss150715 recvp->dri_destaddrlen); 716*c7e4935fSss150715 } else { 717*c7e4935fSss150715 recvp->dri_destaddrlen = 0; 718*c7e4935fSss150715 } 719*c7e4935fSss150715 720*c7e4935fSss150715 recvp->dri_dstaddrtype = udatap->dl_group_address; 721*c7e4935fSss150715 recvp->dri_totmsglen = totmsglen; 722*c7e4935fSss150715 } 723*c7e4935fSss150715 724*c7e4935fSss150715 return (DLPI_SUCCESS); 725*c7e4935fSss150715 } 726*c7e4935fSss150715 727*c7e4935fSss150715 int 728*c7e4935fSss150715 dlpi_fd(dlpi_handle_t dh) 729*c7e4935fSss150715 { 730*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 731*c7e4935fSss150715 732*c7e4935fSss150715 return (dip != NULL ? dip->dli_fd : -1); 733*c7e4935fSss150715 } 734*c7e4935fSss150715 735*c7e4935fSss150715 int 736*c7e4935fSss150715 dlpi_set_timeout(dlpi_handle_t dh, int sec) 737*c7e4935fSss150715 { 738*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 739*c7e4935fSss150715 740*c7e4935fSss150715 if (dip == NULL) 741*c7e4935fSss150715 return (DLPI_EINHANDLE); 742*c7e4935fSss150715 743*c7e4935fSss150715 dip->dli_timeout = sec; 744*c7e4935fSss150715 return (DLPI_SUCCESS); 745*c7e4935fSss150715 } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate const char * 748*c7e4935fSss150715 dlpi_linkname(dlpi_handle_t dh) 7497c478bd9Sstevel@tonic-gate { 750*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 7517c478bd9Sstevel@tonic-gate 752*c7e4935fSss150715 return (dip != NULL ? dip->dli_linkname : NULL); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 755*c7e4935fSss150715 /* 756*c7e4935fSss150715 * Returns DLPI style stored in the handle. 757*c7e4935fSss150715 * Note: This function is used for test purposes only. Do not remove without 758*c7e4935fSss150715 * fixing the DLPI testsuite. 759*c7e4935fSss150715 */ 760*c7e4935fSss150715 uint_t 761*c7e4935fSss150715 dlpi_style(dlpi_handle_t dh) 7627c478bd9Sstevel@tonic-gate { 763*c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 7647c478bd9Sstevel@tonic-gate 765*c7e4935fSss150715 return (dip->dli_style); 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 768*c7e4935fSss150715 /* 769*c7e4935fSss150715 * This function attempts to open linkname under the following namespaces: 770*c7e4935fSss150715 * - /dev 771*c7e4935fSss150715 * - /devices 772*c7e4935fSss150715 * If open doesn't succeed and link doesn't exist (ENOENT), this function 773*c7e4935fSss150715 * returns DLPI_ENOLINK, otherwise returns DL_SYSERR. 774*c7e4935fSss150715 */ 7757c478bd9Sstevel@tonic-gate static int 776*c7e4935fSss150715 i_dlpi_open(const char *provider, int *fd, uint_t flags) 7777c478bd9Sstevel@tonic-gate { 778*c7e4935fSss150715 char path[MAXPATHLEN]; 779*c7e4935fSss150715 int oflags; 780*c7e4935fSss150715 781*c7e4935fSss150715 oflags = O_RDWR; 782*c7e4935fSss150715 if (flags & DLPI_EXCL) 783*c7e4935fSss150715 oflags |= O_EXCL; 784*c7e4935fSss150715 785*c7e4935fSss150715 (void) snprintf(path, sizeof (path), "/dev/%s", provider); 786*c7e4935fSss150715 787*c7e4935fSss150715 if ((*fd = open(path, oflags)) != -1) 788*c7e4935fSss150715 return (DLPI_SUCCESS); 789*c7e4935fSss150715 790*c7e4935fSss150715 /* 791*c7e4935fSss150715 * On diskless boot, it's possible the /dev links have not yet 792*c7e4935fSss150715 * been created; fallback to /devices. When /dev links are 793*c7e4935fSss150715 * created on demand, this code can be removed. 794*c7e4935fSss150715 */ 795*c7e4935fSss150715 (void) snprintf(path, sizeof (path), "/devices/pseudo/clone@0:%s", 796*c7e4935fSss150715 provider); 797*c7e4935fSss150715 798*c7e4935fSss150715 if ((*fd = open(path, oflags)) != -1) 799*c7e4935fSss150715 return (DLPI_SUCCESS); 800*c7e4935fSss150715 801*c7e4935fSss150715 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR); 802*c7e4935fSss150715 } 803*c7e4935fSss150715 804*c7e4935fSss150715 /* 805*c7e4935fSss150715 * Open a style 1 link. PPA is implicitly attached. 806*c7e4935fSss150715 */ 807*c7e4935fSss150715 static int 808*c7e4935fSss150715 i_dlpi_style1_open(dlpi_impl_t *dip) 809*c7e4935fSss150715 { 810*c7e4935fSss150715 int retval, save_errno; 811*c7e4935fSss150715 int fd; 812*c7e4935fSss150715 813*c7e4935fSss150715 /* 814*c7e4935fSss150715 * In order to support open of syntax like device[.module[.module...]] 815*c7e4935fSss150715 * where modules need to be pushed onto the device stream, open only 816*c7e4935fSss150715 * device name, otherwise open the full linkname. 817*c7e4935fSss150715 */ 818*c7e4935fSss150715 retval = i_dlpi_open((dip->dli_mod_cnt != 0) ? dip->dli_provider : 819*c7e4935fSss150715 dip->dli_linkname, &fd, dip->dli_oflags); 820*c7e4935fSss150715 821*c7e4935fSss150715 if (retval != DLPI_SUCCESS) { 822*c7e4935fSss150715 dip->dli_mod_pushed = 0; 823*c7e4935fSss150715 return (retval); 824*c7e4935fSss150715 } 825*c7e4935fSss150715 dip->dli_fd = fd; 826*c7e4935fSss150715 827*c7e4935fSss150715 /* 828*c7e4935fSss150715 * Try to push modules (if any) onto the device stream. If I_PUSH 829*c7e4935fSss150715 * fails, we increment count of modules pushed (dli_mod_pushed) 830*c7e4935fSss150715 * expecting it is last module to be pushed and thus will be pushed 831*c7e4935fSss150715 * in i_dlpi_style2_open(). 832*c7e4935fSss150715 */ 833*c7e4935fSss150715 for (dip->dli_mod_pushed = 0; dip->dli_mod_pushed < dip->dli_mod_cnt; 834*c7e4935fSss150715 dip->dli_mod_pushed++) { 835*c7e4935fSss150715 if (ioctl(fd, I_PUSH, 836*c7e4935fSss150715 dip->dli_modlist[dip->dli_mod_pushed]) == -1) { 837*c7e4935fSss150715 dip->dli_mod_pushed++; 838*c7e4935fSss150715 return (DLPI_FAILURE); 839*c7e4935fSss150715 } 840*c7e4935fSss150715 } 841*c7e4935fSss150715 842*c7e4935fSss150715 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) { 843*c7e4935fSss150715 save_errno = errno; 844*c7e4935fSss150715 (void) close(dip->dli_fd); 845*c7e4935fSss150715 errno = save_errno; 846*c7e4935fSss150715 dip->dli_mod_pushed = 0; 847*c7e4935fSss150715 return (retval); 848*c7e4935fSss150715 } 849*c7e4935fSss150715 850*c7e4935fSss150715 return (DLPI_SUCCESS); 851*c7e4935fSss150715 } 852*c7e4935fSss150715 853*c7e4935fSss150715 /* 854*c7e4935fSss150715 * Open a style 2 link. PPA must be explicitly attached. 855*c7e4935fSss150715 */ 856*c7e4935fSss150715 static int 857*c7e4935fSss150715 i_dlpi_style2_open(dlpi_impl_t *dip) 858*c7e4935fSss150715 { 859*c7e4935fSss150715 int fd; 860*c7e4935fSss150715 int retval, save_errno; 861*c7e4935fSss150715 862*c7e4935fSss150715 /* 863*c7e4935fSss150715 * If style 1 open failed, we need to determine how far it got and 864*c7e4935fSss150715 * finish up the open() call as a style 2 open. 865*c7e4935fSss150715 * 866*c7e4935fSss150715 * If no modules were pushed (mod_pushed == 0), then we need to 867*c7e4935fSss150715 * open it as a style 2 link. 868*c7e4935fSss150715 * 869*c7e4935fSss150715 * If the pushing of the last module failed, we need to 870*c7e4935fSss150715 * try pushing it as a style 2 module. Decrement dli_mod_pushed 871*c7e4935fSss150715 * count so it can be pushed onto the stream. 872*c7e4935fSss150715 * 873*c7e4935fSss150715 * Otherwise we failed during the push of an intermediate module and 874*c7e4935fSss150715 * must fail out and close the link. 875*c7e4935fSss150715 */ 876*c7e4935fSss150715 if (dip->dli_mod_pushed == 0) { 877*c7e4935fSss150715 if ((retval = i_dlpi_open(dip->dli_provider, &fd, 878*c7e4935fSss150715 dip->dli_oflags)) != DLPI_SUCCESS) 879*c7e4935fSss150715 return (retval); 880*c7e4935fSss150715 881*c7e4935fSss150715 dip->dli_fd = fd; 882*c7e4935fSss150715 } else if (dip->dli_mod_pushed == dip->dli_mod_cnt) { 883*c7e4935fSss150715 if (i_dlpi_remove_ppa(dip->dli_modlist[dip->dli_mod_cnt - 1]) 884*c7e4935fSss150715 != DLPI_SUCCESS) 885*c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 886*c7e4935fSss150715 887*c7e4935fSss150715 dip->dli_mod_pushed--; 888*c7e4935fSss150715 fd = dip->dli_fd; 889*c7e4935fSss150715 } else { 890*c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 891*c7e4935fSss150715 } 892*c7e4935fSss150715 893*c7e4935fSss150715 /* Try and push modules (if any) onto the device stream. */ 894*c7e4935fSss150715 for (; dip->dli_mod_pushed < dip->dli_mod_cnt; dip->dli_mod_pushed++) { 895*c7e4935fSss150715 if (ioctl(fd, I_PUSH, 896*c7e4935fSss150715 dip->dli_modlist[dip->dli_mod_pushed]) == -1) { 897*c7e4935fSss150715 retval = DL_SYSERR; 898*c7e4935fSss150715 goto failure; 899*c7e4935fSss150715 } 900*c7e4935fSss150715 } 901*c7e4935fSss150715 902*c7e4935fSss150715 /* 903*c7e4935fSss150715 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a 904*c7e4935fSss150715 * DLPI link so attach and ignore rest. 905*c7e4935fSss150715 */ 906*c7e4935fSss150715 if (dip->dli_oflags & DLPI_SERIAL) 907*c7e4935fSss150715 goto attach; 908*c7e4935fSss150715 909*c7e4935fSss150715 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS) 910*c7e4935fSss150715 goto failure; 911*c7e4935fSss150715 912*c7e4935fSss150715 /* 913*c7e4935fSss150715 * Succeeded opening the link and verified it is style2. Now attach to 914*c7e4935fSss150715 * PPA only if DLPI_NOATTACH is not set. 915*c7e4935fSss150715 */ 916*c7e4935fSss150715 if (dip->dli_oflags & DLPI_NOATTACH) 917*c7e4935fSss150715 return (DLPI_SUCCESS); 918*c7e4935fSss150715 919*c7e4935fSss150715 attach: 920*c7e4935fSss150715 if ((retval = i_dlpi_attach(dip)) != DLPI_SUCCESS) 921*c7e4935fSss150715 goto failure; 922*c7e4935fSss150715 923*c7e4935fSss150715 return (DLPI_SUCCESS); 924*c7e4935fSss150715 925*c7e4935fSss150715 failure: 926*c7e4935fSss150715 save_errno = errno; 927*c7e4935fSss150715 (void) close(dip->dli_fd); 928*c7e4935fSss150715 errno = save_errno; 929*c7e4935fSss150715 return (retval); 930*c7e4935fSss150715 } 931*c7e4935fSss150715 932*c7e4935fSss150715 /* 933*c7e4935fSss150715 * Verify with DLPI that the link is the expected DLPI 'style' device, 934*c7e4935fSss150715 * dlpi_info sets the DLPI style in the DLPI handle. 935*c7e4935fSss150715 */ 936*c7e4935fSss150715 static int 937*c7e4935fSss150715 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style) 938*c7e4935fSss150715 { 939*c7e4935fSss150715 int retval; 940*c7e4935fSss150715 dlpi_info_t dlinfo; 941*c7e4935fSss150715 942*c7e4935fSss150715 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0); 943*c7e4935fSss150715 if (retval == DLPI_SUCCESS && dip->dli_style != style) 944*c7e4935fSss150715 retval = DLPI_EBADLINK; 945*c7e4935fSss150715 946*c7e4935fSss150715 return (retval); 947*c7e4935fSss150715 } 948*c7e4935fSss150715 949*c7e4935fSss150715 /* 950*c7e4935fSss150715 * Remove PPA from end of linkname. 951*c7e4935fSss150715 * Return DLPI_SUCCESS if found, else return DLPI_FAILURE. 952*c7e4935fSss150715 */ 953*c7e4935fSss150715 static int 954*c7e4935fSss150715 i_dlpi_remove_ppa(char *linkname) 955*c7e4935fSss150715 { 956*c7e4935fSss150715 int i = strlen(linkname) - 1; 957*c7e4935fSss150715 958*c7e4935fSss150715 if (i == -1 || !isdigit(linkname[i--])) 959*c7e4935fSss150715 return (DLPI_FAILURE); 960*c7e4935fSss150715 961*c7e4935fSss150715 while (i >= 0 && isdigit(linkname[i])) 962*c7e4935fSss150715 i--; 963*c7e4935fSss150715 964*c7e4935fSss150715 linkname[i + 1] = '\0'; 965*c7e4935fSss150715 return (DLPI_SUCCESS); 966*c7e4935fSss150715 } 967*c7e4935fSss150715 968*c7e4935fSss150715 /* 969*c7e4935fSss150715 * For DLPI style 2 providers, an explicit attach of PPA is required. 970*c7e4935fSss150715 */ 971*c7e4935fSss150715 static int 972*c7e4935fSss150715 i_dlpi_attach(dlpi_impl_t *dip) 973*c7e4935fSss150715 { 974*c7e4935fSss150715 dlpi_msg_t req, ack; 975*c7e4935fSss150715 dl_attach_req_t *attachreqp; 976*c7e4935fSss150715 977*c7e4935fSss150715 /* 978*c7e4935fSss150715 * Special case: DLPI_SERIAL flag (synchronous serial lines) 979*c7e4935fSss150715 * is not a DLPI link so ignore DLPI style. 980*c7e4935fSss150715 */ 981*c7e4935fSss150715 if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL)) 982*c7e4935fSss150715 return (DLPI_ENOTSTYLE2); 983*c7e4935fSss150715 984*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_ATTACH_REQ); 985*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 986*c7e4935fSss150715 987*c7e4935fSss150715 attachreqp = &(req.dlm_msg->attach_req); 988*c7e4935fSss150715 attachreqp->dl_ppa = dip->dli_ppa; 989*c7e4935fSss150715 990*c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 991*c7e4935fSss150715 } 992*c7e4935fSss150715 993*c7e4935fSss150715 /* 994*c7e4935fSss150715 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care 995*c7e4935fSss150715 * if this request fails, as this indicates the underlying DLPI device does 996*c7e4935fSss150715 * not support link aggregation (pre-GLDV3 device drivers), and thus will 997*c7e4935fSss150715 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing 998*c7e4935fSss150715 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p). 999*c7e4935fSss150715 */ 1000*c7e4935fSss150715 static void 1001*c7e4935fSss150715 i_dlpi_passive(dlpi_impl_t *dip) 1002*c7e4935fSss150715 { 1003*c7e4935fSss150715 dlpi_msg_t req, ack; 1004*c7e4935fSss150715 1005*c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_PASSIVE_REQ); 1006*c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1007*c7e4935fSss150715 1008*c7e4935fSss150715 (void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0); 1009*c7e4935fSss150715 } 1010*c7e4935fSss150715 1011*c7e4935fSss150715 /* 1012*c7e4935fSss150715 * Send a dlpi control message and/or data message on a stream. The inputs 1013*c7e4935fSss150715 * for this function are: 1014*c7e4935fSss150715 * int fd: file descriptor of open stream to send message 1015*c7e4935fSss150715 * const dlpi_msg_t *dlreqp: request message structure 1016*c7e4935fSss150715 * void *databuf: data buffer 1017*c7e4935fSss150715 * size_t datalen: data buffer len 1018*c7e4935fSss150715 * int flags: flags to set for putmsg() 1019*c7e4935fSss150715 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure. 1020*c7e4935fSss150715 */ 1021*c7e4935fSss150715 static int 1022*c7e4935fSss150715 i_dlpi_strputmsg(int fd, const dlpi_msg_t *dlreqp, 1023*c7e4935fSss150715 const void *databuf, size_t datalen, int flags) 1024*c7e4935fSss150715 { 1025*c7e4935fSss150715 int retval; 10267c478bd9Sstevel@tonic-gate struct strbuf ctl; 10277c478bd9Sstevel@tonic-gate struct strbuf data; 1028*c7e4935fSss150715 1029*c7e4935fSss150715 if (dlreqp != NULL) { 1030*c7e4935fSss150715 ctl.buf = (void *)dlreqp->dlm_msg; 1031*c7e4935fSss150715 ctl.len = dlreqp->dlm_msgsz; 1032*c7e4935fSss150715 } 1033*c7e4935fSss150715 1034*c7e4935fSss150715 data.buf = (void *)databuf; 1035*c7e4935fSss150715 data.len = datalen; 1036*c7e4935fSss150715 1037*c7e4935fSss150715 retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl), 1038*c7e4935fSss150715 (databuf == NULL ? NULL : &data), flags); 1039*c7e4935fSss150715 1040*c7e4935fSss150715 return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR); 1041*c7e4935fSss150715 } 1042*c7e4935fSss150715 1043*c7e4935fSss150715 /* 1044*c7e4935fSss150715 * Get a DLPI control message and/or data message from a stream. The inputs 1045*c7e4935fSss150715 * for this function are: 1046*c7e4935fSss150715 * int fd: file descriptor of open stream 1047*c7e4935fSss150715 * int msec: timeout to wait for message 1048*c7e4935fSss150715 * dlpi_msg_t *dlreplyp: reply message structure, the message size 1049*c7e4935fSss150715 * member on return stores actual size received 1050*c7e4935fSss150715 * t_uscalar_t dlreqprim: requested primitive 1051*c7e4935fSss150715 * t_uscalar_t dlreplyprim:acknowledged primitive in response to request 1052*c7e4935fSss150715 * size_t dlreplyminsz: minimum size of acknowledged primitive size 1053*c7e4935fSss150715 * void *databuf: data buffer 1054*c7e4935fSss150715 * size_t *datalenp: data buffer len 1055*c7e4935fSss150715 * size_t *totdatalenp: total data received. Greater than 'datalenp' if 1056*c7e4935fSss150715 * actual data received is larger than 'databuf' 1057*c7e4935fSss150715 * Function returns DLPI_SUCCESS if requested message is retrieved 1058*c7e4935fSss150715 * otherwise returns error code or timeouts. 1059*c7e4935fSss150715 */ 1060*c7e4935fSss150715 static int 1061*c7e4935fSss150715 i_dlpi_strgetmsg(int fd, int msec, dlpi_msg_t *dlreplyp, t_uscalar_t dlreqprim, 1062*c7e4935fSss150715 t_uscalar_t dlreplyprim, size_t dlreplyminsz, void *databuf, 1063*c7e4935fSss150715 size_t *datalenp, size_t *totdatalenp) 1064*c7e4935fSss150715 { 1065*c7e4935fSss150715 int retval; 10667c478bd9Sstevel@tonic-gate int flags = 0; 1067*c7e4935fSss150715 struct strbuf ctl, data; 1068*c7e4935fSss150715 struct pollfd pfd; 1069*c7e4935fSss150715 hrtime_t start, current; 1070*c7e4935fSss150715 long bufc[DLPI_CHUNKSIZE / sizeof (long)]; 1071*c7e4935fSss150715 long bufd[DLPI_CHUNKSIZE / sizeof (long)]; 1072*c7e4935fSss150715 union DL_primitives *dlprim; 1073*c7e4935fSss150715 boolean_t infinite = (msec < 0); /* infinite timeout */ 1074*c7e4935fSss150715 1075*c7e4935fSss150715 if ((dlreplyp == NULL && databuf == NULL) || 1076*c7e4935fSss150715 (databuf == NULL && datalenp != NULL) || 1077*c7e4935fSss150715 (databuf != NULL && datalenp == NULL)) 1078*c7e4935fSss150715 return (DLPI_EINVAL); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate pfd.fd = fd; 10817c478bd9Sstevel@tonic-gate pfd.events = POLLIN | POLLPRI; 10827c478bd9Sstevel@tonic-gate 1083*c7e4935fSss150715 ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg; 10847c478bd9Sstevel@tonic-gate ctl.len = 0; 1085*c7e4935fSss150715 ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz; 10867c478bd9Sstevel@tonic-gate 1087*c7e4935fSss150715 data.buf = (databuf == NULL) ? bufd : databuf; 10887c478bd9Sstevel@tonic-gate data.len = 0; 1089*c7e4935fSss150715 data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp; 10907c478bd9Sstevel@tonic-gate 1091*c7e4935fSss150715 for (;;) { 1092*c7e4935fSss150715 if (!infinite) 1093*c7e4935fSss150715 start = gethrtime() / (NANOSEC / MILLISEC); 10947c478bd9Sstevel@tonic-gate 1095*c7e4935fSss150715 switch (poll(&pfd, 1, msec)) { 1096*c7e4935fSss150715 default: 10977c478bd9Sstevel@tonic-gate break; 10987c478bd9Sstevel@tonic-gate case 0: 1099*c7e4935fSss150715 return (DLPI_ETIMEDOUT); 11007c478bd9Sstevel@tonic-gate case -1: 1101*c7e4935fSss150715 return (DL_SYSERR); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 1104*c7e4935fSss150715 if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0) 1105*c7e4935fSss150715 return (DL_SYSERR); 11067c478bd9Sstevel@tonic-gate 1107*c7e4935fSss150715 if (totdatalenp != NULL) 1108*c7e4935fSss150715 *totdatalenp = data.len; 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 1111*c7e4935fSss150715 * The supplied DLPI_CHUNKSIZE sized buffers are large enough 1112*c7e4935fSss150715 * to retrieve all valid DLPI responses in one iteration. 1113*c7e4935fSss150715 * If MORECTL or MOREDATA is set, we are not interested in the 1114*c7e4935fSss150715 * remainder of the message. Temporary buffers are used to 1115*c7e4935fSss150715 * drain the remainder of this message. 1116*c7e4935fSss150715 * The special case we have to account for is if 1117*c7e4935fSss150715 * a higher priority messages is enqueued whilst handling 1118*c7e4935fSss150715 * this condition. We use a change in the flags parameter 1119*c7e4935fSss150715 * returned by getmsg() to indicate the message has changed. 11207c478bd9Sstevel@tonic-gate */ 1121*c7e4935fSss150715 while (retval & (MORECTL | MOREDATA)) { 1122*c7e4935fSss150715 struct strbuf cscratch, dscratch; 1123*c7e4935fSss150715 int oflags = flags; 1124*c7e4935fSss150715 1125*c7e4935fSss150715 cscratch.buf = (char *)bufc; 1126*c7e4935fSss150715 dscratch.buf = (char *)bufd; 1127*c7e4935fSss150715 cscratch.len = dscratch.len = 0; 1128*c7e4935fSss150715 cscratch.maxlen = dscratch.maxlen = 1129*c7e4935fSss150715 sizeof (bufc); 1130*c7e4935fSss150715 1131*c7e4935fSss150715 if ((retval = getmsg(fd, &cscratch, &dscratch, 1132*c7e4935fSss150715 &flags)) < 0) 1133*c7e4935fSss150715 return (DL_SYSERR); 1134*c7e4935fSss150715 1135*c7e4935fSss150715 if (totdatalenp != NULL) 1136*c7e4935fSss150715 *totdatalenp += dscratch.len; 1137*c7e4935fSss150715 /* 1138*c7e4935fSss150715 * In the special case of higher priority 1139*c7e4935fSss150715 * message received, the low priority message 1140*c7e4935fSss150715 * received earlier is discarded, if no data 1141*c7e4935fSss150715 * or control message is left. 1142*c7e4935fSss150715 */ 1143*c7e4935fSss150715 if ((flags != oflags) && 1144*c7e4935fSss150715 !(retval & (MORECTL | MOREDATA)) && 1145*c7e4935fSss150715 (cscratch.len != 0)) { 1146*c7e4935fSss150715 ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE); 1147*c7e4935fSss150715 if (dlreplyp != NULL) 1148*c7e4935fSss150715 (void) memcpy(dlreplyp->dlm_msg, bufc, 1149*c7e4935fSss150715 ctl.len); 1150*c7e4935fSss150715 break; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* 1155*c7e4935fSss150715 * If we were expecting a data message, and we got one, set 1156*c7e4935fSss150715 * *datalenp. If we aren't waiting on a control message, then 1157*c7e4935fSss150715 * we're done. 11587c478bd9Sstevel@tonic-gate */ 1159*c7e4935fSss150715 if (databuf != NULL && data.len >= 0) { 1160*c7e4935fSss150715 *datalenp = data.len; 1161*c7e4935fSss150715 if (dlreplyp == NULL) 1162*c7e4935fSss150715 break; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* 1166*c7e4935fSss150715 * If we were expecting a control message, and the message 1167*c7e4935fSss150715 * we received is at least big enough to be a DLPI message, 1168*c7e4935fSss150715 * then verify it's a reply to something we sent. If it 1169*c7e4935fSss150715 * is a reply to something we sent, also verify its size. 11707c478bd9Sstevel@tonic-gate */ 1171*c7e4935fSss150715 if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) { 1172*c7e4935fSss150715 dlprim = dlreplyp->dlm_msg; 1173*c7e4935fSss150715 if (dlprim->dl_primitive == dlreplyprim) { 1174*c7e4935fSss150715 if (ctl.len < dlreplyminsz) 1175*c7e4935fSss150715 return (DLPI_EBADMSG); 1176*c7e4935fSss150715 dlreplyp->dlm_msgsz = ctl.len; 1177*c7e4935fSss150715 break; 1178*c7e4935fSss150715 } else if (dlprim->dl_primitive == DL_ERROR_ACK) { 1179*c7e4935fSss150715 if (ctl.len < DL_ERROR_ACK_SIZE) 1180*c7e4935fSss150715 return (DLPI_EBADMSG); 11817c478bd9Sstevel@tonic-gate 1182*c7e4935fSss150715 /* Is it ours? */ 1183*c7e4935fSss150715 if (dlprim->error_ack.dl_error_primitive == 1184*c7e4935fSss150715 dlreqprim) 11857c478bd9Sstevel@tonic-gate break; 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate 1189*c7e4935fSss150715 if (!infinite) { 1190*c7e4935fSss150715 current = gethrtime() / (NANOSEC / MILLISEC); 1191*c7e4935fSss150715 msec -= (current - start); 11927c478bd9Sstevel@tonic-gate 1193*c7e4935fSss150715 if (msec <= 0) 1194*c7e4935fSss150715 return (DLPI_ETIMEDOUT); 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 1198*c7e4935fSss150715 return (DLPI_SUCCESS); 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 1202*c7e4935fSss150715 * Common routine invoked by all DLPI control routines. The inputs for this 1203*c7e4935fSss150715 * function are: 1204*c7e4935fSss150715 * dlpi_impl_t *dip: internal dlpi handle 1205*c7e4935fSss150715 * const dlpi_msg_t *dlreqp: request message structure 1206*c7e4935fSss150715 * dlpi_msg_t *dlreplyp: reply message structure 1207*c7e4935fSss150715 * size_t dlreplyminsz: minimum size of reply primitive 1208*c7e4935fSss150715 * int flags: flags to be set to send a message 1209*c7e4935fSss150715 * This routine succeeds if the message is an expected request/acknowledged 1210*c7e4935fSss150715 * message. Unexpected asynchronous messages (e.g. unexpected DL_NOTIFY_IND 1211*c7e4935fSss150715 * messages) will be discarded. 12127c478bd9Sstevel@tonic-gate */ 12137c478bd9Sstevel@tonic-gate static int 1214*c7e4935fSss150715 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp, 1215*c7e4935fSss150715 dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags) 1216*c7e4935fSss150715 { 1217*c7e4935fSss150715 int retval; 1218*c7e4935fSss150715 t_uscalar_t dlreqprim = dlreqp->dlm_msg->dl_primitive; 1219*c7e4935fSss150715 t_uscalar_t dlreplyprim = dlreplyp->dlm_msg->dl_primitive; 1220*c7e4935fSss150715 1221*c7e4935fSss150715 /* Put the requested primitive on the stream. */ 1222*c7e4935fSss150715 retval = i_dlpi_strputmsg(dip->dli_fd, dlreqp, NULL, 0, flags); 1223*c7e4935fSss150715 if (retval != DLPI_SUCCESS) 1224*c7e4935fSss150715 return (retval); 1225*c7e4935fSss150715 1226*c7e4935fSss150715 /* Retrieve acknowledged message for requested primitive. */ 1227*c7e4935fSss150715 retval = i_dlpi_strgetmsg(dip->dli_fd, (dip->dli_timeout * MILLISEC), 1228*c7e4935fSss150715 dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL); 1229*c7e4935fSss150715 if (retval != DLPI_SUCCESS) 1230*c7e4935fSss150715 return (retval); 1231*c7e4935fSss150715 1232*c7e4935fSss150715 /* 1233*c7e4935fSss150715 * If primitive is DL_ERROR_ACK, set errno. 1234*c7e4935fSss150715 */ 1235*c7e4935fSss150715 if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) { 1236*c7e4935fSss150715 errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno; 1237*c7e4935fSss150715 retval = dlreplyp->dlm_msg->error_ack.dl_errno; 1238*c7e4935fSss150715 } 1239*c7e4935fSss150715 1240*c7e4935fSss150715 return (retval); 1241*c7e4935fSss150715 } 1242*c7e4935fSss150715 1243*c7e4935fSss150715 /* 1244*c7e4935fSss150715 * DLPI error codes. 1245*c7e4935fSss150715 */ 1246*c7e4935fSss150715 static const char *dlpi_errlist[] = { 1247*c7e4935fSss150715 "bad LSAP selector", /* DL_BADSAP 0x00 */ 1248*c7e4935fSss150715 "DLSAP address in improper format or invalid", /* DL_BADADDR 0x01 */ 1249*c7e4935fSss150715 "improper permissions for request", /* DL_ACCESS 0x02 */ 1250*c7e4935fSss150715 "primitive issued in improper state", /* DL_OUTSTATE 0x03 */ 1251*c7e4935fSss150715 NULL, /* DL_SYSERR 0x04 */ 1252*c7e4935fSss150715 "sequence number not from outstanding DL_CONN_IND", 1253*c7e4935fSss150715 /* DL_BADCORR 0x05 */ 1254*c7e4935fSss150715 "user data exceeded provider limit", /* DL_BADDATA 0x06 */ 1255*c7e4935fSss150715 "requested service not supplied by provider", 1256*c7e4935fSss150715 /* DL_UNSUPPORTED 0x07 */ 1257*c7e4935fSss150715 "specified PPA was invalid", /* DL_BADPPA 0x08 */ 1258*c7e4935fSss150715 "primitive received not known by provider", /* DL_BADPRIM 0x09 */ 1259*c7e4935fSss150715 "QoS parameters contained invalid values", 1260*c7e4935fSss150715 /* DL_BADQOSPARAM 0x0a */ 1261*c7e4935fSss150715 "QoS structure type is unknown/unsupported", /* DL_BADQOSTYPE 0x0b */ 1262*c7e4935fSss150715 "token used not an active stream", /* DL_BADTOKEN 0x0c */ 1263*c7e4935fSss150715 "attempted second bind with dl_max_conind", /* DL_BOUND 0x0d */ 1264*c7e4935fSss150715 "physical link initialization failed", /* DL_INITFAILED 0x0e */ 1265*c7e4935fSss150715 "provider couldn't allocate alternate address", /* DL_NOADDR 0x0f */ 1266*c7e4935fSss150715 "physical link not initialized", /* DL_NOTINIT 0x10 */ 1267*c7e4935fSss150715 "previous data unit could not be delivered", 1268*c7e4935fSss150715 /* DL_UNDELIVERABLE 0x11 */ 1269*c7e4935fSss150715 "primitive is known but unsupported", 1270*c7e4935fSss150715 /* DL_NOTSUPPORTED 0x12 */ 1271*c7e4935fSss150715 "limit exceeded", /* DL_TOOMANY 0x13 */ 1272*c7e4935fSss150715 "promiscuous mode not enabled", /* DL_NOTENAB 0x14 */ 1273*c7e4935fSss150715 "other streams for PPA in post-attached", /* DL_BUSY 0x15 */ 1274*c7e4935fSss150715 "automatic handling XID&TEST unsupported", /* DL_NOAUTO 0x16 */ 1275*c7e4935fSss150715 "automatic handling of XID unsupported", /* DL_NOXIDAUTO 0x17 */ 1276*c7e4935fSss150715 "automatic handling of TEST unsupported", /* DL_NOTESTAUTO 0x18 */ 1277*c7e4935fSss150715 "automatic handling of XID response", /* DL_XIDAUTO 0x19 */ 1278*c7e4935fSss150715 "automatic handling of TEST response", /* DL_TESTAUTO 0x1a */ 1279*c7e4935fSss150715 "pending outstanding connect indications" /* DL_PENDING 0x1b */ 1280*c7e4935fSss150715 }; 1281*c7e4935fSss150715 1282*c7e4935fSss150715 /* 1283*c7e4935fSss150715 * libdlpi error codes. 1284*c7e4935fSss150715 */ 1285*c7e4935fSss150715 static const char *libdlpi_errlist[] = { 1286*c7e4935fSss150715 "DLPI operation succeeded", /* DLPI_SUCCESS */ 1287*c7e4935fSss150715 "invalid argument", /* DLPI_EINVAL */ 1288*c7e4935fSss150715 "invalid DLPI linkname", /* DLPI_ELINKNAMEINVAL */ 1289*c7e4935fSss150715 "DLPI link does not exist", /* DLPI_ENOLINK */ 1290*c7e4935fSss150715 "bad DLPI link", /* DLPI_EBADLINK */ 1291*c7e4935fSss150715 "invalid DLPI handle", /* DLPI_EINHANDLE */ 1292*c7e4935fSss150715 "DLPI operation timed out", /* DLPI_ETIMEDOUT */ 1293*c7e4935fSss150715 "unsupported DLPI version", /* DLPI_EVERNOTSUP */ 1294*c7e4935fSss150715 "unsupported DLPI connection mode", /* DLPI_EMODENOTSUP */ 1295*c7e4935fSss150715 "unavailable DLPI SAP", /* DLPI_EUNAVAILSAP */ 1296*c7e4935fSss150715 "DLPI operation failed", /* DLPI_FAILURE */ 1297*c7e4935fSss150715 "DLPI style-2 node reports style-1", /* DLPI_ENOTSTYLE2 */ 1298*c7e4935fSss150715 "bad DLPI message", /* DLPI_EBADMSG */ 1299*c7e4935fSss150715 "DLPI raw mode not supported" /* DLPI_ERAWNOTSUP */ 1300*c7e4935fSss150715 }; 1301*c7e4935fSss150715 1302*c7e4935fSss150715 const char * 1303*c7e4935fSss150715 dlpi_strerror(int err) 1304*c7e4935fSss150715 { 1305*c7e4935fSss150715 if (err == DL_SYSERR) 1306*c7e4935fSss150715 return (strerror(errno)); 1307*c7e4935fSss150715 else if (err >= 0 && err < NELEMS(dlpi_errlist)) 1308*c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, dlpi_errlist[err])); 1309*c7e4935fSss150715 else if (err > DLPI_SUCCESS && err < DLPI_ERRMAX) 1310*c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err - 1311*c7e4935fSss150715 DLPI_SUCCESS])); 1312*c7e4935fSss150715 else 1313*c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, "Unknown DLPI error")); 1314*c7e4935fSss150715 } 1315*c7e4935fSss150715 1316*c7e4935fSss150715 /* 1317*c7e4935fSss150715 * Each table entry comprises a DLPI/Private mactype and the description. 1318*c7e4935fSss150715 */ 1319*c7e4935fSss150715 static const dlpi_mactype_t dlpi_mactypes[] = { 1320*c7e4935fSss150715 { DL_CSMACD, "CSMA/CD" }, 1321*c7e4935fSss150715 { DL_TPB, "Token Bus" }, 1322*c7e4935fSss150715 { DL_TPR, "Token Ring" }, 1323*c7e4935fSss150715 { DL_METRO, "Metro Net" }, 1324*c7e4935fSss150715 { DL_ETHER, "Ethernet" }, 1325*c7e4935fSss150715 { DL_HDLC, "HDLC" }, 1326*c7e4935fSss150715 { DL_CHAR, "Sync Character" }, 1327*c7e4935fSss150715 { DL_CTCA, "CTCA" }, 1328*c7e4935fSss150715 { DL_FDDI, "FDDI" }, 1329*c7e4935fSss150715 { DL_FRAME, "Frame Relay (LAPF)" }, 1330*c7e4935fSss150715 { DL_MPFRAME, "MP Frame Relay" }, 1331*c7e4935fSss150715 { DL_ASYNC, "Async Character" }, 1332*c7e4935fSss150715 { DL_IPX25, "X.25 (Classic IP)" }, 1333*c7e4935fSss150715 { DL_LOOP, "Software Loopback" }, 1334*c7e4935fSss150715 { DL_FC, "Fiber Channel" }, 1335*c7e4935fSss150715 { DL_ATM, "ATM" }, 1336*c7e4935fSss150715 { DL_IPATM, "ATM (Classic IP)" }, 1337*c7e4935fSss150715 { DL_X25, "X.25 (LAPB)" }, 1338*c7e4935fSss150715 { DL_ISDN, "ISDN" }, 1339*c7e4935fSss150715 { DL_HIPPI, "HIPPI" }, 1340*c7e4935fSss150715 { DL_100VG, "100BaseVG Ethernet" }, 1341*c7e4935fSss150715 { DL_100VGTPR, "100BaseVG Token Ring" }, 1342*c7e4935fSss150715 { DL_ETH_CSMA, "Ethernet/IEEE 802.3" }, 1343*c7e4935fSss150715 { DL_100BT, "100BaseT" }, 1344*c7e4935fSss150715 { DL_IB, "Infiniband" }, 1345*c7e4935fSss150715 { DL_IPV4, "IPv4 Tunnel" }, 1346*c7e4935fSss150715 { DL_IPV6, "IPv6 Tunnel" }, 1347*c7e4935fSss150715 { DL_WIFI, "IEEE 802.11" } 1348*c7e4935fSss150715 }; 1349*c7e4935fSss150715 1350*c7e4935fSss150715 const char * 1351*c7e4935fSss150715 dlpi_mactype(uint_t mactype) 13527c478bd9Sstevel@tonic-gate { 13537c478bd9Sstevel@tonic-gate int i; 13547c478bd9Sstevel@tonic-gate 1355*c7e4935fSss150715 for (i = 0; i < NELEMS(dlpi_mactypes); i++) { 1356*c7e4935fSss150715 if (dlpi_mactypes[i].dm_mactype == mactype) 1357*c7e4935fSss150715 return (dlpi_mactypes[i].dm_desc); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 1360*c7e4935fSss150715 return ("Unknown MAC Type"); 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate 1363*c7e4935fSss150715 /* 1364*c7e4935fSss150715 * Each table entry comprises a DLPI primitive and the maximum buffer 1365*c7e4935fSss150715 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details). 1366*c7e4935fSss150715 */ 1367*c7e4935fSss150715 static const dlpi_primsz_t dlpi_primsizes[] = { 1368*c7e4935fSss150715 { DL_INFO_REQ, DL_INFO_REQ_SIZE }, 1369*c7e4935fSss150715 { DL_INFO_ACK, DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) + 1370*c7e4935fSss150715 DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))}, 1371*c7e4935fSss150715 { DL_ATTACH_REQ, DL_ATTACH_REQ_SIZE }, 1372*c7e4935fSss150715 { DL_BIND_REQ, DL_BIND_REQ_SIZE }, 1373*c7e4935fSss150715 { DL_BIND_ACK, DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX + 1374*c7e4935fSss150715 DLPI_SAPLEN_MAX }, 1375*c7e4935fSss150715 { DL_UNBIND_REQ, DL_UNBIND_REQ_SIZE }, 1376*c7e4935fSss150715 { DL_ENABMULTI_REQ, DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1377*c7e4935fSss150715 { DL_DISABMULTI_REQ, DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1378*c7e4935fSss150715 { DL_PROMISCON_REQ, DL_PROMISCON_REQ_SIZE }, 1379*c7e4935fSss150715 { DL_PROMISCOFF_REQ, DL_PROMISCOFF_REQ_SIZE }, 1380*c7e4935fSss150715 { DL_PASSIVE_REQ, DL_PASSIVE_REQ_SIZE }, 1381*c7e4935fSss150715 { DL_UNITDATA_REQ, DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX + 1382*c7e4935fSss150715 DLPI_SAPLEN_MAX }, 1383*c7e4935fSss150715 { DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX + 1384*c7e4935fSss150715 DLPI_SAPLEN_MAX)) }, 1385*c7e4935fSss150715 { DL_PHYS_ADDR_REQ, DL_PHYS_ADDR_REQ_SIZE }, 1386*c7e4935fSss150715 { DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX }, 1387*c7e4935fSss150715 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1388*c7e4935fSss150715 { DL_OK_ACK, MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE) } 1389*c7e4935fSss150715 }; 1390*c7e4935fSss150715 1391*c7e4935fSss150715 /* 1392*c7e4935fSss150715 * Refers to the dlpi_primsizes[] table to return corresponding maximum 1393*c7e4935fSss150715 * buffer size. 1394*c7e4935fSss150715 */ 1395*c7e4935fSss150715 static size_t 1396*c7e4935fSss150715 i_dlpi_getprimsize(t_uscalar_t prim) 1397*c7e4935fSss150715 { 1398*c7e4935fSss150715 int i; 1399*c7e4935fSss150715 1400*c7e4935fSss150715 for (i = 0; i < NELEMS(dlpi_primsizes); i++) { 1401*c7e4935fSss150715 if (dlpi_primsizes[i].dp_prim == prim) 1402*c7e4935fSss150715 return (dlpi_primsizes[i].dp_primsz); 1403*c7e4935fSss150715 } 1404*c7e4935fSss150715 1405*c7e4935fSss150715 return (sizeof (t_uscalar_t)); 1406*c7e4935fSss150715 } 1407*c7e4935fSss150715 1408*c7e4935fSss150715 /* 1409*c7e4935fSss150715 * sap values vary in length and are in host byte order, build sap value 1410*c7e4935fSss150715 * by writing saplen bytes, so that the sap value is left aligned. 1411*c7e4935fSss150715 */ 1412*c7e4935fSss150715 static uint_t 1413*c7e4935fSss150715 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen) 1414*c7e4935fSss150715 { 1415*c7e4935fSss150715 int i; 1416*c7e4935fSss150715 uint_t sap = 0; 1417*c7e4935fSss150715 1418*c7e4935fSss150715 #ifdef _LITTLE_ENDIAN 1419*c7e4935fSss150715 for (i = saplen - 1; i >= 0; i--) { 1420*c7e4935fSss150715 #else 1421*c7e4935fSss150715 for (i = 0; i < saplen; i++) { 1422*c7e4935fSss150715 #endif 1423*c7e4935fSss150715 sap <<= 8; 1424*c7e4935fSss150715 sap |= sapp[i]; 1425*c7e4935fSss150715 } 1426*c7e4935fSss150715 1427*c7e4935fSss150715 return (sap); 1428*c7e4935fSss150715 } 1429*c7e4935fSss150715 1430*c7e4935fSss150715 /* 1431*c7e4935fSss150715 * Copy sap value to a buffer in host byte order. saplen is the number of 1432*c7e4935fSss150715 * bytes to copy. 1433*c7e4935fSss150715 */ 1434*c7e4935fSss150715 static void 1435*c7e4935fSss150715 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen) 1436*c7e4935fSss150715 { 1437*c7e4935fSss150715 uint8_t *sapp; 1438*c7e4935fSss150715 1439*c7e4935fSss150715 #ifdef _LITTLE_ENDIAN 1440*c7e4935fSss150715 sapp = (uint8_t *)&sap; 1441*c7e4935fSss150715 #else 1442*c7e4935fSss150715 sapp = (uint8_t *)&sap + (sizeof (sap) - saplen); 1443*c7e4935fSss150715 #endif 1444*c7e4935fSss150715 1445*c7e4935fSss150715 (void) memcpy(dstbuf, sapp, saplen); 14467c478bd9Sstevel@tonic-gate } 1447