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(devname, MAXPATHLEN, "/devices/pseudo/dld@0:%s",
182 	    provider);
183 
184 	if ((fd = open(devname, O_RDWR)) != -1)
185 		return (fd);
186 
187 	(void) snprintf(path, MAXPATHLEN, "/devices/pseudo/clone@0:%s",
188 	    provider);
189 
190 	if (stat(path, &st) == 0) {
191 		(void) strlcpy(devname, path, sizeof (devname));
192 		if ((fd = open(devname, O_RDWR)) != -1)
193 			return (fd);
194 	}
195 
196 	return (-1);
197 }
198 
199 int
200 dlpi_close(int fd)
201 {
202 	return (close(fd));
203 }
204 
205 int
206 dlpi_info(int fd, int timeout, dl_info_ack_t *ackp,
207     union DL_qos_types *selp, union DL_qos_types *rangep,
208     uint8_t *addrp, size_t *addrlenp, uint8_t *brdcst_addrp,
209     size_t *brdcst_addrlenp)
210 {
211 	int			rc = -1;
212 	size_t			size;
213 	dl_info_ack_t		*buf;
214 	dl_info_req_t		dlir;
215 	dl_info_ack_t		*dliap;
216 	union DL_qos_types	*uqtp;
217 
218 	size = sizeof (dl_info_ack_t);		/* DL_INFO_ACK */
219 	size += sizeof (union DL_qos_types);	/* QoS selections */
220 	size += sizeof (union DL_qos_types);	/* QoS ranges */
221 	size += MAXADDRLEN + MAXSAPLEN;		/* DLSAP Address */
222 	size += MAXADDRLEN;			/* Broadcast Address */
223 
224 	if ((buf = malloc(size)) == NULL)
225 		return (-1);
226 
227 	dlir.dl_primitive = DL_INFO_REQ;
228 
229 	if (strputmsg(fd, (uint8_t *)&dlir, DL_INFO_REQ_SIZE, RS_HIPRI) == -1)
230 		goto done;
231 
232 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
233 		goto done;
234 
235 	if (size < DL_INFO_ACK_SIZE) {
236 		errno = EBADMSG;
237 		goto done;
238 	}
239 
240 	dliap = (dl_info_ack_t *)buf;
241 	if (dliap->dl_primitive != DL_INFO_ACK ||
242 	    dliap->dl_version != DL_VERSION_2) {
243 		errno = EPROTO;
244 		goto done;
245 	}
246 
247 	(void) memcpy(ackp, buf, DL_INFO_ACK_SIZE);
248 
249 	if (dliap->dl_qos_offset != 0) {
250 		if (dliap->dl_qos_length < sizeof (t_uscalar_t)) {
251 			errno = EPROTO;
252 			goto done;
253 		}
254 
255 		uqtp = (union DL_qos_types *)
256 		    ((uintptr_t)buf + dliap->dl_qos_offset);
257 		if (uqtp->dl_qos_type != DL_QOS_CO_SEL1 &&
258 		    uqtp->dl_qos_type != DL_QOS_CL_SEL1) {
259 			errno = EPROTO;
260 			goto done;
261 		}
262 
263 		if (selp != NULL)
264 			(void) memcpy(selp, (char *)buf + dliap->dl_qos_offset,
265 			    dliap->dl_qos_length);
266 	}
267 
268 	if (dliap->dl_qos_range_offset != 0) {
269 		if (dliap->dl_qos_range_length < sizeof (t_uscalar_t)) {
270 			errno = EPROTO;
271 			goto done;
272 		}
273 
274 		uqtp = (union DL_qos_types *)
275 		    ((uintptr_t)buf + dliap->dl_qos_range_offset);
276 		if (uqtp->dl_qos_type != DL_QOS_CO_RANGE1 &&
277 		    uqtp->dl_qos_type != DL_QOS_CL_RANGE1) {
278 			errno = EPROTO;
279 			goto done;
280 		}
281 
282 		if (rangep != NULL)
283 			(void) memcpy(rangep,
284 			    (char *)buf + dliap->dl_qos_range_offset,
285 			    dliap->dl_qos_range_length);
286 	}
287 
288 	if (dliap->dl_addr_offset != 0) {
289 		if (dliap->dl_addr_length == 0) {
290 			errno = EPROTO;
291 			goto done;
292 		}
293 
294 		if (addrlenp != NULL)
295 			*addrlenp = dliap->dl_addr_length;
296 		if (addrp != NULL)
297 			(void) memcpy(addrp,
298 			    (char *)buf + dliap->dl_addr_offset,
299 			    dliap->dl_addr_length);
300 	}
301 
302 	if (dliap->dl_brdcst_addr_offset != 0) {
303 		if (dliap->dl_brdcst_addr_length == 0) {
304 			errno = EPROTO;
305 			goto done;
306 		}
307 
308 		if (brdcst_addrlenp != NULL)
309 			*brdcst_addrlenp = dliap->dl_brdcst_addr_length;
310 		if (brdcst_addrp != NULL)
311 			(void) memcpy(brdcst_addrp,
312 			    (char *)buf + dliap->dl_brdcst_addr_offset,
313 			    dliap->dl_brdcst_addr_length);
314 	}
315 
316 	rc = 0;	/* success */
317 done:
318 	free(buf);
319 	return (rc);
320 }
321 
322 int
323 dlpi_attach(int fd, int timeout, uint_t ppa)
324 {
325 	int			rc = -1;
326 	size_t			size;
327 	dl_attach_req_t		dlar;
328 	dl_error_ack_t		*dleap;
329 	union DL_primitives	*buf;
330 	union DL_primitives	*udlp;
331 
332 	size = 0;
333 	size = MAX(sizeof (dl_ok_ack_t), size);
334 	size = MAX(sizeof (dl_error_ack_t), size);
335 
336 	if ((buf = malloc(size)) == NULL)
337 		return (-1);
338 
339 	dlar.dl_primitive = DL_ATTACH_REQ;
340 	dlar.dl_ppa = ppa;
341 
342 	if (strputmsg(fd, (uint8_t *)&dlar, DL_ATTACH_REQ_SIZE, 0) == -1)
343 		goto done;
344 
345 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
346 		goto done;
347 
348 	if (size < sizeof (t_uscalar_t)) {
349 		errno = EBADMSG;
350 		goto done;
351 	}
352 
353 	udlp = (union DL_primitives *)buf;
354 	switch (udlp->dl_primitive) {
355 	case DL_OK_ACK:
356 		if (size < DL_OK_ACK_SIZE) {
357 			errno = EBADMSG;
358 			goto done;
359 		}
360 		break;
361 
362 	case DL_ERROR_ACK:
363 		if (size < DL_ERROR_ACK_SIZE) {
364 			errno = EBADMSG;
365 			goto done;
366 		}
367 
368 		dleap = (dl_error_ack_t *)buf;
369 		switch (dleap->dl_errno) {
370 		case DL_BADPPA:
371 			errno = EINVAL;
372 			break;
373 
374 		case DL_ACCESS:
375 			errno = EPERM;
376 			break;
377 
378 		case DL_SYSERR:
379 			errno = dleap->dl_unix_errno;
380 			break;
381 
382 		default:
383 			errno = EPROTO;
384 			break;
385 		}
386 
387 		goto done;
388 
389 	default:
390 		errno = EBADMSG;
391 		goto done;
392 	}
393 
394 	rc = 0;	/* success */
395 done:
396 	free(buf);
397 	return (rc);
398 }
399 
400 int
401 dlpi_detach(int fd, int timeout)
402 {
403 	int			rc = -1;
404 	size_t			size;
405 	dl_detach_req_t		dldr;
406 	dl_error_ack_t		*dleap;
407 	union DL_primitives	*buf;
408 	union DL_primitives	*udlp;
409 
410 	size = 0;
411 	size = MAX(sizeof (dl_ok_ack_t), size);
412 	size = MAX(sizeof (dl_error_ack_t), size);
413 
414 	if ((buf = malloc(size)) == NULL)
415 		return (-1);
416 
417 	dldr.dl_primitive = DL_DETACH_REQ;
418 
419 	if (strputmsg(fd, (uint8_t *)&dldr, DL_DETACH_REQ_SIZE, 0) == -1)
420 		goto done;
421 
422 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
423 		goto done;
424 
425 	if (size < sizeof (t_uscalar_t)) {
426 		errno = EBADMSG;
427 		goto done;
428 	}
429 
430 	udlp = (union DL_primitives *)buf;
431 	switch (udlp->dl_primitive) {
432 	case DL_OK_ACK:
433 		if (size < DL_OK_ACK_SIZE) {
434 			errno = EBADMSG;
435 			goto done;
436 		}
437 		break;
438 
439 	case DL_ERROR_ACK:
440 		if (size < DL_ERROR_ACK_SIZE) {
441 			errno = EBADMSG;
442 			goto done;
443 		}
444 
445 		dleap = (dl_error_ack_t *)buf;
446 		switch (dleap->dl_errno) {
447 		case DL_SYSERR:
448 			errno = dleap->dl_unix_errno;
449 			break;
450 
451 		default:
452 			errno = EPROTO;
453 			break;
454 		}
455 		goto done;
456 
457 	default:
458 		errno = EBADMSG;
459 		goto done;
460 	}
461 
462 	rc = 0;	/* success */
463 done:
464 	free(buf);
465 	return (rc);
466 }
467 
468 int
469 dlpi_bind(int fd, int timeout, uint_t sap, uint16_t mode,
470     boolean_t conn_mgmt, uint32_t *max_conn_ind,
471     uint32_t *xid_test, uint8_t *addrp, size_t *addrlenp)
472 {
473 	int			rc = -1;
474 	size_t			size;
475 	dl_bind_req_t		dlbr;
476 	dl_bind_ack_t		*dlbap;
477 	dl_error_ack_t		*dleap;
478 	union DL_primitives	*buf;
479 	union DL_primitives	*udlp;
480 
481 	size = 0;
482 	size = MAX(sizeof (dl_bind_ack_t) + MAXADDRLEN + MAXSAPLEN, size);
483 	size = MAX(sizeof (dl_error_ack_t), size);
484 
485 	if ((buf = malloc(size)) == NULL)
486 		return (-1);
487 
488 	dlbr.dl_primitive = DL_BIND_REQ;
489 	dlbr.dl_sap = sap;
490 	dlbr.dl_service_mode = mode;
491 	dlbr.dl_conn_mgmt = (conn_mgmt) ? 1 : 0;
492 	dlbr.dl_max_conind = (max_conn_ind != NULL) ? *max_conn_ind : 0;
493 	dlbr.dl_xidtest_flg = (xid_test != NULL) ? *xid_test : 0;
494 
495 	if (strputmsg(fd, (uint8_t *)&dlbr, DL_BIND_REQ_SIZE, 0) == -1)
496 		goto done;
497 
498 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
499 		goto done;
500 
501 	if (size < sizeof (t_uscalar_t)) {
502 		errno = EBADMSG;
503 		goto done;
504 	}
505 
506 	udlp = (union DL_primitives *)buf;
507 	switch (udlp->dl_primitive) {
508 	case DL_BIND_ACK:
509 		if (size < DL_BIND_ACK_SIZE) {
510 			errno = EBADMSG;
511 			goto done;
512 		}
513 
514 		dlbap = (dl_bind_ack_t *)buf;
515 		if (max_conn_ind != NULL)
516 			*max_conn_ind = dlbap->dl_max_conind;
517 		if (xid_test != NULL)
518 			*xid_test = dlbap->dl_xidtest_flg;
519 
520 		if (dlbap->dl_addr_offset != 0) {
521 			if (dlbap->dl_addr_length == 0) {
522 				errno = EPROTO;
523 				goto done;
524 			}
525 
526 			if (addrlenp != NULL)
527 				*addrlenp = dlbap->dl_addr_length;
528 			if (addrp != NULL)
529 				(void) memcpy(addrp,
530 				    (char *)buf + dlbap->dl_addr_offset,
531 				    dlbap->dl_addr_length);
532 		}
533 
534 		break;
535 
536 	case DL_ERROR_ACK:
537 		if (size < DL_ERROR_ACK_SIZE) {
538 			errno = EBADMSG;
539 			goto done;
540 		}
541 
542 		dleap = (dl_error_ack_t *)buf;
543 		switch (dleap->dl_errno) {
544 		case DL_BADADDR:
545 			errno = EINVAL;
546 			break;
547 
548 		case DL_INITFAILED:
549 		case DL_NOTINIT:
550 			errno = EIO;
551 			break;
552 
553 		case DL_ACCESS:
554 			errno = EACCES;
555 			break;
556 
557 		case DL_NOADDR:
558 			errno = EFAULT;
559 			break;
560 
561 		case DL_UNSUPPORTED:
562 		case DL_NOAUTO:
563 		case DL_NOXIDAUTO:
564 		case DL_NOTESTAUTO:
565 			errno = ENOTSUP;
566 			break;
567 
568 		case DL_SYSERR:
569 			errno = dleap->dl_unix_errno;
570 			break;
571 
572 		default:
573 			errno = EPROTO;
574 			break;
575 		}
576 		goto done;
577 
578 	default:
579 		errno = EBADMSG;
580 		goto done;
581 	}
582 
583 	rc = 0;	/* success */
584 done:
585 	free(buf);
586 	return (rc);
587 }
588 
589 int
590 dlpi_unbind(int fd, int timeout)
591 {
592 	int			rc = -1;
593 	size_t			size;
594 	dl_unbind_req_t		dlubr;
595 	dl_error_ack_t		*dleap;
596 	union DL_primitives	*buf;
597 	union DL_primitives	*udlp;
598 
599 	size = 0;
600 	size = MAX(sizeof (dl_ok_ack_t), size);
601 	size = MAX(sizeof (dl_error_ack_t), size);
602 
603 	if ((buf = malloc(size)) == NULL)
604 		return (-1);
605 
606 	dlubr.dl_primitive = DL_UNBIND_REQ;
607 
608 	if (strputmsg(fd, (uint8_t *)&dlubr, DL_UNBIND_REQ_SIZE, 0) == -1)
609 		goto done;
610 
611 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
612 		goto done;
613 
614 	if (size < sizeof (t_uscalar_t)) {
615 		errno = EBADMSG;
616 		goto done;
617 	}
618 
619 	udlp = (union DL_primitives *)buf;
620 	switch (udlp->dl_primitive) {
621 	case DL_OK_ACK:
622 		if (size < DL_OK_ACK_SIZE) {
623 			errno = EBADMSG;
624 			goto done;
625 		}
626 		break;
627 
628 	case DL_ERROR_ACK:
629 		if (size < DL_ERROR_ACK_SIZE) {
630 			errno = EBADMSG;
631 			goto done;
632 		}
633 
634 		dleap = (dl_error_ack_t *)buf;
635 		switch (dleap->dl_errno) {
636 		case DL_SYSERR:
637 			errno = dleap->dl_unix_errno;
638 			break;
639 
640 		default:
641 			errno = EPROTO;
642 			break;
643 		}
644 		goto done;
645 
646 	default:
647 		errno = EBADMSG;
648 		goto done;
649 	}
650 
651 	rc = 0;	/* success */
652 done:
653 	free(buf);
654 	return (rc);
655 }
656 
657 static int
658 i_dlpi_multi(int fd, int timeout, dlpi_multi_op_t op,
659     uint8_t *addrp, size_t addr_length)
660 {
661 	int			rc = -1;
662 	size_t			opsize;
663 	size_t			size;
664 	dl_enabmulti_req_t	*dlemrp;
665 	dl_disabmulti_req_t	*dldmrp;
666 	dl_error_ack_t		*dleap;
667 	union DL_primitives	*buf;
668 	union DL_primitives	*udlp;
669 
670 	opsize = (op == DLPI_MULTI_ENABLE) ? sizeof (dl_enabmulti_req_t) :
671 	    sizeof (dl_disabmulti_req_t);
672 	opsize += addr_length;
673 
674 	size = 0;
675 	size = MAX(opsize, size);
676 	size = MAX(sizeof (dl_ok_ack_t), size);
677 	size = MAX(sizeof (dl_error_ack_t), size);
678 
679 	if ((buf = malloc(size)) == NULL)
680 		return (-1);
681 
682 	if (op == DLPI_MULTI_ENABLE) {
683 		dlemrp = (dl_enabmulti_req_t *)buf;
684 		dlemrp->dl_primitive = DL_ENABMULTI_REQ;
685 		dlemrp->dl_addr_length = addr_length;
686 		dlemrp->dl_addr_offset = sizeof (dl_enabmulti_req_t);
687 		(void) memcpy(&dlemrp[1], addrp, addr_length);
688 	} else {
689 		dldmrp = (dl_disabmulti_req_t *)buf;
690 		dldmrp->dl_primitive = DL_DISABMULTI_REQ;
691 		dldmrp->dl_addr_length = addr_length;
692 		dldmrp->dl_addr_offset = sizeof (dl_disabmulti_req_t);
693 		(void) memcpy(&dldmrp[1], addrp, addr_length);
694 	}
695 
696 	if (strputmsg(fd, (uint8_t *)buf, opsize, 0) == -1)
697 		goto done;
698 
699 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
700 		goto done;
701 
702 	if (size < sizeof (t_uscalar_t)) {
703 		errno = EBADMSG;
704 		goto done;
705 	}
706 
707 	udlp = (union DL_primitives *)buf;
708 	switch (udlp->dl_primitive) {
709 	case DL_OK_ACK:
710 		if (size < DL_OK_ACK_SIZE) {
711 			errno = EBADMSG;
712 			goto done;
713 		}
714 		break;
715 
716 	case DL_ERROR_ACK:
717 		if (size < DL_ERROR_ACK_SIZE) {
718 			errno = EBADMSG;
719 			goto done;
720 		}
721 
722 		dleap = (dl_error_ack_t *)buf;
723 		switch (dleap->dl_errno) {
724 		case DL_BADADDR:
725 			errno = EINVAL;
726 			break;
727 
728 		case DL_TOOMANY:
729 			errno = ENOSPC;
730 			break;
731 
732 		case DL_NOTSUPPORTED:
733 			errno = ENOTSUP;
734 			break;
735 
736 		case DL_NOTENAB:
737 			errno = EINVAL;
738 			break;
739 
740 		case DL_SYSERR:
741 			errno = dleap->dl_unix_errno;
742 			break;
743 
744 		default:
745 			errno = EPROTO;
746 			break;
747 		}
748 		goto done;
749 
750 	default:
751 		errno = EBADMSG;
752 		goto done;
753 	}
754 
755 	rc = 0;	/* success */
756 done:
757 	free(buf);
758 	return (rc);
759 }
760 
761 int
762 dlpi_enabmulti(int fd, int timeout, uint8_t *addrp,
763     size_t addr_length)
764 {
765 	return (i_dlpi_multi(fd, timeout, DLPI_MULTI_ENABLE, addrp,
766 	    addr_length));
767 }
768 
769 int
770 dlpi_disabmulti(int fd, int timeout, uint8_t *addrp,
771     size_t addr_length)
772 {
773 	return (i_dlpi_multi(fd, timeout, DLPI_MULTI_DISABLE, addrp,
774 	    addr_length));
775 }
776 
777 static int
778 i_dlpi_promisc(int fd, int timeout, dlpi_promisc_op_t op,
779     uint_t level)
780 {
781 	int			rc = -1;
782 	size_t			opsize;
783 	size_t			size;
784 	dl_promiscon_req_t	*dlpnrp;
785 	dl_promiscoff_req_t	*dlpfrp;
786 	dl_error_ack_t		*dleap;
787 	union DL_primitives	*buf;
788 	union DL_primitives	*udlp;
789 
790 	opsize = (op == DLPI_PROMISC_ON) ? sizeof (dl_promiscon_req_t) :
791 	    sizeof (dl_promiscoff_req_t);
792 
793 	size = 0;
794 	size = MAX(opsize, size);
795 	size = MAX(sizeof (dl_ok_ack_t), size);
796 	size = MAX(sizeof (dl_error_ack_t), size);
797 
798 	if ((buf = malloc(size)) == NULL)
799 		return (-1);
800 
801 	if (op == DLPI_PROMISC_ON) {
802 		dlpnrp = (dl_promiscon_req_t *)buf;
803 		dlpnrp->dl_primitive = DL_PROMISCON_REQ;
804 		dlpnrp->dl_level = level;
805 
806 		if (strputmsg(fd, (uint8_t *)dlpnrp, opsize, 0) == -1)
807 			goto done;
808 	} else {
809 		dlpfrp = (dl_promiscoff_req_t *)buf;
810 		dlpfrp->dl_primitive = DL_PROMISCOFF_REQ;
811 		dlpfrp->dl_level = level;
812 
813 		if (strputmsg(fd, (uint8_t *)dlpfrp, opsize, 0) == -1)
814 			goto done;
815 	}
816 
817 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
818 		goto done;
819 
820 	if (size < sizeof (t_uscalar_t)) {
821 		errno = EBADMSG;
822 		goto done;
823 	}
824 
825 	udlp = (union DL_primitives *)buf;
826 	switch (udlp->dl_primitive) {
827 	case DL_OK_ACK:
828 		if (size < DL_OK_ACK_SIZE) {
829 			errno = EBADMSG;
830 			goto done;
831 		}
832 		break;
833 
834 	case DL_ERROR_ACK:
835 		if (size < DL_ERROR_ACK_SIZE) {
836 			errno = EBADMSG;
837 			goto done;
838 		}
839 
840 		dleap = (dl_error_ack_t *)buf;
841 		switch (dleap->dl_errno) {
842 		case DL_NOTSUPPORTED:
843 		case DL_UNSUPPORTED:
844 			errno = ENOTSUP;
845 			break;
846 
847 		case DL_NOTENAB:
848 			errno = EINVAL;
849 			break;
850 
851 		case DL_SYSERR:
852 			errno = dleap->dl_unix_errno;
853 			break;
854 
855 		default:
856 			errno = EPROTO;
857 			break;
858 		}
859 		goto done;
860 
861 	default:
862 		errno = EBADMSG;
863 		goto done;
864 	}
865 
866 	rc = 0;	/* success */
867 done:
868 	free(buf);
869 	return (rc);
870 }
871 
872 int
873 dlpi_promiscon(int fd, int timeout, uint_t level)
874 {
875 	return (i_dlpi_promisc(fd, timeout, DLPI_PROMISC_ON, level));
876 }
877 
878 int
879 dlpi_promiscoff(int fd, int timeout, uint_t level)
880 {
881 	return (i_dlpi_promisc(fd, timeout, DLPI_PROMISC_OFF, level));
882 }
883 
884 int
885 dlpi_phys_addr(int fd, int timeout, uint_t type, uint8_t *addrp,
886     size_t *addrlenp)
887 {
888 	int			rc = -1;
889 	size_t			size;
890 	dl_phys_addr_req_t	dlpar;
891 	dl_phys_addr_ack_t	*dlpaap;
892 	dl_error_ack_t		*dleap;
893 	union DL_primitives	*buf;
894 	union DL_primitives	*udlp;
895 
896 	size = 0;
897 	size = MAX(sizeof (dl_phys_addr_ack_t) + MAXADDRLEN, size);
898 	size = MAX(sizeof (dl_error_ack_t), size);
899 
900 	if ((buf = malloc(size)) == NULL)
901 		return (-1);
902 
903 	dlpar.dl_primitive = DL_PHYS_ADDR_REQ;
904 	dlpar.dl_addr_type = type;
905 
906 	if (strputmsg(fd, (uint8_t *)&dlpar, DL_PHYS_ADDR_REQ_SIZE, 0) == -1)
907 		goto done;
908 
909 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
910 		goto done;
911 
912 	if (size < sizeof (t_uscalar_t)) {
913 		errno = EBADMSG;
914 		goto done;
915 	}
916 
917 	udlp = (union DL_primitives *)buf;
918 	switch (udlp->dl_primitive) {
919 	case DL_PHYS_ADDR_ACK:
920 		if (size < DL_PHYS_ADDR_ACK_SIZE) {
921 			errno = EBADMSG;
922 			goto done;
923 		}
924 
925 		dlpaap = (dl_phys_addr_ack_t *)buf;
926 		if (dlpaap->dl_addr_offset != 0) {
927 			if (dlpaap->dl_addr_length == 0) {
928 				errno = EPROTO;
929 				goto done;
930 			}
931 
932 			if (addrlenp != NULL)
933 				*addrlenp = dlpaap->dl_addr_length;
934 
935 			if (addrp != NULL)
936 				(void) memcpy(addrp,
937 				    (char *)buf + dlpaap->dl_addr_offset,
938 				    dlpaap->dl_addr_length);
939 		}
940 		break;
941 
942 	case DL_ERROR_ACK:
943 		if (size < DL_ERROR_ACK_SIZE) {
944 			errno = EBADMSG;
945 			goto done;
946 		}
947 
948 		dleap = (dl_error_ack_t *)buf;
949 		switch (dleap->dl_errno) {
950 		case DL_SYSERR:
951 			errno = dleap->dl_unix_errno;
952 			break;
953 
954 		default:
955 			errno = EPROTO;
956 			break;
957 		}
958 		goto done;
959 
960 	default:
961 		errno = EBADMSG;
962 		goto done;
963 	}
964 
965 	rc = 0;	/* success */
966 done:
967 	free(buf);
968 	return (rc);
969 }
970 
971 int
972 dlpi_set_phys_addr(int fd, int timeout, uint8_t *addrp,
973     size_t addr_length)
974 {
975 	int			rc = -1;
976 	size_t			opsize;
977 	size_t			size;
978 	dl_set_phys_addr_req_t	*dlspap;
979 	dl_error_ack_t		*dleap;
980 	union DL_primitives	*buf;
981 	union DL_primitives	*udlp;
982 
983 	opsize = sizeof (dl_set_phys_addr_req_t) + addr_length;
984 
985 	size = 0;
986 	size = MAX(opsize, size);
987 	size = MAX(sizeof (dl_ok_ack_t), size);
988 	size = MAX(sizeof (dl_error_ack_t), size);
989 
990 	if ((buf = malloc(size)) == NULL)
991 		return (-1);
992 
993 	dlspap = (dl_set_phys_addr_req_t *)buf;
994 	dlspap->dl_primitive = DL_SET_PHYS_ADDR_REQ;
995 	dlspap->dl_addr_length = addr_length;
996 	dlspap->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
997 	(void) memcpy(&dlspap[1], addrp, addr_length);
998 
999 	if (strputmsg(fd, (uint8_t *)dlspap, opsize, 0) == -1)
1000 		goto done;
1001 
1002 	if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1)
1003 		goto done;
1004 
1005 	if (size < sizeof (t_uscalar_t)) {
1006 		errno = EBADMSG;
1007 		goto done;
1008 	}
1009 
1010 	udlp = (union DL_primitives *)buf;
1011 	switch (udlp->dl_primitive) {
1012 	case DL_OK_ACK:
1013 		if (size < DL_OK_ACK_SIZE) {
1014 			errno = EBADMSG;
1015 			goto done;
1016 		}
1017 		break;
1018 
1019 	case DL_ERROR_ACK:
1020 		if (size < DL_ERROR_ACK_SIZE) {
1021 			errno = EBADMSG;
1022 			goto done;
1023 		}
1024 
1025 		dleap = (dl_error_ack_t *)buf;
1026 		switch (dleap->dl_errno) {
1027 		case DL_BADADDR:
1028 			errno = EINVAL;
1029 			break;
1030 
1031 		case DL_NOTSUPPORTED:
1032 			errno = ENOTSUP;
1033 			break;
1034 
1035 		case DL_SYSERR:
1036 			errno = dleap->dl_unix_errno;
1037 			break;
1038 
1039 		default:
1040 			errno = EPROTO;
1041 			break;
1042 		}
1043 		goto done;
1044 
1045 	default:
1046 		errno = EBADMSG;
1047 		goto done;
1048 	}
1049 
1050 	rc = 0;	/* success */
1051 done:
1052 	free(buf);
1053 	return (rc);
1054 }
1055 
1056 void
1057 dlpi_passive(int fd, int timeout)
1058 {
1059 	size_t			size;
1060 	dl_passive_req_t	dlpr;
1061 	union DL_primitives	*buf;
1062 
1063 	size = MAX(sizeof (dl_ok_ack_t), sizeof (dl_error_ack_t));
1064 
1065 	if ((buf = malloc(size)) == NULL)
1066 		return;
1067 
1068 	dlpr.dl_primitive = DL_PASSIVE_REQ;
1069 
1070 	/*
1071 	 * We don't care about the outcome of this operation.  We at least
1072 	 * don't want to return until the operation completes or the
1073 	 * timeout expires.
1074 	 */
1075 	if (strputmsg(fd, (uint8_t *)&dlpr, DL_PASSIVE_REQ_SIZE, 0) == 0)
1076 		(void) strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL);
1077 	free(buf);
1078 }
1079 
1080 static int
1081 i_dlpi_style1_open(dlpi_if_attr_t *diap)
1082 {
1083 	int		fd;
1084 	int		cnt;
1085 	dl_info_ack_t	dlia;
1086 
1087 	/* Open device */
1088 	if ((fd = dlpi_open(diap->devname)) == -1) {
1089 		diap->style1_failed = B_TRUE;
1090 		diap->mod_pushed = 0;
1091 		return (-1);
1092 	} else {
1093 		diap->style1_fd = fd;
1094 	}
1095 
1096 	/*
1097 	 * Try to push modules (if any) onto the device stream
1098 	 */
1099 	for (cnt = 0; cnt < diap->mod_cnt; cnt++) {
1100 		if (ioctl(fd, I_PUSH, diap->modlist[cnt]) == -1) {
1101 			diap->mod_pushed = cnt+1;
1102 			return (-1);
1103 		}
1104 	}
1105 
1106 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) == -1)
1107 		goto failed;
1108 
1109 	if (dlia.dl_provider_style != DL_STYLE1)
1110 		goto failed;
1111 
1112 	diap->style = DL_STYLE1;
1113 
1114 	return (fd);
1115 failed:
1116 	(void) dlpi_close(fd);
1117 	return (-1);
1118 }
1119 
1120 static int
1121 i_dlpi_style2_open(dlpi_if_attr_t *diap)
1122 {
1123 	int	fd;
1124 	uint_t	ppa;
1125 	dl_info_ack_t	dlia;
1126 
1127 	/*
1128 	 * If style 1 open failed, we need to determine how far it got and
1129 	 * finish up the open() call as a style 2 open
1130 	 *
1131 	 * If no modules were pushed (mod_pushed == 0), then we need to
1132 	 * strip off the ppa off the device name and open it as a style 2
1133 	 * device
1134 	 *
1135 	 * If the pushing of the last module failed, we need to strip off the
1136 	 * ppa from that module and try pushing it as a style 2 module
1137 	 *
1138 	 * Otherwise we failed during the push of an intermediate module and
1139 	 * must fail out and close the device.
1140 	 *
1141 	 * And if style1 did not fail (i.e. we called style2 open directly),
1142 	 * just open the device
1143 	 */
1144 	if (diap->style1_failed) {
1145 		if (!diap->mod_pushed) {
1146 			if (i_dlpi_ifrm_num(diap->devname, &ppa) < 0)
1147 				return (-1);
1148 			if ((fd = dlpi_open(diap->devname)) == -1)
1149 				return (-1);
1150 		} else if (diap->mod_pushed == diap->mod_cnt) {
1151 			if (i_dlpi_ifrm_num(
1152 				    diap->modlist[diap->mod_cnt - 1], &ppa) < 0)
1153 				return (-1);
1154 			diap->mod_pushed--;
1155 			fd = diap->style1_fd;
1156 		} else {
1157 			return (-1);
1158 		}
1159 	} else {
1160 		if ((fd = dlpi_open(diap->devname)) == -1)
1161 			return (-1);
1162 	}
1163 
1164 	/*
1165 	 * Try and push modules (if any) onto the device stream
1166 	 */
1167 	for (; diap->mod_pushed < diap->mod_cnt; diap->mod_pushed++) {
1168 		if (ioctl(fd, I_PUSH,
1169 		    diap->modlist[diap->mod_pushed]) == -1)
1170 			goto failed;
1171 	}
1172 
1173 	if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL,
1174 	    NULL) == -1)
1175 		goto failed;
1176 
1177 	if (dlia.dl_provider_style != DL_STYLE2)
1178 		goto failed;
1179 
1180 	diap->style = DL_STYLE2;
1181 
1182 	if (dlpi_attach(fd, -1, diap->ppa) < 0)
1183 		goto failed;
1184 
1185 	return (fd);
1186 failed:
1187 	(void) dlpi_close(fd);
1188 	return (-1);
1189 }
1190 
1191 static int
1192 i_dlpi_ifname_parse(const char *ifname, dlpi_if_attr_t *diap)
1193 {
1194 	char		*modlist = NULL; /* list of modules to push */
1195 	int		cnt = 0; /* number of modules to push */
1196 	char		modbuf[LIFNAMSIZ + 32];
1197 	char		*nxtmod;
1198 	char		*p;
1199 	int		len;
1200 
1201 	/* if lun is specified fail (backwards compat) */
1202 	if (strchr(ifname, ':') != NULL)
1203 		return (-1);
1204 
1205 	/* save copy of original device name */
1206 	if (strlcpy(diap->ifname, ifname, sizeof (diap->ifname)) >=
1207 	    sizeof (diap->ifname))
1208 		return (-1);
1209 
1210 	/* initialize ppa */
1211 	diap->ppa = -1;
1212 
1213 	/* get provider name and ppa from ifname */
1214 	len = strlen(ifname);
1215 	for (p = (char *)ifname + len; --p != ifname; len--) {
1216 		if (!isdigit(*p)) {
1217 			(void) strlcpy(diap->provider, ifname, len + 1);
1218 			diap->ppa = atoi(p + 1);
1219 			break;
1220 		}
1221 	}
1222 
1223 	if (strlcpy(modbuf, diap->ifname, sizeof (modbuf)) >=
1224 	    sizeof (modbuf))
1225 		return (-1);
1226 
1227 	/* parse '.' delimited module list */
1228 	modlist = strchr(modbuf, '.');
1229 	if (modlist != NULL) {
1230 		/* null-terminate interface name (device) */
1231 		*modlist = '\0';
1232 		modlist++;
1233 		while (modlist && cnt < MAX_MODS) {
1234 			if (*modlist == '\0')
1235 				return (-1);
1236 
1237 			nxtmod = strchr(modlist, '.');
1238 			if (nxtmod) {
1239 				*nxtmod = '\0';
1240 				nxtmod++;
1241 			}
1242 			if (strlcpy(diap->modlist[cnt], modlist,
1243 			    sizeof (diap->modlist[cnt])) >=
1244 			    sizeof (diap->modlist[cnt]))
1245 				return (-1);
1246 			cnt++;
1247 			modlist = nxtmod;
1248 		}
1249 	}
1250 	diap->mod_cnt = cnt;
1251 
1252 	if (strlcpy(diap->devname, modbuf, sizeof (diap->devname)) >=
1253 	    sizeof (diap->devname))
1254 		return (-1);
1255 
1256 	return (0);
1257 }
1258 
1259 int
1260 dlpi_if_open(const char *ifname, dlpi_if_attr_t *diap,
1261     boolean_t force_style2)
1262 {
1263 	int	fd;
1264 
1265 	if (i_dlpi_ifname_parse(ifname, diap) == -1) {
1266 		errno = EINVAL;
1267 		return (-1);
1268 	}
1269 
1270 	if (!force_style2) {
1271 		if ((fd = i_dlpi_style1_open(diap)) != -1)
1272 			return (fd);
1273 	}
1274 
1275 	if ((fd = i_dlpi_style2_open(diap)) == -1)
1276 		return (-1);
1277 
1278 	return (fd);
1279 }
1280 
1281 int
1282 dlpi_if_parse(const char *ifname, char *provider, int *ppap)
1283 {
1284 	dlpi_if_attr_t	diap;
1285 
1286 	if (i_dlpi_ifname_parse(ifname, &diap) == -1) {
1287 		errno = EINVAL;
1288 		return (-1);
1289 	}
1290 
1291 	if (strlcpy(provider, diap.provider, LIFNAMSIZ) > LIFNAMSIZ)
1292 		return (-1);
1293 
1294 	if (ppap != NULL)
1295 		*ppap = diap.ppa;
1296 
1297 	return (0);
1298 }
1299 
1300 /*
1301  * attempt to remove ppa from end of file name
1302  * return -1 if none found
1303  * return ppa if found and remove the ppa from the filename
1304  */
1305 static int
1306 i_dlpi_ifrm_num(char *fname, unsigned int *ppa)
1307 {
1308 	int	i;
1309 	uint_t	p = 0;
1310 	unsigned int	m = 1;
1311 
1312 	i = strlen(fname) - 1;
1313 
1314 	while (i >= 0 && isdigit(fname[i])) {
1315 		p += (fname[i] - '0')*m;
1316 		m *= 10;
1317 		i--;
1318 	}
1319 
1320 	if (m == 1) {
1321 		return (-1);
1322 	}
1323 
1324 	fname[i + 1] = '\0';
1325 	*ppa = p;
1326 	return (0);
1327 }
1328