xref: /titanic_51/usr/src/lib/libdlpi/common/libdlpi.c (revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Data-Link Provider Interface (Version 2)
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <poll.h>
41 #include <stropts.h>
42 #include <sys/dlpi.h>
43 #include <errno.h>
44 #include <sys/sysmacros.h>
45 #include <ctype.h>
46 #include <libdlpi.h>
47 #include <libdladm.h>
48 
49 typedef enum dlpi_multi_op {
50 	DLPI_MULTI_DISABLE = 0,
51 	DLPI_MULTI_ENABLE
52 } dlpi_multi_op_t;
53 
54 typedef enum dlpi_promisc_op {
55 	DLPI_PROMISC_OFF = 0,
56 	DLPI_PROMISC_ON
57 } dlpi_promisc_op_t;
58 
59 const char	*i_dlpi_mac_type[] = {
60 	"CSMA/CD",		/* 0x00 */
61 	"Token Bus",		/* 0x01 */
62 	"Token Ring",		/* 0x02 */
63 	"Metro Net",		/* 0x03 */
64 	"Ethernet",		/* 0x04 */
65 	"HDLC",			/* 0x05 */
66 	"Sync Character",	/* 0x06 */
67 	"CTCA",			/* 0x07 */
68 	"FDDI",			/* 0x08 */
69 	"unknown"		/* 0x09 */
70 	"Frame Relay (LAPF)",	/* 0x0a */
71 	"MP Frame Relay",	/* 0x0b */
72 	"Async Character",	/* 0x0c */
73 	"X.25 (Classic IP)",	/* 0x0d */
74 	"Software Loopback",	/* 0x0e */
75 	"undefined",		/* 0x0f */
76 	"Fiber Channel",	/* 0x10 */
77 	"ATM",			/* 0x11 */
78 	"ATM (Classic IP)",	/* 0x12 */
79 	"X.25 (LAPB)",		/* 0x13 */
80 	"ISDN",			/* 0x14 */
81 	"HIPPI",		/* 0x15 */
82 	"100BaseVG Ethernet",	/* 0x16 */
83 	"100BaseVG Token Ring",	/* 0x17 */
84 	"Ethernet/IEEE 802.3",	/* 0x18 */
85 	"100BaseT",		/* 0x19 */
86 	"Infiniband"		/* 0x1a */
87 };
88 
89 static int i_dlpi_ifrm_num(char *, unsigned int *);
90 
91 const char *
92 dlpi_mac_type(uint_t type)
93 {
94 	if (type >= sizeof (i_dlpi_mac_type) / sizeof (i_dlpi_mac_type[0]))
95 		return ("ERROR");
96 
97 	return (i_dlpi_mac_type[type]);
98 }
99 
100 static int
101 strputmsg(int fd, uint8_t *ctl_buf, size_t ctl_len, int flags)
102 {
103 	struct strbuf	ctl;
104 
105 	ctl.buf = (char *)ctl_buf;
106 	ctl.len = ctl_len;
107 
108 	return (putmsg(fd, &ctl, NULL, flags));
109 }
110 
111 static int
112 strgetmsg(int fd, int timeout, char *ctl_buf,
113     size_t *ctl_lenp, char *data_buf, size_t *data_lenp)
114 {
115 	struct strbuf	ctl;
116 	struct strbuf	data;
117 	int		res;
118 	struct pollfd	pfd;
119 	int		flags = 0;
120 
121 	pfd.fd = fd;
122 	pfd.events = POLLIN | POLLPRI;
123 
124 	switch (poll(&pfd, 1, timeout)) {
125 	default:
126 		ctl.buf = ctl_buf;
127 		ctl.len = 0;
128 		ctl.maxlen = (ctl_lenp != NULL) ? *ctl_lenp : 0;
129 
130 		data.buf = data_buf;
131 		data.len = 0;
132 		data.maxlen = (data_lenp != NULL) ? *data_lenp : 0;
133 
134 		if ((res = getmsg(fd, &ctl, &data, &flags)) < 0)
135 			goto failed;
136 
137 		if (ctl_buf != NULL) {
138 			if (res & MORECTL) {
139 				errno = E2BIG;
140 				goto failed;
141 			}
142 
143 			*ctl_lenp = ctl.len;
144 		}
145 
146 		if (data_buf != NULL) {
147 			if (res & MOREDATA) {
148 				errno = E2BIG;
149 				goto failed;
150 			}
151 
152 			*data_lenp = data.len;
153 		}
154 
155 		break;
156 	case 0:
157 		errno = ETIME;
158 		/*FALLTHRU*/
159 	case -1:
160 		goto failed;
161 	}
162 
163 	return (0);
164 failed:
165 	return (-1);
166 }
167 
168 int
169 dlpi_open(const char *provider)
170 {
171 	char		devname[MAXPATHLEN];
172 	char		path[MAXPATHLEN];
173 	int		fd;
174 	struct stat	st;
175 
176 	(void) snprintf(devname, MAXPATHLEN, "/dev/%s", provider);
177 
178 	if ((fd = open(devname, O_RDWR)) != -1)
179 		return (fd);
180 
181 	(void) snprintf(path, MAXPATHLEN, "/devices/pseudo/clone@0:%s",
182 	    provider);
183 
184 	if (stat(path, &st) == 0) {
185 		(void) strlcpy(devname, path, sizeof (devname));
186 		if ((fd = open(devname, O_RDWR)) != -1)
187 			return (fd);
188 	}
189 
190 	return (-1);
191 }
192 
193 int
194 dlpi_close(int fd)
195 {
196 	return (close(fd));
197 }
198 
199 int
200 dlpi_info(int fd, int timeout, dl_info_ack_t *ackp,
201     union DL_qos_types *selp, union DL_qos_types *rangep,
202     uint8_t *addrp, size_t *addrlenp, uint8_t *brdcst_addrp,
203     size_t *brdcst_addrlenp)
204 {
205 	int			rc = -1;
206 	size_t			size;
207 	dl_info_ack_t		*buf;
208 	dl_info_req_t		dlir;
209 	dl_info_ack_t		*dliap;
210 	union DL_qos_types	*uqtp;
211 
212 	size = sizeof (dl_info_ack_t);		/* DL_INFO_ACK */
213 	size += sizeof (union DL_qos_types);	/* QoS selections */
214 	size += sizeof (union DL_qos_types);	/* QoS ranges */
215 	size += MAXADDRLEN + MAXSAPLEN;		/* DLSAP Address */
216 	size += MAXADDRLEN;			/* Broadcast Address */
217 
218 	if ((buf = malloc(size)) == NULL)
219 		return (-1);
220 
221 	dlir.dl_primitive = DL_INFO_REQ;
222 
223 	if (strputmsg(fd, (uint8_t *)&dlir, DL_INFO_REQ_SIZE, RS_HIPRI) == -1)
224 		goto done;
225 
226 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
227 		goto done;
228 
229 	if (size < DL_INFO_ACK_SIZE) {
230 		errno = EBADMSG;
231 		goto done;
232 	}
233 
234 	dliap = (dl_info_ack_t *)buf;
235 	if (dliap->dl_primitive != DL_INFO_ACK ||
236 	    dliap->dl_version != DL_VERSION_2) {
237 		errno = EPROTO;
238 		goto done;
239 	}
240 
241 	(void) memcpy(ackp, buf, DL_INFO_ACK_SIZE);
242 
243 	if (dliap->dl_qos_offset != 0) {
244 		if (dliap->dl_qos_length < sizeof (t_uscalar_t)) {
245 			errno = EPROTO;
246 			goto done;
247 		}
248 
249 		uqtp = (union DL_qos_types *)
250 		    ((uintptr_t)buf + dliap->dl_qos_offset);
251 		if (uqtp->dl_qos_type != DL_QOS_CO_SEL1 &&
252 		    uqtp->dl_qos_type != DL_QOS_CL_SEL1) {
253 			errno = EPROTO;
254 			goto done;
255 		}
256 
257 		if (selp != NULL)
258 			(void) memcpy(selp, (char *)buf + dliap->dl_qos_offset,
259 			    dliap->dl_qos_length);
260 	}
261 
262 	if (dliap->dl_qos_range_offset != 0) {
263 		if (dliap->dl_qos_range_length < sizeof (t_uscalar_t)) {
264 			errno = EPROTO;
265 			goto done;
266 		}
267 
268 		uqtp = (union DL_qos_types *)
269 		    ((uintptr_t)buf + dliap->dl_qos_range_offset);
270 		if (uqtp->dl_qos_type != DL_QOS_CO_RANGE1 &&
271 		    uqtp->dl_qos_type != DL_QOS_CL_RANGE1) {
272 			errno = EPROTO;
273 			goto done;
274 		}
275 
276 		if (rangep != NULL)
277 			(void) memcpy(rangep,
278 			    (char *)buf + dliap->dl_qos_range_offset,
279 			    dliap->dl_qos_range_length);
280 	}
281 
282 	if (dliap->dl_addr_offset != 0) {
283 		if (dliap->dl_addr_length == 0) {
284 			errno = EPROTO;
285 			goto done;
286 		}
287 
288 		if (addrlenp != NULL)
289 			*addrlenp = dliap->dl_addr_length;
290 		if (addrp != NULL)
291 			(void) memcpy(addrp,
292 			    (char *)buf + dliap->dl_addr_offset,
293 			    dliap->dl_addr_length);
294 	}
295 
296 	if (dliap->dl_brdcst_addr_offset != 0) {
297 		if (dliap->dl_brdcst_addr_length == 0) {
298 			errno = EPROTO;
299 			goto done;
300 		}
301 
302 		if (brdcst_addrlenp != NULL)
303 			*brdcst_addrlenp = dliap->dl_brdcst_addr_length;
304 		if (brdcst_addrp != NULL)
305 			(void) memcpy(brdcst_addrp,
306 			    (char *)buf + dliap->dl_brdcst_addr_offset,
307 			    dliap->dl_brdcst_addr_length);
308 	}
309 
310 	rc = 0;	/* success */
311 done:
312 	free(buf);
313 	return (rc);
314 }
315 
316 int
317 dlpi_attach(int fd, int timeout, uint_t ppa)
318 {
319 	int			rc = -1;
320 	size_t			size;
321 	dl_attach_req_t		dlar;
322 	dl_error_ack_t		*dleap;
323 	union DL_primitives	*buf;
324 	union DL_primitives	*udlp;
325 
326 	size = 0;
327 	size = MAX(sizeof (dl_ok_ack_t), size);
328 	size = MAX(sizeof (dl_error_ack_t), size);
329 
330 	if ((buf = malloc(size)) == NULL)
331 		return (-1);
332 
333 	dlar.dl_primitive = DL_ATTACH_REQ;
334 	dlar.dl_ppa = ppa;
335 
336 	if (strputmsg(fd, (uint8_t *)&dlar, DL_ATTACH_REQ_SIZE, 0) == -1)
337 		goto done;
338 
339 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
340 		goto done;
341 
342 	if (size < sizeof (t_uscalar_t)) {
343 		errno = EBADMSG;
344 		goto done;
345 	}
346 
347 	udlp = (union DL_primitives *)buf;
348 	switch (udlp->dl_primitive) {
349 	case DL_OK_ACK:
350 		if (size < DL_OK_ACK_SIZE) {
351 			errno = EBADMSG;
352 			goto done;
353 		}
354 		break;
355 
356 	case DL_ERROR_ACK:
357 		if (size < DL_ERROR_ACK_SIZE) {
358 			errno = EBADMSG;
359 			goto done;
360 		}
361 
362 		dleap = (dl_error_ack_t *)buf;
363 		switch (dleap->dl_errno) {
364 		case DL_BADPPA:
365 			errno = EINVAL;
366 			break;
367 
368 		case DL_ACCESS:
369 			errno = EPERM;
370 			break;
371 
372 		case DL_SYSERR:
373 			errno = dleap->dl_unix_errno;
374 			break;
375 
376 		default:
377 			errno = EPROTO;
378 			break;
379 		}
380 
381 		goto done;
382 
383 	default:
384 		errno = EBADMSG;
385 		goto done;
386 	}
387 
388 	rc = 0;	/* success */
389 done:
390 	free(buf);
391 	return (rc);
392 }
393 
394 int
395 dlpi_detach(int fd, int timeout)
396 {
397 	int			rc = -1;
398 	size_t			size;
399 	dl_detach_req_t		dldr;
400 	dl_error_ack_t		*dleap;
401 	union DL_primitives	*buf;
402 	union DL_primitives	*udlp;
403 
404 	size = 0;
405 	size = MAX(sizeof (dl_ok_ack_t), size);
406 	size = MAX(sizeof (dl_error_ack_t), size);
407 
408 	if ((buf = malloc(size)) == NULL)
409 		return (-1);
410 
411 	dldr.dl_primitive = DL_DETACH_REQ;
412 
413 	if (strputmsg(fd, (uint8_t *)&dldr, DL_DETACH_REQ_SIZE, 0) == -1)
414 		goto done;
415 
416 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
417 		goto done;
418 
419 	if (size < sizeof (t_uscalar_t)) {
420 		errno = EBADMSG;
421 		goto done;
422 	}
423 
424 	udlp = (union DL_primitives *)buf;
425 	switch (udlp->dl_primitive) {
426 	case DL_OK_ACK:
427 		if (size < DL_OK_ACK_SIZE) {
428 			errno = EBADMSG;
429 			goto done;
430 		}
431 		break;
432 
433 	case DL_ERROR_ACK:
434 		if (size < DL_ERROR_ACK_SIZE) {
435 			errno = EBADMSG;
436 			goto done;
437 		}
438 
439 		dleap = (dl_error_ack_t *)buf;
440 		switch (dleap->dl_errno) {
441 		case DL_SYSERR:
442 			errno = dleap->dl_unix_errno;
443 			break;
444 
445 		default:
446 			errno = EPROTO;
447 			break;
448 		}
449 		goto done;
450 
451 	default:
452 		errno = EBADMSG;
453 		goto done;
454 	}
455 
456 	rc = 0;	/* success */
457 done:
458 	free(buf);
459 	return (rc);
460 }
461 
462 int
463 dlpi_bind(int fd, int timeout, uint_t sap, uint16_t mode,
464     boolean_t conn_mgmt, uint32_t *max_conn_ind,
465     uint32_t *xid_test, uint8_t *addrp, size_t *addrlenp)
466 {
467 	int			rc = -1;
468 	size_t			size;
469 	dl_bind_req_t		dlbr;
470 	dl_bind_ack_t		*dlbap;
471 	dl_error_ack_t		*dleap;
472 	union DL_primitives	*buf;
473 	union DL_primitives	*udlp;
474 
475 	size = 0;
476 	size = MAX(sizeof (dl_bind_ack_t) + MAXADDRLEN + MAXSAPLEN, size);
477 	size = MAX(sizeof (dl_error_ack_t), size);
478 
479 	if ((buf = malloc(size)) == NULL)
480 		return (-1);
481 
482 	dlbr.dl_primitive = DL_BIND_REQ;
483 	dlbr.dl_sap = sap;
484 	dlbr.dl_service_mode = mode;
485 	dlbr.dl_conn_mgmt = (conn_mgmt) ? 1 : 0;
486 	dlbr.dl_max_conind = (max_conn_ind != NULL) ? *max_conn_ind : 0;
487 	dlbr.dl_xidtest_flg = (xid_test != NULL) ? *xid_test : 0;
488 
489 	if (strputmsg(fd, (uint8_t *)&dlbr, DL_BIND_REQ_SIZE, 0) == -1)
490 		goto done;
491 
492 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
493 		goto done;
494 
495 	if (size < sizeof (t_uscalar_t)) {
496 		errno = EBADMSG;
497 		goto done;
498 	}
499 
500 	udlp = (union DL_primitives *)buf;
501 	switch (udlp->dl_primitive) {
502 	case DL_BIND_ACK:
503 		if (size < DL_BIND_ACK_SIZE) {
504 			errno = EBADMSG;
505 			goto done;
506 		}
507 
508 		dlbap = (dl_bind_ack_t *)buf;
509 		if (max_conn_ind != NULL)
510 			*max_conn_ind = dlbap->dl_max_conind;
511 		if (xid_test != NULL)
512 			*xid_test = dlbap->dl_xidtest_flg;
513 
514 		if (dlbap->dl_addr_offset != 0) {
515 			if (dlbap->dl_addr_length == 0) {
516 				errno = EPROTO;
517 				goto done;
518 			}
519 
520 			if (addrlenp != NULL)
521 				*addrlenp = dlbap->dl_addr_length;
522 			if (addrp != NULL)
523 				(void) memcpy(addrp,
524 				    (char *)buf + dlbap->dl_addr_offset,
525 				    dlbap->dl_addr_length);
526 		}
527 
528 		break;
529 
530 	case DL_ERROR_ACK:
531 		if (size < DL_ERROR_ACK_SIZE) {
532 			errno = EBADMSG;
533 			goto done;
534 		}
535 
536 		dleap = (dl_error_ack_t *)buf;
537 		switch (dleap->dl_errno) {
538 		case DL_BADADDR:
539 			errno = EINVAL;
540 			break;
541 
542 		case DL_INITFAILED:
543 		case DL_NOTINIT:
544 			errno = EIO;
545 			break;
546 
547 		case DL_ACCESS:
548 			errno = EACCES;
549 			break;
550 
551 		case DL_NOADDR:
552 			errno = EFAULT;
553 			break;
554 
555 		case DL_UNSUPPORTED:
556 		case DL_NOAUTO:
557 		case DL_NOXIDAUTO:
558 		case DL_NOTESTAUTO:
559 			errno = ENOTSUP;
560 			break;
561 
562 		case DL_SYSERR:
563 			errno = dleap->dl_unix_errno;
564 			break;
565 
566 		default:
567 			errno = EPROTO;
568 			break;
569 		}
570 		goto done;
571 
572 	default:
573 		errno = EBADMSG;
574 		goto done;
575 	}
576 
577 	rc = 0;	/* success */
578 done:
579 	free(buf);
580 	return (rc);
581 }
582 
583 int
584 dlpi_unbind(int fd, int timeout)
585 {
586 	int			rc = -1;
587 	size_t			size;
588 	dl_unbind_req_t		dlubr;
589 	dl_error_ack_t		*dleap;
590 	union DL_primitives	*buf;
591 	union DL_primitives	*udlp;
592 
593 	size = 0;
594 	size = MAX(sizeof (dl_ok_ack_t), size);
595 	size = MAX(sizeof (dl_error_ack_t), size);
596 
597 	if ((buf = malloc(size)) == NULL)
598 		return (-1);
599 
600 	dlubr.dl_primitive = DL_UNBIND_REQ;
601 
602 	if (strputmsg(fd, (uint8_t *)&dlubr, DL_UNBIND_REQ_SIZE, 0) == -1)
603 		goto done;
604 
605 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
606 		goto done;
607 
608 	if (size < sizeof (t_uscalar_t)) {
609 		errno = EBADMSG;
610 		goto done;
611 	}
612 
613 	udlp = (union DL_primitives *)buf;
614 	switch (udlp->dl_primitive) {
615 	case DL_OK_ACK:
616 		if (size < DL_OK_ACK_SIZE) {
617 			errno = EBADMSG;
618 			goto done;
619 		}
620 		break;
621 
622 	case DL_ERROR_ACK:
623 		if (size < DL_ERROR_ACK_SIZE) {
624 			errno = EBADMSG;
625 			goto done;
626 		}
627 
628 		dleap = (dl_error_ack_t *)buf;
629 		switch (dleap->dl_errno) {
630 		case DL_SYSERR:
631 			errno = dleap->dl_unix_errno;
632 			break;
633 
634 		default:
635 			errno = EPROTO;
636 			break;
637 		}
638 		goto done;
639 
640 	default:
641 		errno = EBADMSG;
642 		goto done;
643 	}
644 
645 	rc = 0;	/* success */
646 done:
647 	free(buf);
648 	return (rc);
649 }
650 
651 static int
652 i_dlpi_multi(int fd, int timeout, dlpi_multi_op_t op,
653     uint8_t *addrp, size_t addr_length)
654 {
655 	int			rc = -1;
656 	size_t			opsize;
657 	size_t			size;
658 	dl_enabmulti_req_t	*dlemrp;
659 	dl_disabmulti_req_t	*dldmrp;
660 	dl_error_ack_t		*dleap;
661 	union DL_primitives	*buf;
662 	union DL_primitives	*udlp;
663 
664 	opsize = (op == DLPI_MULTI_ENABLE) ? sizeof (dl_enabmulti_req_t) :
665 	    sizeof (dl_disabmulti_req_t);
666 	opsize += addr_length;
667 
668 	size = 0;
669 	size = MAX(opsize, size);
670 	size = MAX(sizeof (dl_ok_ack_t), size);
671 	size = MAX(sizeof (dl_error_ack_t), size);
672 
673 	if ((buf = malloc(size)) == NULL)
674 		return (-1);
675 
676 	if (op == DLPI_MULTI_ENABLE) {
677 		dlemrp = (dl_enabmulti_req_t *)buf;
678 		dlemrp->dl_primitive = DL_ENABMULTI_REQ;
679 		dlemrp->dl_addr_length = addr_length;
680 		dlemrp->dl_addr_offset = sizeof (dl_enabmulti_req_t);
681 		(void) memcpy(&dlemrp[1], addrp, addr_length);
682 	} else {
683 		dldmrp = (dl_disabmulti_req_t *)buf;
684 		dldmrp->dl_primitive = DL_DISABMULTI_REQ;
685 		dldmrp->dl_addr_length = addr_length;
686 		dldmrp->dl_addr_offset = sizeof (dl_disabmulti_req_t);
687 		(void) memcpy(&dldmrp[1], addrp, addr_length);
688 	}
689 
690 	if (strputmsg(fd, (uint8_t *)buf, opsize, 0) == -1)
691 		goto done;
692 
693 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
694 		goto done;
695 
696 	if (size < sizeof (t_uscalar_t)) {
697 		errno = EBADMSG;
698 		goto done;
699 	}
700 
701 	udlp = (union DL_primitives *)buf;
702 	switch (udlp->dl_primitive) {
703 	case DL_OK_ACK:
704 		if (size < DL_OK_ACK_SIZE) {
705 			errno = EBADMSG;
706 			goto done;
707 		}
708 		break;
709 
710 	case DL_ERROR_ACK:
711 		if (size < DL_ERROR_ACK_SIZE) {
712 			errno = EBADMSG;
713 			goto done;
714 		}
715 
716 		dleap = (dl_error_ack_t *)buf;
717 		switch (dleap->dl_errno) {
718 		case DL_BADADDR:
719 			errno = EINVAL;
720 			break;
721 
722 		case DL_TOOMANY:
723 			errno = ENOSPC;
724 			break;
725 
726 		case DL_NOTSUPPORTED:
727 			errno = ENOTSUP;
728 			break;
729 
730 		case DL_NOTENAB:
731 			errno = EINVAL;
732 			break;
733 
734 		case DL_SYSERR:
735 			errno = dleap->dl_unix_errno;
736 			break;
737 
738 		default:
739 			errno = EPROTO;
740 			break;
741 		}
742 		goto done;
743 
744 	default:
745 		errno = EBADMSG;
746 		goto done;
747 	}
748 
749 	rc = 0;	/* success */
750 done:
751 	free(buf);
752 	return (rc);
753 }
754 
755 int
756 dlpi_enabmulti(int fd, int timeout, uint8_t *addrp,
757     size_t addr_length)
758 {
759 	return (i_dlpi_multi(fd, timeout, DLPI_MULTI_ENABLE, addrp,
760 	    addr_length));
761 }
762 
763 int
764 dlpi_disabmulti(int fd, int timeout, uint8_t *addrp,
765     size_t addr_length)
766 {
767 	return (i_dlpi_multi(fd, timeout, DLPI_MULTI_DISABLE, addrp,
768 	    addr_length));
769 }
770 
771 static int
772 i_dlpi_promisc(int fd, int timeout, dlpi_promisc_op_t op,
773     uint_t level)
774 {
775 	int			rc = -1;
776 	size_t			opsize;
777 	size_t			size;
778 	dl_promiscon_req_t	*dlpnrp;
779 	dl_promiscoff_req_t	*dlpfrp;
780 	dl_error_ack_t		*dleap;
781 	union DL_primitives	*buf;
782 	union DL_primitives	*udlp;
783 
784 	opsize = (op == DLPI_PROMISC_ON) ? sizeof (dl_promiscon_req_t) :
785 	    sizeof (dl_promiscoff_req_t);
786 
787 	size = 0;
788 	size = MAX(opsize, size);
789 	size = MAX(sizeof (dl_ok_ack_t), size);
790 	size = MAX(sizeof (dl_error_ack_t), size);
791 
792 	if ((buf = malloc(size)) == NULL)
793 		return (-1);
794 
795 	if (op == DLPI_PROMISC_ON) {
796 		dlpnrp = (dl_promiscon_req_t *)buf;
797 		dlpnrp->dl_primitive = DL_PROMISCON_REQ;
798 		dlpnrp->dl_level = level;
799 
800 		if (strputmsg(fd, (uint8_t *)dlpnrp, opsize, 0) == -1)
801 			goto done;
802 	} else {
803 		dlpfrp = (dl_promiscoff_req_t *)buf;
804 		dlpfrp->dl_primitive = DL_PROMISCOFF_REQ;
805 		dlpfrp->dl_level = level;
806 
807 		if (strputmsg(fd, (uint8_t *)dlpfrp, opsize, 0) == -1)
808 			goto done;
809 	}
810 
811 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
812 		goto done;
813 
814 	if (size < sizeof (t_uscalar_t)) {
815 		errno = EBADMSG;
816 		goto done;
817 	}
818 
819 	udlp = (union DL_primitives *)buf;
820 	switch (udlp->dl_primitive) {
821 	case DL_OK_ACK:
822 		if (size < DL_OK_ACK_SIZE) {
823 			errno = EBADMSG;
824 			goto done;
825 		}
826 		break;
827 
828 	case DL_ERROR_ACK:
829 		if (size < DL_ERROR_ACK_SIZE) {
830 			errno = EBADMSG;
831 			goto done;
832 		}
833 
834 		dleap = (dl_error_ack_t *)buf;
835 		switch (dleap->dl_errno) {
836 		case DL_NOTSUPPORTED:
837 		case DL_UNSUPPORTED:
838 			errno = ENOTSUP;
839 			break;
840 
841 		case DL_NOTENAB:
842 			errno = EINVAL;
843 			break;
844 
845 		case DL_SYSERR:
846 			errno = dleap->dl_unix_errno;
847 			break;
848 
849 		default:
850 			errno = EPROTO;
851 			break;
852 		}
853 		goto done;
854 
855 	default:
856 		errno = EBADMSG;
857 		goto done;
858 	}
859 
860 	rc = 0;	/* success */
861 done:
862 	free(buf);
863 	return (rc);
864 }
865 
866 int
867 dlpi_promiscon(int fd, int timeout, uint_t level)
868 {
869 	return (i_dlpi_promisc(fd, timeout, DLPI_PROMISC_ON, level));
870 }
871 
872 int
873 dlpi_promiscoff(int fd, int timeout, uint_t level)
874 {
875 	return (i_dlpi_promisc(fd, timeout, DLPI_PROMISC_OFF, level));
876 }
877 
878 int
879 dlpi_phys_addr(int fd, int timeout, uint_t type, uint8_t *addrp,
880     size_t *addrlenp)
881 {
882 	int			rc = -1;
883 	size_t			size;
884 	dl_phys_addr_req_t	dlpar;
885 	dl_phys_addr_ack_t	*dlpaap;
886 	dl_error_ack_t		*dleap;
887 	union DL_primitives	*buf;
888 	union DL_primitives	*udlp;
889 
890 	size = 0;
891 	size = MAX(sizeof (dl_phys_addr_ack_t) + MAXADDRLEN, size);
892 	size = MAX(sizeof (dl_error_ack_t), size);
893 
894 	if ((buf = malloc(size)) == NULL)
895 		return (-1);
896 
897 	dlpar.dl_primitive = DL_PHYS_ADDR_REQ;
898 	dlpar.dl_addr_type = type;
899 
900 	if (strputmsg(fd, (uint8_t *)&dlpar, DL_PHYS_ADDR_REQ_SIZE, 0) == -1)
901 		goto done;
902 
903 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
904 		goto done;
905 
906 	if (size < sizeof (t_uscalar_t)) {
907 		errno = EBADMSG;
908 		goto done;
909 	}
910 
911 	udlp = (union DL_primitives *)buf;
912 	switch (udlp->dl_primitive) {
913 	case DL_PHYS_ADDR_ACK:
914 		if (size < DL_PHYS_ADDR_ACK_SIZE) {
915 			errno = EBADMSG;
916 			goto done;
917 		}
918 
919 		dlpaap = (dl_phys_addr_ack_t *)buf;
920 		if (dlpaap->dl_addr_offset != 0) {
921 			if (dlpaap->dl_addr_length == 0) {
922 				errno = EPROTO;
923 				goto done;
924 			}
925 
926 			if (addrlenp != NULL)
927 				*addrlenp = dlpaap->dl_addr_length;
928 
929 			if (addrp != NULL)
930 				(void) memcpy(addrp,
931 				    (char *)buf + dlpaap->dl_addr_offset,
932 				    dlpaap->dl_addr_length);
933 		}
934 		break;
935 
936 	case DL_ERROR_ACK:
937 		if (size < DL_ERROR_ACK_SIZE) {
938 			errno = EBADMSG;
939 			goto done;
940 		}
941 
942 		dleap = (dl_error_ack_t *)buf;
943 		switch (dleap->dl_errno) {
944 		case DL_SYSERR:
945 			errno = dleap->dl_unix_errno;
946 			break;
947 
948 		default:
949 			errno = EPROTO;
950 			break;
951 		}
952 		goto done;
953 
954 	default:
955 		errno = EBADMSG;
956 		goto done;
957 	}
958 
959 	rc = 0;	/* success */
960 done:
961 	free(buf);
962 	return (rc);
963 }
964 
965 int
966 dlpi_set_phys_addr(int fd, int timeout, uint8_t *addrp,
967     size_t addr_length)
968 {
969 	int			rc = -1;
970 	size_t			opsize;
971 	size_t			size;
972 	dl_set_phys_addr_req_t	*dlspap;
973 	dl_error_ack_t		*dleap;
974 	union DL_primitives	*buf;
975 	union DL_primitives	*udlp;
976 
977 	opsize = sizeof (dl_set_phys_addr_req_t) + addr_length;
978 
979 	size = 0;
980 	size = MAX(opsize, size);
981 	size = MAX(sizeof (dl_ok_ack_t), size);
982 	size = MAX(sizeof (dl_error_ack_t), size);
983 
984 	if ((buf = malloc(size)) == NULL)
985 		return (-1);
986 
987 	dlspap = (dl_set_phys_addr_req_t *)buf;
988 	dlspap->dl_primitive = DL_SET_PHYS_ADDR_REQ;
989 	dlspap->dl_addr_length = addr_length;
990 	dlspap->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
991 	(void) memcpy(&dlspap[1], addrp, addr_length);
992 
993 	if (strputmsg(fd, (uint8_t *)dlspap, opsize, 0) == -1)
994 		goto done;
995 
996 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
997 		goto done;
998 
999 	if (size < sizeof (t_uscalar_t)) {
1000 		errno = EBADMSG;
1001 		goto done;
1002 	}
1003 
1004 	udlp = (union DL_primitives *)buf;
1005 	switch (udlp->dl_primitive) {
1006 	case DL_OK_ACK:
1007 		if (size < DL_OK_ACK_SIZE) {
1008 			errno = EBADMSG;
1009 			goto done;
1010 		}
1011 		break;
1012 
1013 	case DL_ERROR_ACK:
1014 		if (size < DL_ERROR_ACK_SIZE) {
1015 			errno = EBADMSG;
1016 			goto done;
1017 		}
1018 
1019 		dleap = (dl_error_ack_t *)buf;
1020 		switch (dleap->dl_errno) {
1021 		case DL_BADADDR:
1022 			errno = EINVAL;
1023 			break;
1024 
1025 		case DL_NOTSUPPORTED:
1026 			errno = ENOTSUP;
1027 			break;
1028 
1029 		case DL_SYSERR:
1030 			errno = dleap->dl_unix_errno;
1031 			break;
1032 
1033 		default:
1034 			errno = EPROTO;
1035 			break;
1036 		}
1037 		goto done;
1038 
1039 	default:
1040 		errno = EBADMSG;
1041 		goto done;
1042 	}
1043 
1044 	rc = 0;	/* success */
1045 done:
1046 	free(buf);
1047 	return (rc);
1048 }
1049 
1050 void
1051 dlpi_passive(int fd, int timeout)
1052 {
1053 	size_t			size;
1054 	dl_passive_req_t	dlpr;
1055 	union DL_primitives	*buf;
1056 
1057 	size = MAX(sizeof (dl_ok_ack_t), sizeof (dl_error_ack_t));
1058 
1059 	if ((buf = malloc(size)) == NULL)
1060 		return;
1061 
1062 	dlpr.dl_primitive = DL_PASSIVE_REQ;
1063 
1064 	/*
1065 	 * We don't care about the outcome of this operation.  We at least
1066 	 * don't want to return until the operation completes or the
1067 	 * timeout expires.
1068 	 */
1069 	if (strputmsg(fd, (uint8_t *)&dlpr, DL_PASSIVE_REQ_SIZE, 0) == 0)
1070 		(void) strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL);
1071 	free(buf);
1072 }
1073 
1074 static int
1075 i_dlpi_style1_open(dlpi_if_attr_t *diap)
1076 {
1077 	int		fd;
1078 	int		cnt;
1079 	dl_info_ack_t	dlia;
1080 
1081 	/* Open device */
1082 	if ((fd = dlpi_open(diap->devname)) == -1) {
1083 		diap->style1_failed = B_TRUE;
1084 		diap->mod_pushed = 0;
1085 		return (-1);
1086 	} else {
1087 		diap->style1_fd = fd;
1088 	}
1089 
1090 	/*
1091 	 * Try to push modules (if any) onto the device stream
1092 	 */
1093 	for (cnt = 0; cnt < diap->mod_cnt; cnt++) {
1094 		if (ioctl(fd, I_PUSH, diap->modlist[cnt]) == -1) {
1095 			diap->mod_pushed = cnt+1;
1096 			return (-1);
1097 		}
1098 	}
1099 
1100 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) == -1)
1101 		goto failed;
1102 
1103 	if (dlia.dl_provider_style != DL_STYLE1)
1104 		goto failed;
1105 
1106 	diap->style = DL_STYLE1;
1107 
1108 	return (fd);
1109 failed:
1110 	(void) dlpi_close(fd);
1111 	return (-1);
1112 }
1113 
1114 static int
1115 i_dlpi_style2_open(dlpi_if_attr_t *diap)
1116 {
1117 	int	fd;
1118 	uint_t	ppa;
1119 	dl_info_ack_t	dlia;
1120 
1121 	/*
1122 	 * If style 1 open failed, we need to determine how far it got and
1123 	 * finish up the open() call as a style 2 open
1124 	 *
1125 	 * If no modules were pushed (mod_pushed == 0), then we need to
1126 	 * strip off the ppa off the device name and open it as a style 2
1127 	 * device
1128 	 *
1129 	 * If the pushing of the last module failed, we need to strip off the
1130 	 * ppa from that module and try pushing it as a style 2 module
1131 	 *
1132 	 * Otherwise we failed during the push of an intermediate module and
1133 	 * must fail out and close the device.
1134 	 *
1135 	 * And if style1 did not fail (i.e. we called style2 open directly),
1136 	 * just open the device
1137 	 */
1138 	if (diap->style1_failed) {
1139 		if (!diap->mod_pushed) {
1140 			if (i_dlpi_ifrm_num(diap->devname, &ppa) < 0)
1141 				return (-1);
1142 			if ((fd = dlpi_open(diap->devname)) == -1)
1143 				return (-1);
1144 		} else if (diap->mod_pushed == diap->mod_cnt) {
1145 			if (i_dlpi_ifrm_num(
1146 				    diap->modlist[diap->mod_cnt - 1], &ppa) < 0)
1147 				return (-1);
1148 			diap->mod_pushed--;
1149 			fd = diap->style1_fd;
1150 		} else {
1151 			return (-1);
1152 		}
1153 	} else {
1154 		if ((fd = dlpi_open(diap->devname)) == -1)
1155 			return (-1);
1156 	}
1157 
1158 	/*
1159 	 * Try and push modules (if any) onto the device stream
1160 	 */
1161 	for (; diap->mod_pushed < diap->mod_cnt; diap->mod_pushed++) {
1162 		if (ioctl(fd, I_PUSH,
1163 		    diap->modlist[diap->mod_pushed]) == -1)
1164 			goto failed;
1165 	}
1166 
1167 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL,
1168 	    NULL) == -1)
1169 		goto failed;
1170 
1171 	if (dlia.dl_provider_style != DL_STYLE2)
1172 		goto failed;
1173 
1174 	diap->style = DL_STYLE2;
1175 
1176 	if (dlpi_attach(fd, -1, diap->ppa) < 0)
1177 		goto failed;
1178 
1179 	return (fd);
1180 failed:
1181 	(void) dlpi_close(fd);
1182 	return (-1);
1183 }
1184 
1185 static int
1186 i_dlpi_ifname_parse(const char *ifname, dlpi_if_attr_t *diap)
1187 {
1188 	char		*modlist = NULL; /* list of modules to push */
1189 	int		cnt = 0; /* number of modules to push */
1190 	char		modbuf[LIFNAMSIZ + 32];
1191 	char		*nxtmod;
1192 	char		*p;
1193 	int		len;
1194 
1195 	/* if lun is specified fail (backwards compat) */
1196 	if (strchr(ifname, ':') != NULL)
1197 		return (-1);
1198 
1199 	/* save copy of original device name */
1200 	if (strlcpy(diap->ifname, ifname, sizeof (diap->ifname)) >=
1201 	    sizeof (diap->ifname))
1202 		return (-1);
1203 
1204 	/* initialize ppa */
1205 	diap->ppa = -1;
1206 
1207 	/* get provider name and ppa from ifname */
1208 	len = strlen(ifname);
1209 	for (p = (char *)ifname + len; --p != ifname; len--) {
1210 		if (!isdigit(*p)) {
1211 			(void) strlcpy(diap->provider, ifname, len + 1);
1212 			diap->ppa = atoi(p + 1);
1213 			break;
1214 		}
1215 	}
1216 
1217 	if (strlcpy(modbuf, diap->ifname, sizeof (modbuf)) >=
1218 	    sizeof (modbuf))
1219 		return (-1);
1220 
1221 	/* parse '.' delimited module list */
1222 	modlist = strchr(modbuf, '.');
1223 	if (modlist != NULL) {
1224 		/* null-terminate interface name (device) */
1225 		*modlist = '\0';
1226 		modlist++;
1227 		while (modlist && cnt < MAX_MODS) {
1228 			if (*modlist == '\0')
1229 				return (-1);
1230 
1231 			nxtmod = strchr(modlist, '.');
1232 			if (nxtmod) {
1233 				*nxtmod = '\0';
1234 				nxtmod++;
1235 			}
1236 			if (strlcpy(diap->modlist[cnt], modlist,
1237 			    sizeof (diap->modlist[cnt])) >=
1238 			    sizeof (diap->modlist[cnt]))
1239 				return (-1);
1240 			cnt++;
1241 			modlist = nxtmod;
1242 		}
1243 	}
1244 	diap->mod_cnt = cnt;
1245 
1246 	if (strlcpy(diap->devname, modbuf, sizeof (diap->devname)) >=
1247 	    sizeof (diap->devname))
1248 		return (-1);
1249 
1250 	return (0);
1251 }
1252 
1253 int
1254 dlpi_if_open(const char *ifname, dlpi_if_attr_t *diap,
1255     boolean_t force_style2)
1256 {
1257 	int	fd;
1258 
1259 	if (i_dlpi_ifname_parse(ifname, diap) == -1) {
1260 		errno = EINVAL;
1261 		return (-1);
1262 	}
1263 
1264 	if (!force_style2) {
1265 		if ((fd = i_dlpi_style1_open(diap)) != -1)
1266 			return (fd);
1267 	}
1268 
1269 	if ((fd = i_dlpi_style2_open(diap)) == -1)
1270 		return (-1);
1271 
1272 	return (fd);
1273 }
1274 
1275 int
1276 dlpi_if_parse(const char *ifname, char *provider, int *ppap)
1277 {
1278 	dlpi_if_attr_t	diap;
1279 
1280 	if (i_dlpi_ifname_parse(ifname, &diap) == -1) {
1281 		errno = EINVAL;
1282 		return (-1);
1283 	}
1284 
1285 	if (strlcpy(provider, diap.provider, LIFNAMSIZ) > LIFNAMSIZ)
1286 		return (-1);
1287 
1288 	if (ppap != NULL)
1289 		*ppap = diap.ppa;
1290 
1291 	return (0);
1292 }
1293 
1294 /*
1295  * attempt to remove ppa from end of file name
1296  * return -1 if none found
1297  * return ppa if found and remove the ppa from the filename
1298  */
1299 static int
1300 i_dlpi_ifrm_num(char *fname, unsigned int *ppa)
1301 {
1302 	int	i;
1303 	uint_t	p = 0;
1304 	unsigned int	m = 1;
1305 
1306 	i = strlen(fname) - 1;
1307 
1308 	while (i >= 0 && isdigit(fname[i])) {
1309 		p += (fname[i] - '0')*m;
1310 		m *= 10;
1311 		i--;
1312 	}
1313 
1314 	if (m == 1) {
1315 		return (-1);
1316 	}
1317 
1318 	fname[i + 1] = '\0';
1319 	*ppa = p;
1320 	return (0);
1321 }
1322