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 /* 22e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Data-Link Provider Interface (Version 2) 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate #include <stdio.h> 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/stat.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <unistd.h> 367c478bd9Sstevel@tonic-gate #include <poll.h> 377c478bd9Sstevel@tonic-gate #include <stropts.h> 387c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 397c478bd9Sstevel@tonic-gate #include <errno.h> 40c7e4935fSss150715 #include <alloca.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <ctype.h> 43948f2876Sss150715 #include <net/if_types.h> 44948f2876Sss150715 #include <netinet/arp.h> 45d62bc4baSyz147064 #include <libdladm.h> 46d62bc4baSyz147064 #include <libdllink.h> 477c478bd9Sstevel@tonic-gate #include <libdlpi.h> 48c7e4935fSss150715 #include <libintl.h> 49c7e4935fSss150715 #include <libinetutil.h> 50b127ac41SPhilip Kirk #include <dirent.h> 517c478bd9Sstevel@tonic-gate 52c7e4935fSss150715 #include "libdlpi_impl.h" 537c478bd9Sstevel@tonic-gate 54d62bc4baSyz147064 static int i_dlpi_open(const char *, int *, uint_t, boolean_t); 55c7e4935fSss150715 static int i_dlpi_style1_open(dlpi_impl_t *); 56c7e4935fSss150715 static int i_dlpi_style2_open(dlpi_impl_t *); 57c7e4935fSss150715 static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t); 58c7e4935fSss150715 static int i_dlpi_attach(dlpi_impl_t *); 59c7e4935fSss150715 static void i_dlpi_passive(dlpi_impl_t *); 607c478bd9Sstevel@tonic-gate 613ab45760Sss150715 static int i_dlpi_strputmsg(dlpi_impl_t *, const dlpi_msg_t *, const void *, 623ab45760Sss150715 size_t, int); 633ab45760Sss150715 static int i_dlpi_strgetmsg(dlpi_impl_t *, int, dlpi_msg_t *, t_uscalar_t, 643ab45760Sss150715 t_uscalar_t, size_t, void *, size_t *, size_t *); 65c7e4935fSss150715 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *, 66c7e4935fSss150715 size_t, int); 677c478bd9Sstevel@tonic-gate 68c7e4935fSss150715 static size_t i_dlpi_getprimsize(t_uscalar_t); 69c7e4935fSss150715 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t); 70c7e4935fSss150715 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t); 71c7e4935fSss150715 static uint_t i_dlpi_buildsap(uint8_t *, uint_t); 72c7e4935fSss150715 static void i_dlpi_writesap(void *, uint_t, uint_t); 733ab45760Sss150715 static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *); 743ab45760Sss150715 static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *); 753ab45760Sss150715 static void i_dlpi_deletenotifyid(dlpi_impl_t *); 76c7e4935fSss150715 77d62bc4baSyz147064 struct i_dlpi_walklink_arg { 78d62bc4baSyz147064 dlpi_walkfunc_t *fn; 79d62bc4baSyz147064 void *arg; 80d62bc4baSyz147064 }; 81d62bc4baSyz147064 82d62bc4baSyz147064 static int 83d62bc4baSyz147064 i_dlpi_walk_link(const char *name, void *arg) 84d62bc4baSyz147064 { 85d62bc4baSyz147064 struct i_dlpi_walklink_arg *warg = arg; 86d62bc4baSyz147064 87d62bc4baSyz147064 return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE : 88d62bc4baSyz147064 DLADM_WALK_CONTINUE); 89d62bc4baSyz147064 } 90d62bc4baSyz147064 91d62bc4baSyz147064 /*ARGSUSED*/ 92d62bc4baSyz147064 void 93d62bc4baSyz147064 dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags) 94d62bc4baSyz147064 { 95d62bc4baSyz147064 struct i_dlpi_walklink_arg warg; 96b127ac41SPhilip Kirk struct dirent *d; 97b127ac41SPhilip Kirk DIR *dp; 984ac67f02SAnurag S. Maskey dladm_handle_t handle; 99d62bc4baSyz147064 100d62bc4baSyz147064 warg.fn = fn; 101d62bc4baSyz147064 warg.arg = arg; 102d62bc4baSyz147064 103b127ac41SPhilip Kirk if (flags & DLPI_DEVIPNET) { 104b127ac41SPhilip Kirk if ((dp = opendir("/dev/ipnet")) == NULL) 105b127ac41SPhilip Kirk return; 106b127ac41SPhilip Kirk 107b127ac41SPhilip Kirk while ((d = readdir(dp)) != NULL) { 108b127ac41SPhilip Kirk if (d->d_name[0] == '.') 109b127ac41SPhilip Kirk continue; 110b127ac41SPhilip Kirk 111b127ac41SPhilip Kirk if (warg.fn(d->d_name, warg.arg)) 112b127ac41SPhilip Kirk break; 113b127ac41SPhilip Kirk } 114b127ac41SPhilip Kirk 115b127ac41SPhilip Kirk (void) closedir(dp); 116b127ac41SPhilip Kirk } else { 1174ac67f02SAnurag S. Maskey /* 1184ac67f02SAnurag S. Maskey * Rather than have libdlpi take the libdladm handle, 1194ac67f02SAnurag S. Maskey * open the handle here. 1204ac67f02SAnurag S. Maskey */ 1214ac67f02SAnurag S. Maskey if (dladm_open(&handle) != DLADM_STATUS_OK) 1224ac67f02SAnurag S. Maskey return; 1234ac67f02SAnurag S. Maskey 1244ac67f02SAnurag S. Maskey (void) dladm_walk(i_dlpi_walk_link, handle, &warg, 1254ac67f02SAnurag S. Maskey DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1264ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE); 1274ac67f02SAnurag S. Maskey 1284ac67f02SAnurag S. Maskey dladm_close(handle); 129d62bc4baSyz147064 } 130b127ac41SPhilip Kirk } 131d62bc4baSyz147064 132c7e4935fSss150715 int 133c7e4935fSss150715 dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags) 134c7e4935fSss150715 { 135b127ac41SPhilip Kirk int retval, on = 1; 136c7e4935fSss150715 ifspec_t ifsp; 137c7e4935fSss150715 dlpi_impl_t *dip; 138c7e4935fSss150715 139c7e4935fSss150715 /* 140c7e4935fSss150715 * Validate linkname, fail if logical unit number (lun) is specified, 141c7e4935fSss150715 * otherwise decompose the contents into ifsp. 142c7e4935fSss150715 */ 143c7e4935fSss150715 if (linkname == NULL || (strchr(linkname, ':') != NULL) || 144c7e4935fSss150715 !ifparse_ifspec(linkname, &ifsp)) 145c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 146c7e4935fSss150715 147b127ac41SPhilip Kirk /* 148b127ac41SPhilip Kirk * Ensure flags values are sane. 149b127ac41SPhilip Kirk */ 150b127ac41SPhilip Kirk if ((flags & (DLPI_DEVIPNET|DLPI_DEVONLY)) == 151b127ac41SPhilip Kirk (DLPI_DEVIPNET|DLPI_DEVONLY)) 152b127ac41SPhilip Kirk return (DLPI_EINVAL); 153b127ac41SPhilip Kirk 154c7e4935fSss150715 /* Allocate a new dlpi_impl_t. */ 155c7e4935fSss150715 if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL) 156c7e4935fSss150715 return (DL_SYSERR); 157c7e4935fSss150715 158c7e4935fSss150715 /* Fill in known/default libdlpi handle values. */ 159c7e4935fSss150715 dip->dli_timeout = DLPI_DEF_TIMEOUT; 160c7e4935fSss150715 dip->dli_ppa = ifsp.ifsp_ppa; 161c7e4935fSss150715 dip->dli_oflags = flags; 1623ab45760Sss150715 dip->dli_notifylistp = NULL; 1633ab45760Sss150715 dip->dli_note_processing = B_FALSE; 164d62bc4baSyz147064 if (getenv("DLPI_DEVONLY") != NULL) 165d62bc4baSyz147064 dip->dli_oflags |= DLPI_DEVONLY; 166c7e4935fSss150715 167c7e4935fSss150715 /* Copy linkname provided to the function. */ 168c7e4935fSss150715 if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >= 169c7e4935fSss150715 sizeof (dip->dli_linkname)) { 170c7e4935fSss150715 free(dip); 171c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 172c7e4935fSss150715 } 173c7e4935fSss150715 174c7e4935fSss150715 /* Copy provider name. */ 175c7e4935fSss150715 (void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm, 176c7e4935fSss150715 sizeof (dip->dli_provider)); 177c7e4935fSss150715 178c7e4935fSss150715 /* 179c7e4935fSss150715 * Special case: DLPI_SERIAL flag is set to indicate a synchronous 180c7e4935fSss150715 * serial line interface (see syncinit(1M), syncstat(1M), 181c7e4935fSss150715 * syncloop(1M)), which is not a DLPI link. 182c7e4935fSss150715 */ 183c7e4935fSss150715 if (dip->dli_oflags & DLPI_SERIAL) { 184c7e4935fSss150715 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) { 185c7e4935fSss150715 free(dip); 186c7e4935fSss150715 return (retval); 187c7e4935fSss150715 } 188c7e4935fSss150715 189c7e4935fSss150715 *dhp = (dlpi_handle_t)dip; 190c7e4935fSss150715 return (retval); 191c7e4935fSss150715 } 192c7e4935fSss150715 193d62bc4baSyz147064 if ((retval = i_dlpi_style1_open(dip)) != DLPI_SUCCESS) { 194d62bc4baSyz147064 if (retval == DLPI_ENOTSTYLE2) { 195d62bc4baSyz147064 /* 196d62bc4baSyz147064 * The error code indicates not to continue the 197d62bc4baSyz147064 * style-2 open. Change the error code back to 198d62bc4baSyz147064 * DL_SYSERR, so that one would know the cause 199d62bc4baSyz147064 * of failure from errno. 200d62bc4baSyz147064 */ 201d62bc4baSyz147064 retval = DL_SYSERR; 202b127ac41SPhilip Kirk } else if (!(dip->dli_oflags & DLPI_DEVIPNET)) { 203d62bc4baSyz147064 retval = i_dlpi_style2_open(dip); 204d62bc4baSyz147064 } 205d62bc4baSyz147064 if (retval != DLPI_SUCCESS) { 206c7e4935fSss150715 free(dip); 207c7e4935fSss150715 return (retval); 208c7e4935fSss150715 } 209c7e4935fSss150715 } 210c7e4935fSss150715 211c7e4935fSss150715 if (dip->dli_oflags & DLPI_PASSIVE) 212c7e4935fSss150715 i_dlpi_passive(dip); 213c7e4935fSss150715 214c7e4935fSss150715 if ((dip->dli_oflags & DLPI_RAW) && 215c7e4935fSss150715 ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) { 216c7e4935fSss150715 dlpi_close((dlpi_handle_t)dip); 217c7e4935fSss150715 return (DLPI_ERAWNOTSUP); 218c7e4935fSss150715 } 219c7e4935fSss150715 220b127ac41SPhilip Kirk if ((dip->dli_oflags & DLPI_IPNETINFO) && 221b127ac41SPhilip Kirk ioctl(dip->dli_fd, DLIOCIPNETINFO, &on) < 0) { 222b127ac41SPhilip Kirk dlpi_close((dlpi_handle_t)dip); 223b127ac41SPhilip Kirk return (DLPI_EIPNETINFONOTSUP); 224b127ac41SPhilip Kirk } 225b127ac41SPhilip Kirk 226c7e4935fSss150715 /* 227c7e4935fSss150715 * We intentionally do not care if this request fails, as this 228c7e4935fSss150715 * indicates the underlying DLPI device does not support Native mode 229c7e4935fSss150715 * (pre-GLDV3 device drivers). 230c7e4935fSss150715 */ 231c7e4935fSss150715 if (dip->dli_oflags & DLPI_NATIVE) { 232c7e4935fSss150715 if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0) 233c7e4935fSss150715 dip->dli_mactype = retval; 234c7e4935fSss150715 } 235c7e4935fSss150715 236c7e4935fSss150715 *dhp = (dlpi_handle_t)dip; 237c7e4935fSss150715 return (DLPI_SUCCESS); 238c7e4935fSss150715 } 239c7e4935fSss150715 240c7e4935fSss150715 void 241c7e4935fSss150715 dlpi_close(dlpi_handle_t dh) 242c7e4935fSss150715 { 243c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 2443ab45760Sss150715 dlpi_notifyent_t *next, *dnp; 245c7e4935fSss150715 246c7e4935fSss150715 if (dip != NULL) { 2473ab45760Sss150715 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = next) { 2483ab45760Sss150715 next = dnp->dln_next; 2493ab45760Sss150715 free(dnp); 2503ab45760Sss150715 } 2513ab45760Sss150715 252c7e4935fSss150715 (void) close(dip->dli_fd); 253c7e4935fSss150715 free(dip); 254c7e4935fSss150715 } 255c7e4935fSss150715 } 256c7e4935fSss150715 257c7e4935fSss150715 /* 258c7e4935fSss150715 * NOTE: The opt argument must be zero and is reserved for future use to extend 259c7e4935fSss150715 * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)). 260c7e4935fSss150715 */ 261c7e4935fSss150715 int 262c7e4935fSss150715 dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt) 263c7e4935fSss150715 { 264c7e4935fSss150715 int retval; 265c7e4935fSss150715 dlpi_msg_t req, ack; 266c7e4935fSss150715 dl_info_ack_t *infoackp; 267c7e4935fSss150715 uint8_t *sapp, *addrp; 268c7e4935fSss150715 caddr_t ackendp, datap; 269c7e4935fSss150715 t_uscalar_t dataoff, datalen; 270c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 271c7e4935fSss150715 272c7e4935fSss150715 if (dip == NULL) 273c7e4935fSss150715 return (DLPI_EINHANDLE); 274c7e4935fSss150715 275c7e4935fSss150715 if (infop == NULL || opt != 0) 276c7e4935fSss150715 return (DLPI_EINVAL); 277c7e4935fSss150715 278c7e4935fSss150715 (void) memset(infop, 0, sizeof (dlpi_info_t)); 279c7e4935fSss150715 280c7e4935fSss150715 /* Set QoS range parameters to default unsupported value. */ 281c7e4935fSss150715 infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN; 282c7e4935fSss150715 infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN; 283c7e4935fSss150715 infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN; 284c7e4935fSss150715 infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN; 285c7e4935fSss150715 infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN; 286c7e4935fSss150715 infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN; 287c7e4935fSss150715 infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN; 288c7e4935fSss150715 infop->di_qos_range.dl_residual_error = DL_UNKNOWN; 289c7e4935fSss150715 290c7e4935fSss150715 /* Set QoS parameters to default unsupported value. */ 291c7e4935fSss150715 infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN; 292c7e4935fSss150715 infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN; 293c7e4935fSss150715 infop->di_qos_sel.dl_priority = DL_UNKNOWN; 294c7e4935fSss150715 infop->di_qos_sel.dl_protection = DL_UNKNOWN; 295c7e4935fSss150715 infop->di_qos_sel.dl_residual_error = DL_UNKNOWN; 296c7e4935fSss150715 297c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_INFO_REQ); 298c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_INFO_ACK); 299c7e4935fSss150715 300c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI); 301c7e4935fSss150715 if (retval != DLPI_SUCCESS) 302c7e4935fSss150715 return (retval); 303c7e4935fSss150715 304c7e4935fSss150715 infoackp = &(ack.dlm_msg->info_ack); 305c7e4935fSss150715 if (infoackp->dl_version != DL_VERSION_2) 306c7e4935fSss150715 return (DLPI_EVERNOTSUP); 307c7e4935fSss150715 308c7e4935fSss150715 if (infoackp->dl_service_mode != DL_CLDLS) 309c7e4935fSss150715 return (DLPI_EMODENOTSUP); 310c7e4935fSss150715 311c7e4935fSss150715 dip->dli_style = infoackp->dl_provider_style; 312c7e4935fSss150715 dip->dli_mactype = infoackp->dl_mac_type; 313c7e4935fSss150715 314c7e4935fSss150715 ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz; 315c7e4935fSss150715 316c7e4935fSss150715 /* Check and save QoS selection information, if any. */ 317c7e4935fSss150715 datalen = infoackp->dl_qos_length; 318c7e4935fSss150715 dataoff = infoackp->dl_qos_offset; 319c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 320c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 321c7e4935fSss150715 if (datalen > sizeof (dl_qos_cl_sel1_t) || 322c7e4935fSss150715 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 323c7e4935fSss150715 return (DLPI_EBADMSG); 324c7e4935fSss150715 325c7e4935fSss150715 (void) memcpy(&infop->di_qos_sel, datap, datalen); 326c7e4935fSss150715 if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1) 327c7e4935fSss150715 return (DLPI_EMODENOTSUP); 328c7e4935fSss150715 } 329c7e4935fSss150715 330c7e4935fSss150715 /* Check and save QoS range information, if any. */ 331c7e4935fSss150715 datalen = infoackp->dl_qos_range_length; 332c7e4935fSss150715 dataoff = infoackp->dl_qos_range_offset; 333c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 334c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 335c7e4935fSss150715 if (datalen > sizeof (dl_qos_cl_range1_t) || 336c7e4935fSss150715 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 337c7e4935fSss150715 return (DLPI_EBADMSG); 338c7e4935fSss150715 339c7e4935fSss150715 (void) memcpy(&infop->di_qos_range, datap, datalen); 340c7e4935fSss150715 if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1) 341c7e4935fSss150715 return (DLPI_EMODENOTSUP); 342c7e4935fSss150715 } 343c7e4935fSss150715 344c7e4935fSss150715 /* Check and save physical address and SAP information. */ 345c7e4935fSss150715 dip->dli_saplen = abs(infoackp->dl_sap_length); 346c7e4935fSss150715 dip->dli_sapbefore = (infoackp->dl_sap_length > 0); 347c7e4935fSss150715 infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen; 348c7e4935fSss150715 349c7e4935fSss150715 if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX || 350c7e4935fSss150715 dip->dli_saplen > DLPI_SAPLEN_MAX) 351c7e4935fSss150715 return (DL_BADADDR); 352c7e4935fSss150715 353c7e4935fSss150715 dataoff = infoackp->dl_addr_offset; 354c7e4935fSss150715 datalen = infoackp->dl_addr_length; 355c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 356c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 357c7e4935fSss150715 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 358c7e4935fSss150715 return (DLPI_EBADMSG); 359c7e4935fSss150715 360c7e4935fSss150715 sapp = addrp = (uint8_t *)datap; 361c7e4935fSss150715 if (dip->dli_sapbefore) 362c7e4935fSss150715 addrp += dip->dli_saplen; 363c7e4935fSss150715 else 364c7e4935fSss150715 sapp += infop->di_physaddrlen; 365c7e4935fSss150715 366c7e4935fSss150715 (void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen); 367c7e4935fSss150715 infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen); 368c7e4935fSss150715 } 369c7e4935fSss150715 370c7e4935fSss150715 /* Check and save broadcast address information, if any. */ 371c7e4935fSss150715 datalen = infoackp->dl_brdcst_addr_length; 372c7e4935fSss150715 dataoff = infoackp->dl_brdcst_addr_offset; 373c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 374c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff; 375c7e4935fSss150715 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 376c7e4935fSss150715 return (DLPI_EBADMSG); 377c7e4935fSss150715 if (datalen != infop->di_physaddrlen) 378c7e4935fSss150715 return (DL_BADADDR); 379c7e4935fSss150715 380c7e4935fSss150715 infop->di_bcastaddrlen = datalen; 381c7e4935fSss150715 (void) memcpy(infop->di_bcastaddr, datap, datalen); 382c7e4935fSss150715 } 383c7e4935fSss150715 384c7e4935fSss150715 infop->di_max_sdu = infoackp->dl_max_sdu; 385c7e4935fSss150715 infop->di_min_sdu = infoackp->dl_min_sdu; 386c7e4935fSss150715 infop->di_state = infoackp->dl_current_state; 387c7e4935fSss150715 infop->di_mactype = infoackp->dl_mac_type; 388c7e4935fSss150715 389c7e4935fSss150715 /* Information retrieved from the handle. */ 390c7e4935fSss150715 (void) strlcpy(infop->di_linkname, dip->dli_linkname, 391c7e4935fSss150715 sizeof (infop->di_linkname)); 392c7e4935fSss150715 infop->di_timeout = dip->dli_timeout; 393c7e4935fSss150715 394c7e4935fSss150715 return (DLPI_SUCCESS); 395c7e4935fSss150715 } 396c7e4935fSss150715 397c7e4935fSss150715 /* 398c7e4935fSss150715 * This function parses 'linkname' and stores the 'provider' name and 'PPA'. 399c7e4935fSss150715 */ 400c7e4935fSss150715 int 401c7e4935fSss150715 dlpi_parselink(const char *linkname, char *provider, uint_t *ppa) 402c7e4935fSss150715 { 403e7801d59Ssowmini dladm_status_t status; 404c7e4935fSss150715 405e7801d59Ssowmini status = dladm_parselink(linkname, provider, ppa); 406e7801d59Ssowmini 407e7801d59Ssowmini if (status != DLADM_STATUS_OK) 408c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 409c7e4935fSss150715 410c7e4935fSss150715 return (DLPI_SUCCESS); 411c7e4935fSss150715 } 412c7e4935fSss150715 413c7e4935fSss150715 /* 414c7e4935fSss150715 * This function takes a provider name and a PPA and stores a full linkname 415c7e4935fSss150715 * as 'linkname'. If 'provider' already is a full linkname 'provider' name 416c7e4935fSss150715 * is stored in 'linkname'. 417c7e4935fSss150715 */ 418c7e4935fSss150715 int 419c7e4935fSss150715 dlpi_makelink(char *linkname, const char *provider, uint_t ppa) 420c7e4935fSss150715 { 421c7e4935fSss150715 int provlen = strlen(provider); 422c7e4935fSss150715 423c7e4935fSss150715 if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX) 424c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL); 425c7e4935fSss150715 426c7e4935fSss150715 if (!isdigit(provider[provlen - 1])) { 427c7e4935fSss150715 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider, 428c7e4935fSss150715 ppa); 429c7e4935fSss150715 } else { 430c7e4935fSss150715 (void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX); 431c7e4935fSss150715 } 432c7e4935fSss150715 433c7e4935fSss150715 return (DLPI_SUCCESS); 434c7e4935fSss150715 } 435c7e4935fSss150715 436c7e4935fSss150715 int 437c7e4935fSss150715 dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap) 438c7e4935fSss150715 { 439c7e4935fSss150715 int retval; 440c7e4935fSss150715 dlpi_msg_t req, ack; 441c7e4935fSss150715 dl_bind_req_t *bindreqp; 442c7e4935fSss150715 dl_bind_ack_t *bindackp; 443c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 444c7e4935fSss150715 445c7e4935fSss150715 if (dip == NULL) 446c7e4935fSss150715 return (DLPI_EINHANDLE); 447c7e4935fSss150715 448c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_BIND_REQ); 449c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_BIND_ACK); 450c7e4935fSss150715 bindreqp = &(req.dlm_msg->bind_req); 451c7e4935fSss150715 452c7e4935fSss150715 /* 453c7e4935fSss150715 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on 454c7e4935fSss150715 * other interface types (SAP 0 has special significance on token ring). 455c7e4935fSss150715 */ 456c7e4935fSss150715 if (sap == DLPI_ANY_SAP) 457c7e4935fSss150715 bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0); 458c7e4935fSss150715 else 459c7e4935fSss150715 bindreqp->dl_sap = sap; 460c7e4935fSss150715 461c7e4935fSss150715 bindreqp->dl_service_mode = DL_CLDLS; 462c7e4935fSss150715 bindreqp->dl_conn_mgmt = 0; 463c7e4935fSss150715 bindreqp->dl_max_conind = 0; 464c7e4935fSss150715 bindreqp->dl_xidtest_flg = 0; 465c7e4935fSss150715 466c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0); 467c7e4935fSss150715 if (retval != DLPI_SUCCESS) 468c7e4935fSss150715 return (retval); 469c7e4935fSss150715 470c7e4935fSss150715 bindackp = &(ack.dlm_msg->bind_ack); 471c7e4935fSss150715 /* 472c7e4935fSss150715 * Received a DLPI_BIND_ACK, now verify that the bound SAP 473c7e4935fSss150715 * is equal to the SAP requested. Some DLPI MAC type may bind 474c7e4935fSss150715 * to a different SAP than requested, in this case 'boundsap' 475c7e4935fSss150715 * returns the actual bound SAP. For the case where 'boundsap' 476c7e4935fSss150715 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails. 477c7e4935fSss150715 */ 478c7e4935fSss150715 if (boundsap != NULL) { 479c7e4935fSss150715 *boundsap = bindackp->dl_sap; 480c7e4935fSss150715 } else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) { 481c7e4935fSss150715 if (dlpi_unbind(dh) != DLPI_SUCCESS) 482c7e4935fSss150715 return (DLPI_FAILURE); 483c7e4935fSss150715 else 484c7e4935fSss150715 return (DLPI_EUNAVAILSAP); 485c7e4935fSss150715 } 486c7e4935fSss150715 487c7e4935fSss150715 dip->dli_sap = bindackp->dl_sap; /* save sap value in handle */ 488c7e4935fSss150715 return (DLPI_SUCCESS); 489c7e4935fSss150715 } 490c7e4935fSss150715 491c7e4935fSss150715 int 492c7e4935fSss150715 dlpi_unbind(dlpi_handle_t dh) 493c7e4935fSss150715 { 494c7e4935fSss150715 dlpi_msg_t req, ack; 495c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 496c7e4935fSss150715 497c7e4935fSss150715 if (dip == NULL) 498c7e4935fSss150715 return (DLPI_EINHANDLE); 499c7e4935fSss150715 500c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_UNBIND_REQ); 501c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 502c7e4935fSss150715 503c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 504c7e4935fSss150715 } 505c7e4935fSss150715 506c7e4935fSss150715 /* 507c7e4935fSss150715 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and 508c7e4935fSss150715 * based on the "op" value, multicast address is enabled/disabled. 509c7e4935fSss150715 */ 510c7e4935fSss150715 static int 511c7e4935fSss150715 i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp, 512c7e4935fSss150715 size_t addrlen) 513c7e4935fSss150715 { 514c7e4935fSss150715 dlpi_msg_t req, ack; 515c7e4935fSss150715 dl_enabmulti_req_t *multireqp; 516c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 517c7e4935fSss150715 518c7e4935fSss150715 if (dip == NULL) 519c7e4935fSss150715 return (DLPI_EINHANDLE); 520c7e4935fSss150715 521c7e4935fSss150715 if (addrlen > DLPI_PHYSADDR_MAX) 522c7e4935fSss150715 return (DLPI_EINVAL); 523c7e4935fSss150715 524c7e4935fSss150715 DLPI_MSG_CREATE(req, op); 525c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 526c7e4935fSss150715 527c7e4935fSss150715 multireqp = &(req.dlm_msg->enabmulti_req); 528c7e4935fSss150715 multireqp->dl_addr_length = addrlen; 529c7e4935fSss150715 multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t); 530c7e4935fSss150715 (void) memcpy(&multireqp[1], addrp, addrlen); 531c7e4935fSss150715 532c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 533c7e4935fSss150715 } 534c7e4935fSss150715 535c7e4935fSss150715 int 536c7e4935fSss150715 dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen) 537c7e4935fSss150715 { 538c7e4935fSss150715 return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen)); 539c7e4935fSss150715 } 540c7e4935fSss150715 541c7e4935fSss150715 int 542c7e4935fSss150715 dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen) 543c7e4935fSss150715 { 544c7e4935fSss150715 return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen)); 545c7e4935fSss150715 } 546c7e4935fSss150715 547c7e4935fSss150715 /* 548c7e4935fSss150715 * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based 549c7e4935fSss150715 * on the value of 'op', promiscuous mode is turned on/off at the specified 550c7e4935fSss150715 * 'level'. 551c7e4935fSss150715 */ 552c7e4935fSss150715 static int 553c7e4935fSss150715 i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level) 554c7e4935fSss150715 { 555c7e4935fSss150715 dlpi_msg_t req, ack; 556c7e4935fSss150715 dl_promiscon_req_t *promiscreqp; 557c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 558c7e4935fSss150715 559c7e4935fSss150715 if (dip == NULL) 560c7e4935fSss150715 return (DLPI_EINHANDLE); 561c7e4935fSss150715 562c7e4935fSss150715 DLPI_MSG_CREATE(req, op); 563c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 564c7e4935fSss150715 565c7e4935fSss150715 promiscreqp = &(req.dlm_msg->promiscon_req); 566c7e4935fSss150715 promiscreqp->dl_level = level; 567c7e4935fSss150715 568c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 569c7e4935fSss150715 } 570c7e4935fSss150715 571c7e4935fSss150715 int 572c7e4935fSss150715 dlpi_promiscon(dlpi_handle_t dh, uint_t level) 573c7e4935fSss150715 { 574c7e4935fSss150715 return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level)); 575c7e4935fSss150715 } 576c7e4935fSss150715 577c7e4935fSss150715 int 578c7e4935fSss150715 dlpi_promiscoff(dlpi_handle_t dh, uint_t level) 579c7e4935fSss150715 { 580c7e4935fSss150715 return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level)); 581c7e4935fSss150715 } 582c7e4935fSss150715 583c7e4935fSss150715 int 584c7e4935fSss150715 dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp) 585c7e4935fSss150715 { 586c7e4935fSss150715 int retval; 587c7e4935fSss150715 dlpi_msg_t req, ack; 588c7e4935fSss150715 dl_phys_addr_req_t *physreqp; 589c7e4935fSss150715 dl_phys_addr_ack_t *physackp; 590c7e4935fSss150715 t_uscalar_t dataoff, datalen; 591c7e4935fSss150715 caddr_t datap, physackendp; 592c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 593c7e4935fSss150715 594c7e4935fSss150715 if (dip == NULL) 595c7e4935fSss150715 return (DLPI_EINHANDLE); 596c7e4935fSss150715 597c7e4935fSss150715 if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX) 598c7e4935fSss150715 return (DLPI_EINVAL); 599c7e4935fSss150715 600c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ); 601c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK); 602c7e4935fSss150715 603c7e4935fSss150715 physreqp = &(req.dlm_msg->physaddr_req); 604c7e4935fSss150715 physreqp->dl_addr_type = type; 605c7e4935fSss150715 606c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0); 607c7e4935fSss150715 if (retval != DLPI_SUCCESS) 608c7e4935fSss150715 return (retval); 609c7e4935fSss150715 610c7e4935fSss150715 /* Received DL_PHYS_ADDR_ACK, store the physical address and length. */ 611c7e4935fSss150715 physackp = &(ack.dlm_msg->physaddr_ack); 612c7e4935fSss150715 physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz; 613c7e4935fSss150715 dataoff = physackp->dl_addr_offset; 614c7e4935fSss150715 datalen = physackp->dl_addr_length; 615c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 616c7e4935fSss150715 datap = (caddr_t)physackp + dataoff; 617c7e4935fSss150715 if (datalen > DLPI_PHYSADDR_MAX) 618c7e4935fSss150715 return (DL_BADADDR); 619c7e4935fSss150715 if (dataoff < DL_PHYS_ADDR_ACK_SIZE || 620c7e4935fSss150715 datap + datalen > physackendp) 621c7e4935fSss150715 return (DLPI_EBADMSG); 622c7e4935fSss150715 623c7e4935fSss150715 *addrlenp = physackp->dl_addr_length; 624c7e4935fSss150715 (void) memcpy(addrp, datap, datalen); 625c7e4935fSss150715 } else { 626c7e4935fSss150715 *addrlenp = datalen; 627c7e4935fSss150715 } 628c7e4935fSss150715 629c7e4935fSss150715 return (DLPI_SUCCESS); 630c7e4935fSss150715 } 631c7e4935fSss150715 632c7e4935fSss150715 int 633c7e4935fSss150715 dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp, 634c7e4935fSss150715 size_t addrlen) 635c7e4935fSss150715 { 636c7e4935fSss150715 dlpi_msg_t req, ack; 637c7e4935fSss150715 dl_set_phys_addr_req_t *setphysreqp; 638c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 639c7e4935fSss150715 640c7e4935fSss150715 if (dip == NULL) 641c7e4935fSss150715 return (DLPI_EINHANDLE); 642c7e4935fSss150715 643c7e4935fSss150715 if (addrp == NULL || type != DL_CURR_PHYS_ADDR || 644c7e4935fSss150715 addrlen > DLPI_PHYSADDR_MAX) 645c7e4935fSss150715 return (DLPI_EINVAL); 646c7e4935fSss150715 647c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ); 648c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 649c7e4935fSss150715 650c7e4935fSss150715 setphysreqp = &(req.dlm_msg->set_physaddr_req); 651c7e4935fSss150715 setphysreqp->dl_addr_length = addrlen; 652c7e4935fSss150715 setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); 653c7e4935fSss150715 (void) memcpy(&setphysreqp[1], addrp, addrlen); 654c7e4935fSss150715 655c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 656c7e4935fSss150715 } 657c7e4935fSss150715 658c7e4935fSss150715 int 659c7e4935fSss150715 dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen, 660c7e4935fSss150715 const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp) 661c7e4935fSss150715 { 662c7e4935fSss150715 dlpi_msg_t req; 663c7e4935fSss150715 dl_unitdata_req_t *udatareqp; 664c7e4935fSss150715 uint_t sap; 665c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 666c7e4935fSss150715 667c7e4935fSss150715 if (dip == NULL) 668c7e4935fSss150715 return (DLPI_EINHANDLE); 669c7e4935fSss150715 670c7e4935fSss150715 if (dip->dli_oflags & DLPI_RAW) 6713ab45760Sss150715 return (i_dlpi_strputmsg(dip, NULL, msgbuf, msglen, 0)); 672c7e4935fSss150715 673948f2876Sss150715 if ((daddrlen > 0 && daddrp == NULL) || daddrlen > DLPI_PHYSADDR_MAX) 674c7e4935fSss150715 return (DLPI_EINVAL); 675c7e4935fSss150715 676c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_UNITDATA_REQ); 677c7e4935fSss150715 udatareqp = &(req.dlm_msg->unitdata_req); 678c7e4935fSss150715 679c7e4935fSss150715 /* Set priority to default priority range. */ 680c7e4935fSss150715 udatareqp->dl_priority.dl_min = 0; 681c7e4935fSss150715 udatareqp->dl_priority.dl_max = 0; 682c7e4935fSss150715 683c7e4935fSss150715 /* Use SAP value if specified otherwise use bound SAP value. */ 684c7e4935fSss150715 if (sendp != NULL) { 685c7e4935fSss150715 sap = sendp->dsi_sap; 686c7e4935fSss150715 if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE) 687c7e4935fSss150715 udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min; 688c7e4935fSss150715 if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE) 689c7e4935fSss150715 udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max; 690c7e4935fSss150715 } else { 691c7e4935fSss150715 sap = dip->dli_sap; 692c7e4935fSss150715 } 693c7e4935fSss150715 694c7e4935fSss150715 udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen; 695c7e4935fSss150715 udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE; 696c7e4935fSss150715 697c7e4935fSss150715 /* 698c7e4935fSss150715 * Since `daddrp' only has the link-layer destination address, 699c7e4935fSss150715 * we must prepend or append the SAP (according to dli_sapbefore) 700c7e4935fSss150715 * to make a full DLPI address. 701c7e4935fSss150715 */ 702c7e4935fSss150715 if (dip->dli_sapbefore) { 703c7e4935fSss150715 i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen); 704c7e4935fSss150715 (void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen, 705c7e4935fSss150715 daddrp, daddrlen); 706c7e4935fSss150715 } else { 707c7e4935fSss150715 (void) memcpy(&udatareqp[1], daddrp, daddrlen); 708c7e4935fSss150715 i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap, 709c7e4935fSss150715 dip->dli_saplen); 710c7e4935fSss150715 } 711c7e4935fSss150715 7123ab45760Sss150715 return (i_dlpi_strputmsg(dip, &req, msgbuf, msglen, 0)); 713c7e4935fSss150715 } 714c7e4935fSss150715 715c7e4935fSss150715 int 716c7e4935fSss150715 dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf, 717c7e4935fSss150715 size_t *msglenp, int msec, dlpi_recvinfo_t *recvp) 718c7e4935fSss150715 { 719c7e4935fSss150715 int retval; 720c7e4935fSss150715 dlpi_msg_t ind; 721c7e4935fSss150715 size_t totmsglen; 722c7e4935fSss150715 dl_unitdata_ind_t *udatap; 723c7e4935fSss150715 t_uscalar_t dataoff, datalen; 724c7e4935fSss150715 caddr_t datap, indendp; 725c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 726c7e4935fSss150715 727c7e4935fSss150715 if (dip == NULL) 728c7e4935fSss150715 return (DLPI_EINHANDLE); 729c7e4935fSss150715 /* 730c7e4935fSss150715 * If handle is in raw mode ignore everything except total message 731c7e4935fSss150715 * length. 732c7e4935fSss150715 */ 733c7e4935fSss150715 if (dip->dli_oflags & DLPI_RAW) { 7343ab45760Sss150715 retval = i_dlpi_strgetmsg(dip, msec, NULL, 0, 0, 0, msgbuf, 7353ab45760Sss150715 msglenp, &totmsglen); 736c7e4935fSss150715 737c7e4935fSss150715 if (retval == DLPI_SUCCESS && recvp != NULL) 738c7e4935fSss150715 recvp->dri_totmsglen = totmsglen; 739c7e4935fSss150715 return (retval); 740c7e4935fSss150715 } 741c7e4935fSss150715 742c7e4935fSss150715 DLPI_MSG_CREATE(ind, DL_UNITDATA_IND); 743c7e4935fSss150715 udatap = &(ind.dlm_msg->unitdata_ind); 744c7e4935fSss150715 indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz; 745c7e4935fSss150715 7463ab45760Sss150715 if ((retval = i_dlpi_strgetmsg(dip, msec, &ind, DL_UNITDATA_IND, 7473ab45760Sss150715 DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, msgbuf, 7483ab45760Sss150715 msglenp, &totmsglen)) != DLPI_SUCCESS) 749c7e4935fSss150715 return (retval); 750c7e4935fSss150715 751c7e4935fSss150715 /* 752c7e4935fSss150715 * If DLPI link provides source address, store source address in 753c7e4935fSss150715 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0. 754c7e4935fSss150715 */ 755c7e4935fSss150715 if (saddrp != NULL && saddrlenp != NULL) { 756c7e4935fSss150715 if (*saddrlenp < DLPI_PHYSADDR_MAX) 757c7e4935fSss150715 return (DLPI_EINVAL); 758c7e4935fSss150715 759c7e4935fSss150715 dataoff = udatap->dl_src_addr_offset; 760c7e4935fSss150715 datalen = udatap->dl_src_addr_length; 761c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 762c7e4935fSss150715 datap = (caddr_t)udatap + dataoff; 763c7e4935fSss150715 if (dataoff < DL_UNITDATA_IND_SIZE || 764c7e4935fSss150715 datap + datalen > indendp) 765c7e4935fSss150715 return (DLPI_EBADMSG); 766c7e4935fSss150715 767c7e4935fSss150715 *saddrlenp = datalen - dip->dli_saplen; 768c7e4935fSss150715 if (*saddrlenp > DLPI_PHYSADDR_MAX) 769c7e4935fSss150715 return (DL_BADADDR); 770c7e4935fSss150715 771c7e4935fSss150715 if (dip->dli_sapbefore) 772c7e4935fSss150715 datap += dip->dli_saplen; 773c7e4935fSss150715 (void) memcpy(saddrp, datap, *saddrlenp); 774c7e4935fSss150715 } else { 775c7e4935fSss150715 *saddrlenp = 0; 776c7e4935fSss150715 } 777c7e4935fSss150715 } 778c7e4935fSss150715 779c7e4935fSss150715 /* 780c7e4935fSss150715 * If destination address requested, check and save destination 781c7e4935fSss150715 * address, if any. 782c7e4935fSss150715 */ 783c7e4935fSss150715 if (recvp != NULL) { 784c7e4935fSss150715 dataoff = udatap->dl_dest_addr_offset; 785c7e4935fSss150715 datalen = udatap->dl_dest_addr_length; 786c7e4935fSss150715 if (dataoff != 0 && datalen != 0) { 787c7e4935fSss150715 datap = (caddr_t)udatap + dataoff; 788c7e4935fSss150715 if (dataoff < DL_UNITDATA_IND_SIZE || 789c7e4935fSss150715 datap + datalen > indendp) 790c7e4935fSss150715 return (DLPI_EBADMSG); 791c7e4935fSss150715 792c7e4935fSss150715 recvp->dri_destaddrlen = datalen - dip->dli_saplen; 793c7e4935fSss150715 if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX) 794c7e4935fSss150715 return (DL_BADADDR); 795c7e4935fSss150715 796c7e4935fSss150715 if (dip->dli_sapbefore) 797c7e4935fSss150715 datap += dip->dli_saplen; 798c7e4935fSss150715 (void) memcpy(recvp->dri_destaddr, datap, 799c7e4935fSss150715 recvp->dri_destaddrlen); 800c7e4935fSss150715 } else { 801c7e4935fSss150715 recvp->dri_destaddrlen = 0; 802c7e4935fSss150715 } 803c7e4935fSss150715 8045494fa53Sss150715 recvp->dri_destaddrtype = udatap->dl_group_address; 805c7e4935fSss150715 recvp->dri_totmsglen = totmsglen; 806c7e4935fSss150715 } 807c7e4935fSss150715 808c7e4935fSss150715 return (DLPI_SUCCESS); 809c7e4935fSss150715 } 810c7e4935fSss150715 811c7e4935fSss150715 int 8123ab45760Sss150715 dlpi_enabnotify(dlpi_handle_t dh, uint_t notes, dlpi_notifyfunc_t *funcp, 8133ab45760Sss150715 void *arg, dlpi_notifyid_t *id) 8143ab45760Sss150715 { 8153ab45760Sss150715 int retval; 8163ab45760Sss150715 dlpi_msg_t req, ack; 8173ab45760Sss150715 dl_notify_req_t *notifyreqp; 8183ab45760Sss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 8193ab45760Sss150715 dlpi_notifyent_t *newnotifp; 8203ab45760Sss150715 dlpi_info_t dlinfo; 8213ab45760Sss150715 8223ab45760Sss150715 if (dip == NULL) 8233ab45760Sss150715 return (DLPI_EINHANDLE); 8243ab45760Sss150715 8253ab45760Sss150715 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0); 8263ab45760Sss150715 if (retval != DLPI_SUCCESS) 8273ab45760Sss150715 return (retval); 8283ab45760Sss150715 8293ab45760Sss150715 if (dip->dli_note_processing) 8303ab45760Sss150715 return (DLPI_FAILURE); 8313ab45760Sss150715 8323ab45760Sss150715 if (funcp == NULL || id == NULL) 8333ab45760Sss150715 return (DLPI_EINVAL); 8343ab45760Sss150715 8353ab45760Sss150715 if ((~DLPI_NOTIFICATION_TYPES & notes) || 8363ab45760Sss150715 !(notes & DLPI_NOTIFICATION_TYPES)) 8373ab45760Sss150715 return (DLPI_ENOTEINVAL); 8383ab45760Sss150715 8393ab45760Sss150715 DLPI_MSG_CREATE(req, DL_NOTIFY_REQ); 8403ab45760Sss150715 DLPI_MSG_CREATE(ack, DL_NOTIFY_ACK); 8413ab45760Sss150715 8423ab45760Sss150715 notifyreqp = &(req.dlm_msg->notify_req); 8433ab45760Sss150715 notifyreqp->dl_notifications = notes; 8443ab45760Sss150715 notifyreqp->dl_timelimit = 0; 8453ab45760Sss150715 8463ab45760Sss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_NOTIFY_ACK_SIZE, 0); 8473ab45760Sss150715 if (retval == DL_NOTSUPPORTED) 8483ab45760Sss150715 return (DLPI_ENOTENOTSUP); 8493ab45760Sss150715 8503ab45760Sss150715 if (retval != DLPI_SUCCESS) 8513ab45760Sss150715 return (retval); 8523ab45760Sss150715 8533ab45760Sss150715 if ((newnotifp = calloc(1, sizeof (dlpi_notifyent_t))) == NULL) 8543ab45760Sss150715 return (DL_SYSERR); 8553ab45760Sss150715 8563ab45760Sss150715 /* Register notification information. */ 8573ab45760Sss150715 newnotifp->dln_fnp = funcp; 8583ab45760Sss150715 newnotifp->dln_notes = notes; 8593ab45760Sss150715 newnotifp->arg = arg; 8603ab45760Sss150715 newnotifp->dln_rm = B_FALSE; 8613ab45760Sss150715 8623ab45760Sss150715 /* Insert notification node at head */ 8633ab45760Sss150715 newnotifp->dln_next = dip->dli_notifylistp; 8643ab45760Sss150715 dip->dli_notifylistp = newnotifp; 8653ab45760Sss150715 8663ab45760Sss150715 *id = (dlpi_notifyid_t)newnotifp; 8673ab45760Sss150715 return (DLPI_SUCCESS); 8683ab45760Sss150715 } 8693ab45760Sss150715 8703ab45760Sss150715 int 8713ab45760Sss150715 dlpi_disabnotify(dlpi_handle_t dh, dlpi_notifyid_t id, void **argp) 8723ab45760Sss150715 { 8733ab45760Sss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 8743ab45760Sss150715 dlpi_notifyent_t *remid = (dlpi_notifyent_t *)id; 8753ab45760Sss150715 8763ab45760Sss150715 if (dip == NULL) 8773ab45760Sss150715 return (DLPI_EINHANDLE); 8783ab45760Sss150715 8793ab45760Sss150715 /* Walk the notifyentry list to find matching id. */ 8803ab45760Sss150715 if (!(i_dlpi_notifyidexists(dip, remid))) 8813ab45760Sss150715 return (DLPI_ENOTEIDINVAL); 8823ab45760Sss150715 8833ab45760Sss150715 if (argp != NULL) 8843ab45760Sss150715 *argp = remid->arg; 8853ab45760Sss150715 8863ab45760Sss150715 remid->dln_rm = B_TRUE; 8873ab45760Sss150715 /* Delete node if callbacks are not being processed. */ 8883ab45760Sss150715 if (!dip->dli_note_processing) 8893ab45760Sss150715 i_dlpi_deletenotifyid(dip); 8903ab45760Sss150715 8913ab45760Sss150715 return (DLPI_SUCCESS); 8923ab45760Sss150715 } 8933ab45760Sss150715 8943ab45760Sss150715 int 895c7e4935fSss150715 dlpi_fd(dlpi_handle_t dh) 896c7e4935fSss150715 { 897c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 898c7e4935fSss150715 899c7e4935fSss150715 return (dip != NULL ? dip->dli_fd : -1); 900c7e4935fSss150715 } 901c7e4935fSss150715 902c7e4935fSss150715 int 903c7e4935fSss150715 dlpi_set_timeout(dlpi_handle_t dh, int sec) 904c7e4935fSss150715 { 905c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 906c7e4935fSss150715 907c7e4935fSss150715 if (dip == NULL) 908c7e4935fSss150715 return (DLPI_EINHANDLE); 909c7e4935fSss150715 910c7e4935fSss150715 dip->dli_timeout = sec; 911c7e4935fSss150715 return (DLPI_SUCCESS); 912c7e4935fSss150715 } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate const char * 915c7e4935fSss150715 dlpi_linkname(dlpi_handle_t dh) 9167c478bd9Sstevel@tonic-gate { 917c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 9187c478bd9Sstevel@tonic-gate 919c7e4935fSss150715 return (dip != NULL ? dip->dli_linkname : NULL); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 922c7e4935fSss150715 /* 923c7e4935fSss150715 * Returns DLPI style stored in the handle. 924c7e4935fSss150715 * Note: This function is used for test purposes only. Do not remove without 925c7e4935fSss150715 * fixing the DLPI testsuite. 926c7e4935fSss150715 */ 927c7e4935fSss150715 uint_t 928c7e4935fSss150715 dlpi_style(dlpi_handle_t dh) 9297c478bd9Sstevel@tonic-gate { 930c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 9317c478bd9Sstevel@tonic-gate 932c7e4935fSss150715 return (dip->dli_style); 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate 935948f2876Sss150715 uint_t 936948f2876Sss150715 dlpi_arptype(uint_t dlpitype) 937948f2876Sss150715 { 938948f2876Sss150715 switch (dlpitype) { 939948f2876Sss150715 940948f2876Sss150715 case DL_ETHER: 941948f2876Sss150715 return (ARPHRD_ETHER); 942948f2876Sss150715 943948f2876Sss150715 case DL_FRAME: 944948f2876Sss150715 return (ARPHRD_FRAME); 945948f2876Sss150715 946948f2876Sss150715 case DL_ATM: 947948f2876Sss150715 return (ARPHRD_ATM); 948948f2876Sss150715 949948f2876Sss150715 case DL_IPATM: 950948f2876Sss150715 return (ARPHRD_IPATM); 951948f2876Sss150715 952948f2876Sss150715 case DL_HDLC: 953948f2876Sss150715 return (ARPHRD_HDLC); 954948f2876Sss150715 955948f2876Sss150715 case DL_FC: 956948f2876Sss150715 return (ARPHRD_FC); 957948f2876Sss150715 958948f2876Sss150715 case DL_CSMACD: /* ieee 802 networks */ 959948f2876Sss150715 case DL_TPB: 960948f2876Sss150715 case DL_TPR: 961948f2876Sss150715 case DL_METRO: 962948f2876Sss150715 case DL_FDDI: 963948f2876Sss150715 return (ARPHRD_IEEE802); 964948f2876Sss150715 965948f2876Sss150715 case DL_IB: 966948f2876Sss150715 return (ARPHRD_IB); 967948f2876Sss150715 968948f2876Sss150715 case DL_IPV4: 969948f2876Sss150715 case DL_IPV6: 970948f2876Sss150715 return (ARPHRD_TUNNEL); 971948f2876Sss150715 } 972948f2876Sss150715 973948f2876Sss150715 return (0); 974948f2876Sss150715 } 975948f2876Sss150715 976948f2876Sss150715 uint_t 977948f2876Sss150715 dlpi_iftype(uint_t dlpitype) 978948f2876Sss150715 { 979948f2876Sss150715 switch (dlpitype) { 980948f2876Sss150715 981948f2876Sss150715 case DL_ETHER: 982948f2876Sss150715 return (IFT_ETHER); 983948f2876Sss150715 984948f2876Sss150715 case DL_ATM: 985948f2876Sss150715 return (IFT_ATM); 986948f2876Sss150715 987948f2876Sss150715 case DL_CSMACD: 988948f2876Sss150715 return (IFT_ISO88023); 989948f2876Sss150715 990948f2876Sss150715 case DL_TPB: 991948f2876Sss150715 return (IFT_ISO88024); 992948f2876Sss150715 993948f2876Sss150715 case DL_TPR: 994948f2876Sss150715 return (IFT_ISO88025); 995948f2876Sss150715 996948f2876Sss150715 case DL_FDDI: 997948f2876Sss150715 return (IFT_FDDI); 998948f2876Sss150715 999948f2876Sss150715 case DL_IB: 1000948f2876Sss150715 return (IFT_IB); 1001948f2876Sss150715 1002948f2876Sss150715 case DL_OTHER: 1003948f2876Sss150715 return (IFT_OTHER); 1004948f2876Sss150715 } 1005948f2876Sss150715 1006948f2876Sss150715 return (0); 1007948f2876Sss150715 } 1008948f2876Sss150715 1009c7e4935fSss150715 /* 1010d62bc4baSyz147064 * This function attempts to open a device under the following namespaces: 1011b127ac41SPhilip Kirk * /dev/ipnet - if DLPI_DEVIPNET is specified 1012d62bc4baSyz147064 * /dev/net - if a data-link with the specified name exists 1013d62bc4baSyz147064 * /dev - if DLPI_DEVONLY is specified, or if there is no 1014d62bc4baSyz147064 * data-link with the specified name (could be /dev/ip) 1015d62bc4baSyz147064 * 1016b127ac41SPhilip Kirk * In particular, if DLPI_DEVIPNET is not specified, this function is used to 1017b127ac41SPhilip Kirk * open a data-link node, or "/dev/ip" node. It is usually be called firstly 1018d62bc4baSyz147064 * with style1 being B_TRUE, and if that fails and the return value is not 1019d62bc4baSyz147064 * DLPI_ENOTSTYLE2, the function will again be called with style1 being 1020d62bc4baSyz147064 * B_FALSE (style-1 open attempt first, then style-2 open attempt). 1021d62bc4baSyz147064 * 1022d62bc4baSyz147064 * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node 1023d62bc4baSyz147064 * directly. 1024d62bc4baSyz147064 * 1025d62bc4baSyz147064 * Otherwise, for style-1 attempt, the function will try to open the style-1 1026d62bc4baSyz147064 * /dev/net node, and perhaps fallback to open the style-1 /dev node if the 1027d62bc4baSyz147064 * give name is not a data-link name (e.g., it is /dev/ip). Note that the 1028d62bc4baSyz147064 * fallback and the subsequent style-2 attempt will not happen if: 1029d62bc4baSyz147064 * 1. style-1 opening of the /dev/net node succeeds; 1030d62bc4baSyz147064 * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT, 1031d62bc4baSyz147064 * which means that the specific /dev/net node exist, but the attempt fails 1032d62bc4baSyz147064 * for some other reason; 1033d62bc4baSyz147064 * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is 1034d62bc4baSyz147064 * a known device name or its VLAN PPA hack name. (for example, assuming 1035d62bc4baSyz147064 * device bge0 is renamed to net0, opening /dev/net/bge1000 would return 1036d62bc4baSyz147064 * ENOENT, but we should not fallback to open /dev/bge1000 in this case, 1037d62bc4baSyz147064 * as VLAN 1 over the bge0 device should be named as net1000. 1038d62bc4baSyz147064 * 1039d62bc4baSyz147064 * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed 1040d62bc4baSyz147064 * the second style-2 open attempt. 1041c7e4935fSss150715 */ 10427c478bd9Sstevel@tonic-gate static int 1043d62bc4baSyz147064 i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1) 10447c478bd9Sstevel@tonic-gate { 1045c7e4935fSss150715 char path[MAXPATHLEN]; 1046c7e4935fSss150715 int oflags; 1047c7e4935fSss150715 1048d62bc4baSyz147064 errno = ENOENT; 1049c7e4935fSss150715 oflags = O_RDWR; 1050c7e4935fSss150715 if (flags & DLPI_EXCL) 1051c7e4935fSss150715 oflags |= O_EXCL; 1052c7e4935fSss150715 1053b127ac41SPhilip Kirk if (flags & DLPI_DEVIPNET) { 1054b127ac41SPhilip Kirk (void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider); 1055b127ac41SPhilip Kirk if ((*fd = open(path, oflags)) != -1) 1056b127ac41SPhilip Kirk return (DLPI_SUCCESS); 1057b127ac41SPhilip Kirk else 1058b127ac41SPhilip Kirk return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR); 1059b127ac41SPhilip Kirk } else if (style1 && !(flags & DLPI_DEVONLY)) { 1060d62bc4baSyz147064 char driver[DLPI_LINKNAME_MAX]; 1061d62bc4baSyz147064 char device[DLPI_LINKNAME_MAX]; 1062d62bc4baSyz147064 datalink_id_t linkid; 1063d62bc4baSyz147064 uint_t ppa; 10644ac67f02SAnurag S. Maskey dladm_handle_t handle; 1065c7e4935fSss150715 1066d62bc4baSyz147064 /* 1067d62bc4baSyz147064 * This is not a valid style-1 name. It could be "ip" module 1068d62bc4baSyz147064 * for example. Fallback to open the /dev node. 1069d62bc4baSyz147064 */ 1070d62bc4baSyz147064 if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS) 1071d62bc4baSyz147064 goto fallback; 1072d62bc4baSyz147064 1073d62bc4baSyz147064 (void) snprintf(path, sizeof (path), "/dev/net/%s", provider); 1074c7e4935fSss150715 if ((*fd = open(path, oflags)) != -1) 1075c7e4935fSss150715 return (DLPI_SUCCESS); 1076c7e4935fSss150715 1077c7e4935fSss150715 /* 1078d62bc4baSyz147064 * We don't fallback to open the /dev node when it returns 1079d62bc4baSyz147064 * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2 1080d62bc4baSyz147064 * is returned to indicate not to continue the style-2 open. 1081c7e4935fSss150715 */ 1082d62bc4baSyz147064 if (errno != ENOENT) 1083d62bc4baSyz147064 return (DLPI_ENOTSTYLE2); 1084c7e4935fSss150715 1085d62bc4baSyz147064 /* 1086d62bc4baSyz147064 * We didn't find the /dev/net node. Then we check whether 1087d62bc4baSyz147064 * the given name is a device name or its VLAN PPA hack name 1088d62bc4baSyz147064 * of a known link. If the answer is yes, and this link 1089d62bc4baSyz147064 * supports vanity naming, then the link (or the VLAN) should 1090d62bc4baSyz147064 * also have its /dev/net node but perhaps with another vanity 1091d62bc4baSyz147064 * name (for example, when bge0 is renamed to net0). In this 1092d62bc4baSyz147064 * case, although attempt to open the /dev/net/<devname> fails, 1093d62bc4baSyz147064 * we should not fallback to open the /dev/<devname> node. 1094d62bc4baSyz147064 */ 1095d62bc4baSyz147064 (void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver, 1096d62bc4baSyz147064 ppa >= 1000 ? ppa % 1000 : ppa); 1097d62bc4baSyz147064 10984ac67f02SAnurag S. Maskey /* open libdladm handle rather than taking it as input */ 10994ac67f02SAnurag S. Maskey if (dladm_open(&handle) != DLADM_STATUS_OK) 1100e11c3f44Smeem goto fallback; 11014ac67f02SAnurag S. Maskey 11024ac67f02SAnurag S. Maskey if (dladm_dev2linkid(handle, device, &linkid) == 11034ac67f02SAnurag S. Maskey DLADM_STATUS_OK) { 1104d62bc4baSyz147064 dladm_phys_attr_t dpa; 1105d62bc4baSyz147064 11064ac67f02SAnurag S. Maskey if ((dladm_phys_info(handle, linkid, &dpa, 11074ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE)) == DLADM_STATUS_OK && 11084ac67f02SAnurag S. Maskey !dpa.dp_novanity) { 11094ac67f02SAnurag S. Maskey dladm_close(handle); 1110d62bc4baSyz147064 return (DLPI_ENOTSTYLE2); 1111d62bc4baSyz147064 } 1112d62bc4baSyz147064 } 11134ac67f02SAnurag S. Maskey dladm_close(handle); 1114d62bc4baSyz147064 } 1115d62bc4baSyz147064 1116d62bc4baSyz147064 fallback: 1117d62bc4baSyz147064 (void) snprintf(path, sizeof (path), "/dev/%s", provider); 1118c7e4935fSss150715 if ((*fd = open(path, oflags)) != -1) 1119c7e4935fSss150715 return (DLPI_SUCCESS); 1120c7e4935fSss150715 1121c7e4935fSss150715 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR); 1122c7e4935fSss150715 } 1123c7e4935fSss150715 1124c7e4935fSss150715 /* 1125c7e4935fSss150715 * Open a style 1 link. PPA is implicitly attached. 1126c7e4935fSss150715 */ 1127c7e4935fSss150715 static int 1128c7e4935fSss150715 i_dlpi_style1_open(dlpi_impl_t *dip) 1129c7e4935fSss150715 { 1130c7e4935fSss150715 int retval, save_errno; 1131c7e4935fSss150715 int fd; 1132c7e4935fSss150715 11332b24ab6bSSebastien Roy retval = i_dlpi_open(dip->dli_linkname, &fd, dip->dli_oflags, B_TRUE); 11342b24ab6bSSebastien Roy if (retval != DLPI_SUCCESS) 1135c7e4935fSss150715 return (retval); 1136c7e4935fSss150715 dip->dli_fd = fd; 1137c7e4935fSss150715 1138c7e4935fSss150715 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) { 1139c7e4935fSss150715 save_errno = errno; 1140c7e4935fSss150715 (void) close(dip->dli_fd); 1141c7e4935fSss150715 errno = save_errno; 1142c7e4935fSss150715 } 1143c7e4935fSss150715 11442b24ab6bSSebastien Roy return (retval); 1145c7e4935fSss150715 } 1146c7e4935fSss150715 1147c7e4935fSss150715 /* 1148c7e4935fSss150715 * Open a style 2 link. PPA must be explicitly attached. 1149c7e4935fSss150715 */ 1150c7e4935fSss150715 static int 1151c7e4935fSss150715 i_dlpi_style2_open(dlpi_impl_t *dip) 1152c7e4935fSss150715 { 1153c7e4935fSss150715 int fd; 1154c7e4935fSss150715 int retval, save_errno; 1155c7e4935fSss150715 11562b24ab6bSSebastien Roy retval = i_dlpi_open(dip->dli_provider, &fd, dip->dli_oflags, B_FALSE); 11572b24ab6bSSebastien Roy if (retval != DLPI_SUCCESS) 1158c7e4935fSss150715 return (retval); 1159c7e4935fSss150715 dip->dli_fd = fd; 1160c7e4935fSss150715 1161c7e4935fSss150715 /* 1162c7e4935fSss150715 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a 1163c7e4935fSss150715 * DLPI link so attach and ignore rest. 1164c7e4935fSss150715 */ 1165c7e4935fSss150715 if (dip->dli_oflags & DLPI_SERIAL) 1166c7e4935fSss150715 goto attach; 1167c7e4935fSss150715 1168c7e4935fSss150715 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS) 1169c7e4935fSss150715 goto failure; 1170c7e4935fSss150715 1171c7e4935fSss150715 /* 1172c7e4935fSss150715 * Succeeded opening the link and verified it is style2. Now attach to 1173c7e4935fSss150715 * PPA only if DLPI_NOATTACH is not set. 1174c7e4935fSss150715 */ 1175c7e4935fSss150715 if (dip->dli_oflags & DLPI_NOATTACH) 1176c7e4935fSss150715 return (DLPI_SUCCESS); 1177c7e4935fSss150715 1178c7e4935fSss150715 attach: 11792b24ab6bSSebastien Roy if ((retval = i_dlpi_attach(dip)) == DLPI_SUCCESS) 1180c7e4935fSss150715 return (DLPI_SUCCESS); 1181c7e4935fSss150715 1182c7e4935fSss150715 failure: 1183c7e4935fSss150715 save_errno = errno; 1184c7e4935fSss150715 (void) close(dip->dli_fd); 1185c7e4935fSss150715 errno = save_errno; 1186c7e4935fSss150715 return (retval); 1187c7e4935fSss150715 } 1188c7e4935fSss150715 1189c7e4935fSss150715 /* 1190c7e4935fSss150715 * Verify with DLPI that the link is the expected DLPI 'style' device, 1191c7e4935fSss150715 * dlpi_info sets the DLPI style in the DLPI handle. 1192c7e4935fSss150715 */ 1193c7e4935fSss150715 static int 1194c7e4935fSss150715 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style) 1195c7e4935fSss150715 { 1196c7e4935fSss150715 int retval; 1197c7e4935fSss150715 dlpi_info_t dlinfo; 1198c7e4935fSss150715 1199c7e4935fSss150715 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0); 1200c7e4935fSss150715 if (retval == DLPI_SUCCESS && dip->dli_style != style) 1201c7e4935fSss150715 retval = DLPI_EBADLINK; 1202c7e4935fSss150715 1203c7e4935fSss150715 return (retval); 1204c7e4935fSss150715 } 1205c7e4935fSss150715 1206c7e4935fSss150715 /* 1207c7e4935fSss150715 * For DLPI style 2 providers, an explicit attach of PPA is required. 1208c7e4935fSss150715 */ 1209c7e4935fSss150715 static int 1210c7e4935fSss150715 i_dlpi_attach(dlpi_impl_t *dip) 1211c7e4935fSss150715 { 1212c7e4935fSss150715 dlpi_msg_t req, ack; 1213c7e4935fSss150715 dl_attach_req_t *attachreqp; 1214c7e4935fSss150715 1215c7e4935fSss150715 /* 1216c7e4935fSss150715 * Special case: DLPI_SERIAL flag (synchronous serial lines) 1217c7e4935fSss150715 * is not a DLPI link so ignore DLPI style. 1218c7e4935fSss150715 */ 1219c7e4935fSss150715 if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL)) 1220c7e4935fSss150715 return (DLPI_ENOTSTYLE2); 1221c7e4935fSss150715 1222c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_ATTACH_REQ); 1223c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1224c7e4935fSss150715 1225c7e4935fSss150715 attachreqp = &(req.dlm_msg->attach_req); 1226c7e4935fSss150715 attachreqp->dl_ppa = dip->dli_ppa; 1227c7e4935fSss150715 1228c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 1229c7e4935fSss150715 } 1230c7e4935fSss150715 1231c7e4935fSss150715 /* 1232c7e4935fSss150715 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care 1233c7e4935fSss150715 * if this request fails, as this indicates the underlying DLPI device does 1234c7e4935fSss150715 * not support link aggregation (pre-GLDV3 device drivers), and thus will 1235c7e4935fSss150715 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing 1236c7e4935fSss150715 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p). 1237c7e4935fSss150715 */ 1238c7e4935fSss150715 static void 1239c7e4935fSss150715 i_dlpi_passive(dlpi_impl_t *dip) 1240c7e4935fSss150715 { 1241c7e4935fSss150715 dlpi_msg_t req, ack; 1242c7e4935fSss150715 1243c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_PASSIVE_REQ); 1244c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1245c7e4935fSss150715 1246c7e4935fSss150715 (void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0); 1247c7e4935fSss150715 } 1248c7e4935fSss150715 1249c7e4935fSss150715 /* 1250c7e4935fSss150715 * Send a dlpi control message and/or data message on a stream. The inputs 1251c7e4935fSss150715 * for this function are: 12523ab45760Sss150715 * dlpi_impl_t *dip: internal dlpi handle to open stream 1253c7e4935fSss150715 * const dlpi_msg_t *dlreqp: request message structure 1254c7e4935fSss150715 * void *databuf: data buffer 1255c7e4935fSss150715 * size_t datalen: data buffer len 1256c7e4935fSss150715 * int flags: flags to set for putmsg() 1257c7e4935fSss150715 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure. 1258c7e4935fSss150715 */ 1259c7e4935fSss150715 static int 12603ab45760Sss150715 i_dlpi_strputmsg(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp, 1261c7e4935fSss150715 const void *databuf, size_t datalen, int flags) 1262c7e4935fSss150715 { 1263c7e4935fSss150715 int retval; 12643ab45760Sss150715 int fd = dip->dli_fd; 12657c478bd9Sstevel@tonic-gate struct strbuf ctl; 12667c478bd9Sstevel@tonic-gate struct strbuf data; 1267c7e4935fSss150715 1268c7e4935fSss150715 if (dlreqp != NULL) { 1269c7e4935fSss150715 ctl.buf = (void *)dlreqp->dlm_msg; 1270c7e4935fSss150715 ctl.len = dlreqp->dlm_msgsz; 1271c7e4935fSss150715 } 1272c7e4935fSss150715 1273c7e4935fSss150715 data.buf = (void *)databuf; 1274c7e4935fSss150715 data.len = datalen; 1275c7e4935fSss150715 1276c7e4935fSss150715 retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl), 1277c7e4935fSss150715 (databuf == NULL ? NULL : &data), flags); 1278c7e4935fSss150715 1279c7e4935fSss150715 return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR); 1280c7e4935fSss150715 } 1281c7e4935fSss150715 1282c7e4935fSss150715 /* 1283c7e4935fSss150715 * Get a DLPI control message and/or data message from a stream. The inputs 1284c7e4935fSss150715 * for this function are: 12853ab45760Sss150715 * dlpi_impl_t *dip: internal dlpi handle 1286c7e4935fSss150715 * int msec: timeout to wait for message 1287c7e4935fSss150715 * dlpi_msg_t *dlreplyp: reply message structure, the message size 1288c7e4935fSss150715 * member on return stores actual size received 1289c7e4935fSss150715 * t_uscalar_t dlreqprim: requested primitive 1290c7e4935fSss150715 * t_uscalar_t dlreplyprim:acknowledged primitive in response to request 1291c7e4935fSss150715 * size_t dlreplyminsz: minimum size of acknowledged primitive size 1292c7e4935fSss150715 * void *databuf: data buffer 1293c7e4935fSss150715 * size_t *datalenp: data buffer len 1294c7e4935fSss150715 * size_t *totdatalenp: total data received. Greater than 'datalenp' if 1295c7e4935fSss150715 * actual data received is larger than 'databuf' 1296c7e4935fSss150715 * Function returns DLPI_SUCCESS if requested message is retrieved 12973ab45760Sss150715 * otherwise returns error code or timeouts. If a notification arrives on 12983ab45760Sss150715 * the stream the callback is notified. However, error returned during the 12993ab45760Sss150715 * handling of notification is ignored as it would be confusing to actual caller 13003ab45760Sss150715 * of this function. 1301c7e4935fSss150715 */ 1302c7e4935fSss150715 static int 13033ab45760Sss150715 i_dlpi_strgetmsg(dlpi_impl_t *dip, int msec, dlpi_msg_t *dlreplyp, 13043ab45760Sss150715 t_uscalar_t dlreqprim, t_uscalar_t dlreplyprim, size_t dlreplyminsz, 13053ab45760Sss150715 void *databuf, size_t *datalenp, size_t *totdatalenp) 1306c7e4935fSss150715 { 1307c7e4935fSss150715 int retval; 1308e11c3f44Smeem int flags; 13093ab45760Sss150715 int fd = dip->dli_fd; 1310c7e4935fSss150715 struct strbuf ctl, data; 1311c7e4935fSss150715 struct pollfd pfd; 1312c7e4935fSss150715 hrtime_t start, current; 1313c7e4935fSss150715 long bufc[DLPI_CHUNKSIZE / sizeof (long)]; 1314c7e4935fSss150715 long bufd[DLPI_CHUNKSIZE / sizeof (long)]; 1315c7e4935fSss150715 union DL_primitives *dlprim; 13163ab45760Sss150715 dl_notify_ind_t *dlnotif; 1317c7e4935fSss150715 boolean_t infinite = (msec < 0); /* infinite timeout */ 1318c7e4935fSss150715 1319c623edd3SGirish Moodalbail /* 1320c623edd3SGirish Moodalbail * dlreplyp and databuf can be NULL at the same time, to force a check 1321c623edd3SGirish Moodalbail * for pending events on the DLPI link instance; dlpi_enabnotify(3DLPI). 1322c623edd3SGirish Moodalbail * this will be true more so for DLPI_RAW mode with notifications 1323c623edd3SGirish Moodalbail * enabled. 1324c623edd3SGirish Moodalbail */ 1325c623edd3SGirish Moodalbail if ((databuf == NULL && datalenp != NULL) || 1326c7e4935fSss150715 (databuf != NULL && datalenp == NULL)) 1327c7e4935fSss150715 return (DLPI_EINVAL); 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate pfd.fd = fd; 13307c478bd9Sstevel@tonic-gate pfd.events = POLLIN | POLLPRI; 13317c478bd9Sstevel@tonic-gate 1332c7e4935fSss150715 ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg; 13337c478bd9Sstevel@tonic-gate ctl.len = 0; 1334c7e4935fSss150715 ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz; 13357c478bd9Sstevel@tonic-gate 1336c7e4935fSss150715 data.buf = (databuf == NULL) ? bufd : databuf; 13377c478bd9Sstevel@tonic-gate data.len = 0; 1338c7e4935fSss150715 data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp; 13397c478bd9Sstevel@tonic-gate 1340c7e4935fSss150715 for (;;) { 1341c7e4935fSss150715 if (!infinite) 1342*19449258SJosef 'Jeff' Sipek start = NSEC2MSEC(gethrtime()); 13437c478bd9Sstevel@tonic-gate 1344c7e4935fSss150715 switch (poll(&pfd, 1, msec)) { 1345c7e4935fSss150715 default: 1346948f2876Sss150715 if (pfd.revents & POLLHUP) 1347948f2876Sss150715 return (DL_SYSERR); 13487c478bd9Sstevel@tonic-gate break; 13497c478bd9Sstevel@tonic-gate case 0: 1350c7e4935fSss150715 return (DLPI_ETIMEDOUT); 13517c478bd9Sstevel@tonic-gate case -1: 1352c7e4935fSss150715 return (DL_SYSERR); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 1355e11c3f44Smeem flags = 0; 1356c7e4935fSss150715 if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0) 1357c7e4935fSss150715 return (DL_SYSERR); 13587c478bd9Sstevel@tonic-gate 1359c7e4935fSss150715 if (totdatalenp != NULL) 1360c7e4935fSss150715 *totdatalenp = data.len; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* 1363c7e4935fSss150715 * The supplied DLPI_CHUNKSIZE sized buffers are large enough 1364c7e4935fSss150715 * to retrieve all valid DLPI responses in one iteration. 1365c7e4935fSss150715 * If MORECTL or MOREDATA is set, we are not interested in the 1366c7e4935fSss150715 * remainder of the message. Temporary buffers are used to 1367c7e4935fSss150715 * drain the remainder of this message. 1368c7e4935fSss150715 * The special case we have to account for is if 1369c7e4935fSss150715 * a higher priority messages is enqueued whilst handling 1370c7e4935fSss150715 * this condition. We use a change in the flags parameter 1371c7e4935fSss150715 * returned by getmsg() to indicate the message has changed. 13727c478bd9Sstevel@tonic-gate */ 1373c7e4935fSss150715 while (retval & (MORECTL | MOREDATA)) { 1374c7e4935fSss150715 struct strbuf cscratch, dscratch; 1375c7e4935fSss150715 int oflags = flags; 1376c7e4935fSss150715 1377c7e4935fSss150715 cscratch.buf = (char *)bufc; 1378c7e4935fSss150715 dscratch.buf = (char *)bufd; 1379c7e4935fSss150715 cscratch.len = dscratch.len = 0; 1380c7e4935fSss150715 cscratch.maxlen = dscratch.maxlen = 1381c7e4935fSss150715 sizeof (bufc); 1382c7e4935fSss150715 1383c7e4935fSss150715 if ((retval = getmsg(fd, &cscratch, &dscratch, 1384c7e4935fSss150715 &flags)) < 0) 1385c7e4935fSss150715 return (DL_SYSERR); 1386c7e4935fSss150715 1387c7e4935fSss150715 if (totdatalenp != NULL) 1388c7e4935fSss150715 *totdatalenp += dscratch.len; 1389c7e4935fSss150715 /* 1390c7e4935fSss150715 * In the special case of higher priority 1391c7e4935fSss150715 * message received, the low priority message 1392c7e4935fSss150715 * received earlier is discarded, if no data 1393c7e4935fSss150715 * or control message is left. 1394c7e4935fSss150715 */ 1395c7e4935fSss150715 if ((flags != oflags) && 1396c7e4935fSss150715 !(retval & (MORECTL | MOREDATA)) && 1397c7e4935fSss150715 (cscratch.len != 0)) { 1398c7e4935fSss150715 ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE); 1399c7e4935fSss150715 if (dlreplyp != NULL) 1400c7e4935fSss150715 (void) memcpy(dlreplyp->dlm_msg, bufc, 1401c7e4935fSss150715 ctl.len); 1402c7e4935fSss150715 break; 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate /* 14073ab45760Sss150715 * Check if DL_NOTIFY_IND message received. If there is one, 14083ab45760Sss150715 * notify the callback function(s) and continue processing the 14093ab45760Sss150715 * requested message. 14103ab45760Sss150715 */ 14113ab45760Sss150715 if (dip->dli_notifylistp != NULL && 1412c623edd3SGirish Moodalbail ctl.len >= (int)(sizeof (t_uscalar_t)) && 1413c623edd3SGirish Moodalbail *(t_uscalar_t *)(void *)ctl.buf == DL_NOTIFY_IND) { 1414c623edd3SGirish Moodalbail /* process properly-formed DL_NOTIFY_IND messages */ 1415c623edd3SGirish Moodalbail if (ctl.len >= DL_NOTIFY_IND_SIZE) { 1416c623edd3SGirish Moodalbail dlnotif = (dl_notify_ind_t *)(void *)ctl.buf; 14173ab45760Sss150715 (void) i_dlpi_notifyind_process(dip, dlnotif); 1418c623edd3SGirish Moodalbail } 1419c623edd3SGirish Moodalbail goto update_timer; 14203ab45760Sss150715 } 14213ab45760Sss150715 14223ab45760Sss150715 /* 1423c7e4935fSss150715 * If we were expecting a data message, and we got one, set 1424c7e4935fSss150715 * *datalenp. If we aren't waiting on a control message, then 1425c7e4935fSss150715 * we're done. 14267c478bd9Sstevel@tonic-gate */ 1427c7e4935fSss150715 if (databuf != NULL && data.len >= 0) { 1428c7e4935fSss150715 *datalenp = data.len; 1429c7e4935fSss150715 if (dlreplyp == NULL) 1430c7e4935fSss150715 break; 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* 1434c7e4935fSss150715 * If we were expecting a control message, and the message 1435c7e4935fSss150715 * we received is at least big enough to be a DLPI message, 1436c7e4935fSss150715 * then verify it's a reply to something we sent. If it 1437c7e4935fSss150715 * is a reply to something we sent, also verify its size. 14387c478bd9Sstevel@tonic-gate */ 1439c7e4935fSss150715 if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) { 1440c7e4935fSss150715 dlprim = dlreplyp->dlm_msg; 1441c7e4935fSss150715 if (dlprim->dl_primitive == dlreplyprim) { 1442c7e4935fSss150715 if (ctl.len < dlreplyminsz) 1443c7e4935fSss150715 return (DLPI_EBADMSG); 1444c7e4935fSss150715 dlreplyp->dlm_msgsz = ctl.len; 1445c7e4935fSss150715 break; 1446c7e4935fSss150715 } else if (dlprim->dl_primitive == DL_ERROR_ACK) { 1447c7e4935fSss150715 if (ctl.len < DL_ERROR_ACK_SIZE) 1448c7e4935fSss150715 return (DLPI_EBADMSG); 14497c478bd9Sstevel@tonic-gate 1450c7e4935fSss150715 /* Is it ours? */ 1451c7e4935fSss150715 if (dlprim->error_ack.dl_error_primitive == 1452c7e4935fSss150715 dlreqprim) 14537c478bd9Sstevel@tonic-gate break; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate } 1456c623edd3SGirish Moodalbail update_timer: 1457c7e4935fSss150715 if (!infinite) { 1458*19449258SJosef 'Jeff' Sipek current = NSEC2MSEC(gethrtime()); 1459c7e4935fSss150715 msec -= (current - start); 14607c478bd9Sstevel@tonic-gate 1461c7e4935fSss150715 if (msec <= 0) 1462c7e4935fSss150715 return (DLPI_ETIMEDOUT); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 1466c7e4935fSss150715 return (DLPI_SUCCESS); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate /* 1470c7e4935fSss150715 * Common routine invoked by all DLPI control routines. The inputs for this 1471c7e4935fSss150715 * function are: 1472c7e4935fSss150715 * dlpi_impl_t *dip: internal dlpi handle 1473c7e4935fSss150715 * const dlpi_msg_t *dlreqp: request message structure 1474c7e4935fSss150715 * dlpi_msg_t *dlreplyp: reply message structure 1475c7e4935fSss150715 * size_t dlreplyminsz: minimum size of reply primitive 1476c7e4935fSss150715 * int flags: flags to be set to send a message 1477c7e4935fSss150715 * This routine succeeds if the message is an expected request/acknowledged 14783ab45760Sss150715 * message. However, if DLPI notification has been enabled via 14793ab45760Sss150715 * dlpi_enabnotify(), DL_NOTIFY_IND messages are handled before handling 14803ab45760Sss150715 * expected messages. Otherwise, any other unexpected asynchronous messages will 14813ab45760Sss150715 * be discarded. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate static int 1484c7e4935fSss150715 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp, 1485c7e4935fSss150715 dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags) 1486c7e4935fSss150715 { 1487c7e4935fSss150715 int retval; 1488c7e4935fSss150715 t_uscalar_t dlreqprim = dlreqp->dlm_msg->dl_primitive; 1489c7e4935fSss150715 t_uscalar_t dlreplyprim = dlreplyp->dlm_msg->dl_primitive; 1490c7e4935fSss150715 1491c7e4935fSss150715 /* Put the requested primitive on the stream. */ 14923ab45760Sss150715 retval = i_dlpi_strputmsg(dip, dlreqp, NULL, 0, flags); 1493c7e4935fSss150715 if (retval != DLPI_SUCCESS) 1494c7e4935fSss150715 return (retval); 1495c7e4935fSss150715 1496c7e4935fSss150715 /* Retrieve acknowledged message for requested primitive. */ 14973ab45760Sss150715 retval = i_dlpi_strgetmsg(dip, (dip->dli_timeout * MILLISEC), 1498c7e4935fSss150715 dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL); 1499c7e4935fSss150715 if (retval != DLPI_SUCCESS) 1500c7e4935fSss150715 return (retval); 1501c7e4935fSss150715 1502c7e4935fSss150715 /* 1503c7e4935fSss150715 * If primitive is DL_ERROR_ACK, set errno. 1504c7e4935fSss150715 */ 1505c7e4935fSss150715 if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) { 1506c7e4935fSss150715 errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno; 1507c7e4935fSss150715 retval = dlreplyp->dlm_msg->error_ack.dl_errno; 1508c7e4935fSss150715 } 1509c7e4935fSss150715 1510c7e4935fSss150715 return (retval); 1511c7e4935fSss150715 } 1512c7e4935fSss150715 1513c7e4935fSss150715 /* 1514c7e4935fSss150715 * DLPI error codes. 1515c7e4935fSss150715 */ 1516c7e4935fSss150715 static const char *dlpi_errlist[] = { 1517c7e4935fSss150715 "bad LSAP selector", /* DL_BADSAP 0x00 */ 1518c7e4935fSss150715 "DLSAP address in improper format or invalid", /* DL_BADADDR 0x01 */ 1519c7e4935fSss150715 "improper permissions for request", /* DL_ACCESS 0x02 */ 1520c7e4935fSss150715 "primitive issued in improper state", /* DL_OUTSTATE 0x03 */ 1521c7e4935fSss150715 NULL, /* DL_SYSERR 0x04 */ 1522c7e4935fSss150715 "sequence number not from outstanding DL_CONN_IND", 1523c7e4935fSss150715 /* DL_BADCORR 0x05 */ 1524c7e4935fSss150715 "user data exceeded provider limit", /* DL_BADDATA 0x06 */ 1525c7e4935fSss150715 "requested service not supplied by provider", 1526c7e4935fSss150715 /* DL_UNSUPPORTED 0x07 */ 1527c7e4935fSss150715 "specified PPA was invalid", /* DL_BADPPA 0x08 */ 1528c7e4935fSss150715 "primitive received not known by provider", /* DL_BADPRIM 0x09 */ 1529c7e4935fSss150715 "QoS parameters contained invalid values", 1530c7e4935fSss150715 /* DL_BADQOSPARAM 0x0a */ 1531c7e4935fSss150715 "QoS structure type is unknown/unsupported", /* DL_BADQOSTYPE 0x0b */ 1532c7e4935fSss150715 "token used not an active stream", /* DL_BADTOKEN 0x0c */ 1533c7e4935fSss150715 "attempted second bind with dl_max_conind", /* DL_BOUND 0x0d */ 1534c7e4935fSss150715 "physical link initialization failed", /* DL_INITFAILED 0x0e */ 1535c7e4935fSss150715 "provider couldn't allocate alternate address", /* DL_NOADDR 0x0f */ 1536c7e4935fSss150715 "physical link not initialized", /* DL_NOTINIT 0x10 */ 1537c7e4935fSss150715 "previous data unit could not be delivered", 1538c7e4935fSss150715 /* DL_UNDELIVERABLE 0x11 */ 1539c7e4935fSss150715 "primitive is known but unsupported", 1540c7e4935fSss150715 /* DL_NOTSUPPORTED 0x12 */ 1541c7e4935fSss150715 "limit exceeded", /* DL_TOOMANY 0x13 */ 1542c7e4935fSss150715 "promiscuous mode not enabled", /* DL_NOTENAB 0x14 */ 1543c7e4935fSss150715 "other streams for PPA in post-attached", /* DL_BUSY 0x15 */ 1544c7e4935fSss150715 "automatic handling XID&TEST unsupported", /* DL_NOAUTO 0x16 */ 1545c7e4935fSss150715 "automatic handling of XID unsupported", /* DL_NOXIDAUTO 0x17 */ 1546c7e4935fSss150715 "automatic handling of TEST unsupported", /* DL_NOTESTAUTO 0x18 */ 1547c7e4935fSss150715 "automatic handling of XID response", /* DL_XIDAUTO 0x19 */ 1548c7e4935fSss150715 "automatic handling of TEST response", /* DL_TESTAUTO 0x1a */ 1549c7e4935fSss150715 "pending outstanding connect indications" /* DL_PENDING 0x1b */ 1550c7e4935fSss150715 }; 1551c7e4935fSss150715 1552c7e4935fSss150715 /* 1553c7e4935fSss150715 * libdlpi error codes. 1554c7e4935fSss150715 */ 1555c7e4935fSss150715 static const char *libdlpi_errlist[] = { 1556c7e4935fSss150715 "DLPI operation succeeded", /* DLPI_SUCCESS */ 1557c7e4935fSss150715 "invalid argument", /* DLPI_EINVAL */ 1558c7e4935fSss150715 "invalid DLPI linkname", /* DLPI_ELINKNAMEINVAL */ 1559c7e4935fSss150715 "DLPI link does not exist", /* DLPI_ENOLINK */ 1560c7e4935fSss150715 "bad DLPI link", /* DLPI_EBADLINK */ 1561c7e4935fSss150715 "invalid DLPI handle", /* DLPI_EINHANDLE */ 1562c7e4935fSss150715 "DLPI operation timed out", /* DLPI_ETIMEDOUT */ 1563c7e4935fSss150715 "unsupported DLPI version", /* DLPI_EVERNOTSUP */ 1564c7e4935fSss150715 "unsupported DLPI connection mode", /* DLPI_EMODENOTSUP */ 1565c7e4935fSss150715 "unavailable DLPI SAP", /* DLPI_EUNAVAILSAP */ 1566c7e4935fSss150715 "DLPI operation failed", /* DLPI_FAILURE */ 1567c7e4935fSss150715 "DLPI style-2 node reports style-1", /* DLPI_ENOTSTYLE2 */ 1568c7e4935fSss150715 "bad DLPI message", /* DLPI_EBADMSG */ 15693ab45760Sss150715 "DLPI raw mode not supported", /* DLPI_ERAWNOTSUP */ 15703ab45760Sss150715 "DLPI notification not supported by link", 15713ab45760Sss150715 /* DLPI_ENOTENOTSUP */ 15723ab45760Sss150715 "invalid DLPI notification type", /* DLPI_ENOTEINVAL */ 1573b127ac41SPhilip Kirk "invalid DLPI notification id", /* DLPI_ENOTEIDINVAL */ 1574b127ac41SPhilip Kirk "DLPI_IPNETINFO not supported" /* DLPI_EIPNETINFONOTSUP */ 1575c7e4935fSss150715 }; 1576c7e4935fSss150715 1577c7e4935fSss150715 const char * 1578c7e4935fSss150715 dlpi_strerror(int err) 1579c7e4935fSss150715 { 1580c7e4935fSss150715 if (err == DL_SYSERR) 1581c7e4935fSss150715 return (strerror(errno)); 1582c7e4935fSss150715 else if (err >= 0 && err < NELEMS(dlpi_errlist)) 1583c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, dlpi_errlist[err])); 15843ab45760Sss150715 else if (err >= DLPI_SUCCESS && err < DLPI_ERRMAX) 1585c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err - 1586c7e4935fSss150715 DLPI_SUCCESS])); 1587c7e4935fSss150715 else 1588c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, "Unknown DLPI error")); 1589c7e4935fSss150715 } 1590c7e4935fSss150715 1591c7e4935fSss150715 /* 1592c7e4935fSss150715 * Each table entry comprises a DLPI/Private mactype and the description. 1593c7e4935fSss150715 */ 1594c7e4935fSss150715 static const dlpi_mactype_t dlpi_mactypes[] = { 1595c7e4935fSss150715 { DL_CSMACD, "CSMA/CD" }, 1596c7e4935fSss150715 { DL_TPB, "Token Bus" }, 1597c7e4935fSss150715 { DL_TPR, "Token Ring" }, 1598c7e4935fSss150715 { DL_METRO, "Metro Net" }, 1599c7e4935fSss150715 { DL_ETHER, "Ethernet" }, 1600c7e4935fSss150715 { DL_HDLC, "HDLC" }, 1601c7e4935fSss150715 { DL_CHAR, "Sync Character" }, 1602c7e4935fSss150715 { DL_CTCA, "CTCA" }, 1603c7e4935fSss150715 { DL_FDDI, "FDDI" }, 1604c7e4935fSss150715 { DL_FRAME, "Frame Relay (LAPF)" }, 1605c7e4935fSss150715 { DL_MPFRAME, "MP Frame Relay" }, 1606c7e4935fSss150715 { DL_ASYNC, "Async Character" }, 1607c7e4935fSss150715 { DL_IPX25, "X.25 (Classic IP)" }, 1608c7e4935fSss150715 { DL_LOOP, "Software Loopback" }, 1609c7e4935fSss150715 { DL_FC, "Fiber Channel" }, 1610c7e4935fSss150715 { DL_ATM, "ATM" }, 1611c7e4935fSss150715 { DL_IPATM, "ATM (Classic IP)" }, 1612c7e4935fSss150715 { DL_X25, "X.25 (LAPB)" }, 1613c7e4935fSss150715 { DL_ISDN, "ISDN" }, 1614c7e4935fSss150715 { DL_HIPPI, "HIPPI" }, 1615c7e4935fSss150715 { DL_100VG, "100BaseVG Ethernet" }, 1616c7e4935fSss150715 { DL_100VGTPR, "100BaseVG Token Ring" }, 1617c7e4935fSss150715 { DL_ETH_CSMA, "Ethernet/IEEE 802.3" }, 1618c7e4935fSss150715 { DL_100BT, "100BaseT" }, 1619c7e4935fSss150715 { DL_IB, "Infiniband" }, 1620c7e4935fSss150715 { DL_IPV4, "IPv4 Tunnel" }, 1621c7e4935fSss150715 { DL_IPV6, "IPv6 Tunnel" }, 1622b127ac41SPhilip Kirk { DL_WIFI, "IEEE 802.11" }, 1623b127ac41SPhilip Kirk { DL_IPNET, "IPNET" } 1624c7e4935fSss150715 }; 1625c7e4935fSss150715 1626c7e4935fSss150715 const char * 1627c7e4935fSss150715 dlpi_mactype(uint_t mactype) 16287c478bd9Sstevel@tonic-gate { 16297c478bd9Sstevel@tonic-gate int i; 16307c478bd9Sstevel@tonic-gate 1631c7e4935fSss150715 for (i = 0; i < NELEMS(dlpi_mactypes); i++) { 1632c7e4935fSss150715 if (dlpi_mactypes[i].dm_mactype == mactype) 1633c7e4935fSss150715 return (dlpi_mactypes[i].dm_desc); 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate 1636c7e4935fSss150715 return ("Unknown MAC Type"); 16377c478bd9Sstevel@tonic-gate } 16387c478bd9Sstevel@tonic-gate 1639c7e4935fSss150715 /* 1640c7e4935fSss150715 * Each table entry comprises a DLPI primitive and the maximum buffer 1641c7e4935fSss150715 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details). 1642c7e4935fSss150715 */ 1643c7e4935fSss150715 static const dlpi_primsz_t dlpi_primsizes[] = { 1644c7e4935fSss150715 { DL_INFO_REQ, DL_INFO_REQ_SIZE }, 1645c7e4935fSss150715 { DL_INFO_ACK, DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) + 1646c7e4935fSss150715 DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))}, 1647c7e4935fSss150715 { DL_ATTACH_REQ, DL_ATTACH_REQ_SIZE }, 1648c7e4935fSss150715 { DL_BIND_REQ, DL_BIND_REQ_SIZE }, 1649c7e4935fSss150715 { DL_BIND_ACK, DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX + 1650c7e4935fSss150715 DLPI_SAPLEN_MAX }, 1651c7e4935fSss150715 { DL_UNBIND_REQ, DL_UNBIND_REQ_SIZE }, 1652c7e4935fSss150715 { DL_ENABMULTI_REQ, DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1653c7e4935fSss150715 { DL_DISABMULTI_REQ, DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1654c7e4935fSss150715 { DL_PROMISCON_REQ, DL_PROMISCON_REQ_SIZE }, 1655c7e4935fSss150715 { DL_PROMISCOFF_REQ, DL_PROMISCOFF_REQ_SIZE }, 1656c7e4935fSss150715 { DL_PASSIVE_REQ, DL_PASSIVE_REQ_SIZE }, 1657c7e4935fSss150715 { DL_UNITDATA_REQ, DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX + 1658c7e4935fSss150715 DLPI_SAPLEN_MAX }, 1659c7e4935fSss150715 { DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX + 1660c7e4935fSss150715 DLPI_SAPLEN_MAX)) }, 1661c7e4935fSss150715 { DL_PHYS_ADDR_REQ, DL_PHYS_ADDR_REQ_SIZE }, 1662c7e4935fSss150715 { DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX }, 1663c7e4935fSss150715 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX }, 16643ab45760Sss150715 { DL_OK_ACK, MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE) }, 16653ab45760Sss150715 { DL_NOTIFY_REQ, DL_NOTIFY_REQ_SIZE }, 16663ab45760Sss150715 { DL_NOTIFY_ACK, MAX(DL_ERROR_ACK_SIZE, DL_NOTIFY_ACK_SIZE) }, 16673ab45760Sss150715 { DL_NOTIFY_IND, DL_NOTIFY_IND_SIZE + DLPI_PHYSADDR_MAX + 16683ab45760Sss150715 DLPI_SAPLEN_MAX } 1669c7e4935fSss150715 }; 1670c7e4935fSss150715 1671c7e4935fSss150715 /* 1672c7e4935fSss150715 * Refers to the dlpi_primsizes[] table to return corresponding maximum 1673c7e4935fSss150715 * buffer size. 1674c7e4935fSss150715 */ 1675c7e4935fSss150715 static size_t 1676c7e4935fSss150715 i_dlpi_getprimsize(t_uscalar_t prim) 1677c7e4935fSss150715 { 1678c7e4935fSss150715 int i; 1679c7e4935fSss150715 1680c7e4935fSss150715 for (i = 0; i < NELEMS(dlpi_primsizes); i++) { 1681c7e4935fSss150715 if (dlpi_primsizes[i].dp_prim == prim) 1682c7e4935fSss150715 return (dlpi_primsizes[i].dp_primsz); 1683c7e4935fSss150715 } 1684c7e4935fSss150715 1685c7e4935fSss150715 return (sizeof (t_uscalar_t)); 1686c7e4935fSss150715 } 1687c7e4935fSss150715 1688c7e4935fSss150715 /* 1689c7e4935fSss150715 * sap values vary in length and are in host byte order, build sap value 1690c7e4935fSss150715 * by writing saplen bytes, so that the sap value is left aligned. 1691c7e4935fSss150715 */ 1692c7e4935fSss150715 static uint_t 1693c7e4935fSss150715 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen) 1694c7e4935fSss150715 { 1695c7e4935fSss150715 int i; 1696c7e4935fSss150715 uint_t sap = 0; 1697c7e4935fSss150715 1698c7e4935fSss150715 #ifdef _LITTLE_ENDIAN 1699c7e4935fSss150715 for (i = saplen - 1; i >= 0; i--) { 1700c7e4935fSss150715 #else 1701c7e4935fSss150715 for (i = 0; i < saplen; i++) { 1702c7e4935fSss150715 #endif 1703c7e4935fSss150715 sap <<= 8; 1704c7e4935fSss150715 sap |= sapp[i]; 1705c7e4935fSss150715 } 1706c7e4935fSss150715 1707c7e4935fSss150715 return (sap); 1708c7e4935fSss150715 } 1709c7e4935fSss150715 1710c7e4935fSss150715 /* 1711c7e4935fSss150715 * Copy sap value to a buffer in host byte order. saplen is the number of 1712c7e4935fSss150715 * bytes to copy. 1713c7e4935fSss150715 */ 1714c7e4935fSss150715 static void 1715c7e4935fSss150715 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen) 1716c7e4935fSss150715 { 1717c7e4935fSss150715 uint8_t *sapp; 1718c7e4935fSss150715 1719c7e4935fSss150715 #ifdef _LITTLE_ENDIAN 1720c7e4935fSss150715 sapp = (uint8_t *)&sap; 1721c7e4935fSss150715 #else 1722c7e4935fSss150715 sapp = (uint8_t *)&sap + (sizeof (sap) - saplen); 1723c7e4935fSss150715 #endif 1724c7e4935fSss150715 1725c7e4935fSss150715 (void) memcpy(dstbuf, sapp, saplen); 17267c478bd9Sstevel@tonic-gate } 17273ab45760Sss150715 17283ab45760Sss150715 /* 17293ab45760Sss150715 * Fill notification payload and callback each registered functions. 17303ab45760Sss150715 * Delete nodes if any was called while processing. 17313ab45760Sss150715 */ 17323ab45760Sss150715 static int 17333ab45760Sss150715 i_dlpi_notifyind_process(dlpi_impl_t *dip, dl_notify_ind_t *dlnotifyindp) 17343ab45760Sss150715 { 17353ab45760Sss150715 dlpi_notifyinfo_t notifinfo; 17363ab45760Sss150715 t_uscalar_t dataoff, datalen; 17373ab45760Sss150715 caddr_t datap; 17383ab45760Sss150715 dlpi_notifyent_t *dnp; 17393ab45760Sss150715 uint_t note = dlnotifyindp->dl_notification; 17403ab45760Sss150715 uint_t deletenode = B_FALSE; 17413ab45760Sss150715 17423ab45760Sss150715 notifinfo.dni_note = note; 17433ab45760Sss150715 17443ab45760Sss150715 switch (note) { 17453ab45760Sss150715 case DL_NOTE_SPEED: 17463ab45760Sss150715 notifinfo.dni_speed = dlnotifyindp->dl_data; 17473ab45760Sss150715 break; 17483ab45760Sss150715 case DL_NOTE_SDU_SIZE: 17493ab45760Sss150715 notifinfo.dni_size = dlnotifyindp->dl_data; 17503ab45760Sss150715 break; 17513ab45760Sss150715 case DL_NOTE_PHYS_ADDR: 17522b24ab6bSSebastien Roy /* 17532b24ab6bSSebastien Roy * libdlpi currently only supports notifications for 17542b24ab6bSSebastien Roy * DL_CURR_PHYS_ADDR. 17552b24ab6bSSebastien Roy */ 17562b24ab6bSSebastien Roy if (dlnotifyindp->dl_data != DL_CURR_PHYS_ADDR) 17572b24ab6bSSebastien Roy return (DLPI_ENOTENOTSUP); 17582b24ab6bSSebastien Roy 17593ab45760Sss150715 dataoff = dlnotifyindp->dl_addr_offset; 17603ab45760Sss150715 datalen = dlnotifyindp->dl_addr_length; 17613ab45760Sss150715 17623ab45760Sss150715 if (dataoff == 0 || datalen == 0) 17633ab45760Sss150715 return (DLPI_EBADMSG); 17643ab45760Sss150715 17653ab45760Sss150715 datap = (caddr_t)dlnotifyindp + dataoff; 17663ab45760Sss150715 if (dataoff < DL_NOTIFY_IND_SIZE) 17673ab45760Sss150715 return (DLPI_EBADMSG); 17683ab45760Sss150715 17693ab45760Sss150715 notifinfo.dni_physaddrlen = datalen - dip->dli_saplen; 17703ab45760Sss150715 17713ab45760Sss150715 if (notifinfo.dni_physaddrlen > DLPI_PHYSADDR_MAX) 17723ab45760Sss150715 return (DL_BADADDR); 17733ab45760Sss150715 17743ab45760Sss150715 (void) memcpy(notifinfo.dni_physaddr, datap, 17753ab45760Sss150715 notifinfo.dni_physaddrlen); 17763ab45760Sss150715 break; 17773ab45760Sss150715 } 17783ab45760Sss150715 17793ab45760Sss150715 dip->dli_note_processing = B_TRUE; 17803ab45760Sss150715 17813ab45760Sss150715 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) { 17823ab45760Sss150715 if (note & dnp->dln_notes) 17833ab45760Sss150715 dnp->dln_fnp((dlpi_handle_t)dip, ¬ifinfo, dnp->arg); 17843ab45760Sss150715 if (dnp->dln_rm) 17853ab45760Sss150715 deletenode = B_TRUE; 17863ab45760Sss150715 } 17873ab45760Sss150715 17883ab45760Sss150715 dip->dli_note_processing = B_FALSE; 17893ab45760Sss150715 17903ab45760Sss150715 /* Walk the notifyentry list to unregister marked entries. */ 17913ab45760Sss150715 if (deletenode) 17923ab45760Sss150715 i_dlpi_deletenotifyid(dip); 17933ab45760Sss150715 17943ab45760Sss150715 return (DLPI_SUCCESS); 17953ab45760Sss150715 } 17963ab45760Sss150715 /* 17973ab45760Sss150715 * Find registered notification. 17983ab45760Sss150715 */ 17993ab45760Sss150715 static boolean_t 18003ab45760Sss150715 i_dlpi_notifyidexists(dlpi_impl_t *dip, dlpi_notifyent_t *id) 18013ab45760Sss150715 { 18023ab45760Sss150715 dlpi_notifyent_t *dnp; 18033ab45760Sss150715 18043ab45760Sss150715 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) { 18053ab45760Sss150715 if (id == dnp) 18063ab45760Sss150715 return (B_TRUE); 18073ab45760Sss150715 } 18083ab45760Sss150715 18093ab45760Sss150715 return (B_FALSE); 18103ab45760Sss150715 } 18113ab45760Sss150715 18123ab45760Sss150715 /* 18133ab45760Sss150715 * Walk the list of notifications and deleted nodes marked to be deleted. 18143ab45760Sss150715 */ 18153ab45760Sss150715 static void 18163ab45760Sss150715 i_dlpi_deletenotifyid(dlpi_impl_t *dip) 18173ab45760Sss150715 { 18183ab45760Sss150715 dlpi_notifyent_t *prev, *dnp; 18193ab45760Sss150715 18203ab45760Sss150715 prev = NULL; 18213ab45760Sss150715 dnp = dip->dli_notifylistp; 18223ab45760Sss150715 while (dnp != NULL) { 18233ab45760Sss150715 if (!dnp->dln_rm) { 18243ab45760Sss150715 prev = dnp; 18253ab45760Sss150715 dnp = dnp->dln_next; 18263ab45760Sss150715 } else if (prev == NULL) { 18273ab45760Sss150715 dip->dli_notifylistp = dnp->dln_next; 18283ab45760Sss150715 free(dnp); 18293ab45760Sss150715 dnp = dip->dli_notifylistp; 18303ab45760Sss150715 } else { 18313ab45760Sss150715 prev->dln_next = dnp->dln_next; 18323ab45760Sss150715 free(dnp); 18333ab45760Sss150715 dnp = prev->dln_next; 18343ab45760Sss150715 } 18353ab45760Sss150715 } 18363ab45760Sss150715 } 1837