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
5392b1d6eSyz147064 * Common Development and Distribution License (the "License").
6392b1d6eSyz147064 * 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 /*
223a18a1c1Smeem * 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 * Common Sun DLPI routines.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
337c478bd9Sstevel@tonic-gate #include <sys/stream.h>
347c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
357c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
36d62bc4baSyz147064 #include <sys/ddi.h>
37d62bc4baSyz147064 #include <sys/sunddi.h>
38d62bc4baSyz147064 #include <sys/sunldi.h>
39d62bc4baSyz147064 #include <sys/cmn_err.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate void
dlbindack(queue_t * wq,mblk_t * mp,t_scalar_t sap,const void * addrp,t_uscalar_t addrlen,t_uscalar_t maxconind,t_uscalar_t xidtest)427c478bd9Sstevel@tonic-gate dlbindack(
437c478bd9Sstevel@tonic-gate queue_t *wq,
447c478bd9Sstevel@tonic-gate mblk_t *mp,
457c478bd9Sstevel@tonic-gate t_scalar_t sap,
463a18a1c1Smeem const void *addrp,
477c478bd9Sstevel@tonic-gate t_uscalar_t addrlen,
487c478bd9Sstevel@tonic-gate t_uscalar_t maxconind,
497c478bd9Sstevel@tonic-gate t_uscalar_t xidtest)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate union DL_primitives *dlp;
527c478bd9Sstevel@tonic-gate size_t size;
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate size = sizeof (dl_bind_ack_t) + addrlen;
557c478bd9Sstevel@tonic-gate if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
567c478bd9Sstevel@tonic-gate return;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
597c478bd9Sstevel@tonic-gate dlp->bind_ack.dl_sap = sap;
607c478bd9Sstevel@tonic-gate dlp->bind_ack.dl_addr_length = addrlen;
617c478bd9Sstevel@tonic-gate dlp->bind_ack.dl_addr_offset = sizeof (dl_bind_ack_t);
627c478bd9Sstevel@tonic-gate dlp->bind_ack.dl_max_conind = maxconind;
637c478bd9Sstevel@tonic-gate dlp->bind_ack.dl_xidtest_flg = xidtest;
647c478bd9Sstevel@tonic-gate if (addrlen != 0)
657c478bd9Sstevel@tonic-gate bcopy(addrp, mp->b_rptr + sizeof (dl_bind_ack_t), addrlen);
667c478bd9Sstevel@tonic-gate qreply(wq, mp);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate void
dlokack(queue_t * wq,mblk_t * mp,t_uscalar_t correct_primitive)707c478bd9Sstevel@tonic-gate dlokack(
717c478bd9Sstevel@tonic-gate queue_t *wq,
727c478bd9Sstevel@tonic-gate mblk_t *mp,
737c478bd9Sstevel@tonic-gate t_uscalar_t correct_primitive)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate union DL_primitives *dlp;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate if ((mp = mexchange(wq, mp, sizeof (dl_ok_ack_t), M_PCPROTO,
787c478bd9Sstevel@tonic-gate DL_OK_ACK)) == NULL)
797c478bd9Sstevel@tonic-gate return;
807c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
817c478bd9Sstevel@tonic-gate dlp->ok_ack.dl_correct_primitive = correct_primitive;
827c478bd9Sstevel@tonic-gate qreply(wq, mp);
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate void
dlerrorack(queue_t * wq,mblk_t * mp,t_uscalar_t error_primitive,t_uscalar_t error,t_uscalar_t unix_errno)867c478bd9Sstevel@tonic-gate dlerrorack(
877c478bd9Sstevel@tonic-gate queue_t *wq,
887c478bd9Sstevel@tonic-gate mblk_t *mp,
897c478bd9Sstevel@tonic-gate t_uscalar_t error_primitive,
907c478bd9Sstevel@tonic-gate t_uscalar_t error,
917c478bd9Sstevel@tonic-gate t_uscalar_t unix_errno)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate union DL_primitives *dlp;
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate if ((mp = mexchange(wq, mp, sizeof (dl_error_ack_t), M_PCPROTO,
967c478bd9Sstevel@tonic-gate DL_ERROR_ACK)) == NULL)
977c478bd9Sstevel@tonic-gate return;
987c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
997c478bd9Sstevel@tonic-gate dlp->error_ack.dl_error_primitive = error_primitive;
1007c478bd9Sstevel@tonic-gate dlp->error_ack.dl_errno = error;
1017c478bd9Sstevel@tonic-gate dlp->error_ack.dl_unix_errno = unix_errno;
1027c478bd9Sstevel@tonic-gate qreply(wq, mp);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate void
dluderrorind(queue_t * wq,mblk_t * mp,const void * addrp,t_uscalar_t addrlen,t_uscalar_t error,t_uscalar_t unix_errno)1067c478bd9Sstevel@tonic-gate dluderrorind(
1077c478bd9Sstevel@tonic-gate queue_t *wq,
1087c478bd9Sstevel@tonic-gate mblk_t *mp,
1093a18a1c1Smeem const void *addrp,
1107c478bd9Sstevel@tonic-gate t_uscalar_t addrlen,
1117c478bd9Sstevel@tonic-gate t_uscalar_t error,
1127c478bd9Sstevel@tonic-gate t_uscalar_t unix_errno)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate union DL_primitives *dlp;
1157c478bd9Sstevel@tonic-gate size_t size;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate size = sizeof (dl_uderror_ind_t) + addrlen;
1187c478bd9Sstevel@tonic-gate if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_UDERROR_IND)) == NULL)
1197c478bd9Sstevel@tonic-gate return;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
1227c478bd9Sstevel@tonic-gate dlp->uderror_ind.dl_dest_addr_length = addrlen;
1237c478bd9Sstevel@tonic-gate dlp->uderror_ind.dl_dest_addr_offset = sizeof (dl_uderror_ind_t);
1247c478bd9Sstevel@tonic-gate dlp->uderror_ind.dl_unix_errno = unix_errno;
1257c478bd9Sstevel@tonic-gate dlp->uderror_ind.dl_errno = error;
1263a18a1c1Smeem if (addrlen != 0)
1273a18a1c1Smeem bcopy(addrp, mp->b_rptr + sizeof (dl_uderror_ind_t), addrlen);
1287c478bd9Sstevel@tonic-gate qreply(wq, mp);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate void
dlphysaddrack(queue_t * wq,mblk_t * mp,const void * addrp,t_uscalar_t len)1327c478bd9Sstevel@tonic-gate dlphysaddrack(
1337c478bd9Sstevel@tonic-gate queue_t *wq,
1347c478bd9Sstevel@tonic-gate mblk_t *mp,
1353a18a1c1Smeem const void *addrp,
1367c478bd9Sstevel@tonic-gate t_uscalar_t len)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate union DL_primitives *dlp;
1397c478bd9Sstevel@tonic-gate size_t size;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate size = sizeof (dl_phys_addr_ack_t) + len;
1427c478bd9Sstevel@tonic-gate if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_PHYS_ADDR_ACK)) == NULL)
1437c478bd9Sstevel@tonic-gate return;
1447c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
1457c478bd9Sstevel@tonic-gate dlp->physaddr_ack.dl_addr_length = len;
1467c478bd9Sstevel@tonic-gate dlp->physaddr_ack.dl_addr_offset = sizeof (dl_phys_addr_ack_t);
1477c478bd9Sstevel@tonic-gate if (len != 0)
1487c478bd9Sstevel@tonic-gate bcopy(addrp, mp->b_rptr + sizeof (dl_phys_addr_ack_t), len);
1497c478bd9Sstevel@tonic-gate qreply(wq, mp);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate void
dlcapabsetqid(dl_mid_t * idp,const queue_t * q)1537c478bd9Sstevel@tonic-gate dlcapabsetqid(dl_mid_t *idp, const queue_t *q)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate #ifndef _LP64
1567c478bd9Sstevel@tonic-gate idp->mid[0] = (t_uscalar_t)q;
1577c478bd9Sstevel@tonic-gate #else
1587c478bd9Sstevel@tonic-gate idp->mid[0] = (t_uscalar_t)BMASK_32((uint64_t)q);
1597c478bd9Sstevel@tonic-gate idp->mid[1] = (t_uscalar_t)BMASK_32(((uint64_t)q) >> 32);
1607c478bd9Sstevel@tonic-gate #endif
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate boolean_t
dlcapabcheckqid(const dl_mid_t * idp,const queue_t * q)1647c478bd9Sstevel@tonic-gate dlcapabcheckqid(const dl_mid_t *idp, const queue_t *q)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate #ifndef _LP64
1677c478bd9Sstevel@tonic-gate return ((queue_t *)(idp->mid[0]) == q);
1687c478bd9Sstevel@tonic-gate #else
1697c478bd9Sstevel@tonic-gate return ((queue_t *)
1707c478bd9Sstevel@tonic-gate ((uint64_t)idp->mid[0] | ((uint64_t)idp->mid[1] << 32)) == q);
1717c478bd9Sstevel@tonic-gate #endif
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate void
dlnotifyack(queue_t * wq,mblk_t * mp,uint32_t notifications)1757c478bd9Sstevel@tonic-gate dlnotifyack(
1767c478bd9Sstevel@tonic-gate queue_t *wq,
1777c478bd9Sstevel@tonic-gate mblk_t *mp,
1787c478bd9Sstevel@tonic-gate uint32_t notifications)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate union DL_primitives *dlp;
1817c478bd9Sstevel@tonic-gate
182392b1d6eSyz147064 if ((mp = mexchange(wq, mp, sizeof (dl_notify_ack_t), M_PROTO,
1837c478bd9Sstevel@tonic-gate DL_NOTIFY_ACK)) == NULL)
1847c478bd9Sstevel@tonic-gate return;
1857c478bd9Sstevel@tonic-gate dlp = (union DL_primitives *)mp->b_rptr;
1867c478bd9Sstevel@tonic-gate dlp->notify_ack.dl_notifications = notifications;
1877c478bd9Sstevel@tonic-gate qreply(wq, mp);
1887c478bd9Sstevel@tonic-gate }
189d62bc4baSyz147064
190d62bc4baSyz147064 static int
dl_op(ldi_handle_t lh,mblk_t ** mpp,t_uscalar_t expprim,size_t minlen,dl_error_ack_t * dleap,timestruc_t * tvp)191d62bc4baSyz147064 dl_op(ldi_handle_t lh, mblk_t **mpp, t_uscalar_t expprim, size_t minlen,
192d62bc4baSyz147064 dl_error_ack_t *dleap, timestruc_t *tvp)
193d62bc4baSyz147064 {
194d62bc4baSyz147064 int err;
195d62bc4baSyz147064 size_t len;
196d62bc4baSyz147064 mblk_t *mp = *mpp;
197d62bc4baSyz147064 t_uscalar_t reqprim, ackprim, ackreqprim;
198d62bc4baSyz147064 union DL_primitives *dlp;
199d62bc4baSyz147064
200d62bc4baSyz147064 reqprim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
201d62bc4baSyz147064
202d62bc4baSyz147064 (void) ldi_putmsg(lh, mp);
203d62bc4baSyz147064
204d62bc4baSyz147064 switch (err = ldi_getmsg(lh, &mp, tvp)) {
205d62bc4baSyz147064 case 0:
206d62bc4baSyz147064 break;
207d62bc4baSyz147064 case ETIME:
208d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_op: timed out waiting for %s to %s",
209d62bc4baSyz147064 dl_primstr(reqprim), dl_primstr(expprim));
210d62bc4baSyz147064 return (ETIME);
211d62bc4baSyz147064 default:
212d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_op: ldi_getmsg() for %s failed: %d",
213d62bc4baSyz147064 dl_primstr(expprim), err);
214d62bc4baSyz147064 return (err);
215d62bc4baSyz147064 }
216d62bc4baSyz147064
217d62bc4baSyz147064 len = MBLKL(mp);
218d62bc4baSyz147064 if (len < sizeof (t_uscalar_t)) {
219d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_op: received runt DLPI message");
220d62bc4baSyz147064 freemsg(mp);
221d62bc4baSyz147064 return (EBADMSG);
222d62bc4baSyz147064 }
223d62bc4baSyz147064
224d62bc4baSyz147064 dlp = (union DL_primitives *)mp->b_rptr;
225d62bc4baSyz147064 ackprim = dlp->dl_primitive;
226d62bc4baSyz147064
227d62bc4baSyz147064 if (ackprim == expprim) {
228d62bc4baSyz147064 if (len < minlen)
229d62bc4baSyz147064 goto runt;
230d62bc4baSyz147064
231d62bc4baSyz147064 if (ackprim == DL_OK_ACK) {
232d62bc4baSyz147064 if (dlp->ok_ack.dl_correct_primitive != reqprim) {
233d62bc4baSyz147064 ackreqprim = dlp->ok_ack.dl_correct_primitive;
234d62bc4baSyz147064 goto mixup;
235d62bc4baSyz147064 }
236d62bc4baSyz147064 }
237d62bc4baSyz147064 *mpp = mp;
238d62bc4baSyz147064 return (0);
239d62bc4baSyz147064 }
240d62bc4baSyz147064
241d62bc4baSyz147064 if (ackprim == DL_ERROR_ACK) {
242d62bc4baSyz147064 if (len < DL_ERROR_ACK_SIZE)
243d62bc4baSyz147064 goto runt;
244d62bc4baSyz147064
245d62bc4baSyz147064 if (dlp->error_ack.dl_error_primitive != reqprim) {
246d62bc4baSyz147064 ackreqprim = dlp->error_ack.dl_error_primitive;
247d62bc4baSyz147064 goto mixup;
248d62bc4baSyz147064 }
249d62bc4baSyz147064
250d62bc4baSyz147064 /*
251d62bc4baSyz147064 * Return a special error code (ENOTSUP) indicating that the
252d62bc4baSyz147064 * caller has returned DL_ERROR_ACK. Callers that want more
253d62bc4baSyz147064 * details an pass a non-NULL dleap.
254d62bc4baSyz147064 */
255d62bc4baSyz147064 if (dleap != NULL)
256d62bc4baSyz147064 *dleap = dlp->error_ack;
257d62bc4baSyz147064
258d62bc4baSyz147064 freemsg(mp);
259d62bc4baSyz147064 return (ENOTSUP);
260d62bc4baSyz147064 }
261d62bc4baSyz147064
262d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_op: expected %s but received %s",
263d62bc4baSyz147064 dl_primstr(expprim), dl_primstr(ackprim));
264d62bc4baSyz147064 freemsg(mp);
265d62bc4baSyz147064 return (EBADMSG);
266d62bc4baSyz147064 runt:
267d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_op: received runt %s", dl_primstr(ackprim));
268d62bc4baSyz147064 freemsg(mp);
269d62bc4baSyz147064 return (EBADMSG);
270d62bc4baSyz147064 mixup:
271d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_op: received %s for %s instead of %s",
272d62bc4baSyz147064 dl_primstr(ackprim), dl_primstr(ackreqprim), dl_primstr(reqprim));
273d62bc4baSyz147064 freemsg(mp);
274d62bc4baSyz147064 return (EBADMSG);
275d62bc4baSyz147064 }
276d62bc4baSyz147064
277d62bc4baSyz147064 /*
278d62bc4baSyz147064 * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response.
279d62bc4baSyz147064 *
280d62bc4baSyz147064 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
281d62bc4baSyz147064 * caller can get the contents by passing a non-NULL `dleap').
282d62bc4baSyz147064 */
283d62bc4baSyz147064 int
dl_attach(ldi_handle_t lh,int ppa,dl_error_ack_t * dleap)284d62bc4baSyz147064 dl_attach(ldi_handle_t lh, int ppa, dl_error_ack_t *dleap)
285d62bc4baSyz147064 {
286d62bc4baSyz147064 mblk_t *mp;
287d62bc4baSyz147064 int err;
288d62bc4baSyz147064
289d62bc4baSyz147064 mp = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ);
290d62bc4baSyz147064 if (mp == NULL)
291d62bc4baSyz147064 return (ENOMEM);
292d62bc4baSyz147064
293d62bc4baSyz147064 ((dl_attach_req_t *)mp->b_rptr)->dl_ppa = ppa;
294d62bc4baSyz147064
295d62bc4baSyz147064 err = dl_op(lh, &mp, DL_OK_ACK, DL_OK_ACK_SIZE, dleap, NULL);
296d62bc4baSyz147064 if (err == 0)
297d62bc4baSyz147064 freemsg(mp);
298d62bc4baSyz147064 return (err);
299d62bc4baSyz147064 }
300d62bc4baSyz147064
301d62bc4baSyz147064 /*
302d62bc4baSyz147064 * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response.
303d62bc4baSyz147064 *
304d62bc4baSyz147064 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
305d62bc4baSyz147064 * caller can get the contents by passing a non-NULL `dleap').
306d62bc4baSyz147064 */
307d62bc4baSyz147064 int
dl_bind(ldi_handle_t lh,uint_t sap,dl_error_ack_t * dleap)308d62bc4baSyz147064 dl_bind(ldi_handle_t lh, uint_t sap, dl_error_ack_t *dleap)
309d62bc4baSyz147064 {
310d62bc4baSyz147064 dl_bind_req_t *dlbrp;
311d62bc4baSyz147064 dl_bind_ack_t *dlbap;
312d62bc4baSyz147064 mblk_t *mp;
313d62bc4baSyz147064 int err;
314d62bc4baSyz147064
315d62bc4baSyz147064 mp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
316d62bc4baSyz147064 if (mp == NULL)
317d62bc4baSyz147064 return (ENOMEM);
318d62bc4baSyz147064
319d62bc4baSyz147064 dlbrp = (dl_bind_req_t *)mp->b_rptr;
320d62bc4baSyz147064 dlbrp->dl_sap = sap;
321d62bc4baSyz147064 dlbrp->dl_conn_mgmt = 0;
322d62bc4baSyz147064 dlbrp->dl_max_conind = 0;
323d62bc4baSyz147064 dlbrp->dl_xidtest_flg = 0;
324d62bc4baSyz147064 dlbrp->dl_service_mode = DL_CLDLS;
325d62bc4baSyz147064
326d62bc4baSyz147064 err = dl_op(lh, &mp, DL_BIND_ACK, DL_BIND_ACK_SIZE, dleap, NULL);
327d62bc4baSyz147064 if (err == 0) {
328d62bc4baSyz147064 dlbap = (dl_bind_ack_t *)mp->b_rptr;
329d62bc4baSyz147064 if (dlbap->dl_sap != sap) {
330d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_bind: DL_BIND_ACK: bad sap %u",
331d62bc4baSyz147064 dlbap->dl_sap);
332d62bc4baSyz147064 err = EPROTO;
333d62bc4baSyz147064 }
334d62bc4baSyz147064 freemsg(mp);
335d62bc4baSyz147064 }
336d62bc4baSyz147064 return (err);
337d62bc4baSyz147064 }
338d62bc4baSyz147064
339d62bc4baSyz147064 /*
340d62bc4baSyz147064 * Send a DL_PHYS_ADDR_REQ over `lh' and wait for the response. The caller
341d62bc4baSyz147064 * must set `*physlenp' to the size of `physaddr' (both of which must be
342d62bc4baSyz147064 * non-NULL); upon success they will be updated to contain the actual physical
343d62bc4baSyz147064 * address and length.
344d62bc4baSyz147064 *
345d62bc4baSyz147064 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
346d62bc4baSyz147064 * caller can get the contents by passing a non-NULL `dleap').
347d62bc4baSyz147064 */
348d62bc4baSyz147064 int
dl_phys_addr(ldi_handle_t lh,uchar_t * physaddr,size_t * physlenp,dl_error_ack_t * dleap)349d62bc4baSyz147064 dl_phys_addr(ldi_handle_t lh, uchar_t *physaddr, size_t *physlenp,
350d62bc4baSyz147064 dl_error_ack_t *dleap)
351d62bc4baSyz147064 {
352d62bc4baSyz147064 dl_phys_addr_ack_t *dlpap;
353d62bc4baSyz147064 mblk_t *mp;
354d62bc4baSyz147064 int err;
355d62bc4baSyz147064 t_uscalar_t paddrlen, paddroff;
356d62bc4baSyz147064 timestruc_t tv;
357d62bc4baSyz147064
358d62bc4baSyz147064 mp = mexchange(NULL, NULL, DL_PHYS_ADDR_REQ_SIZE, M_PROTO,
359d62bc4baSyz147064 DL_PHYS_ADDR_REQ);
360d62bc4baSyz147064 if (mp == NULL)
361d62bc4baSyz147064 return (ENOMEM);
362d62bc4baSyz147064
363d62bc4baSyz147064 ((dl_phys_addr_req_t *)mp->b_rptr)->dl_addr_type = DL_CURR_PHYS_ADDR;
364d62bc4baSyz147064
365d62bc4baSyz147064 /*
366d62bc4baSyz147064 * In case some provider doesn't implement or NAK the
367d62bc4baSyz147064 * request, just wait for 15 seconds.
368d62bc4baSyz147064 */
369d62bc4baSyz147064 tv.tv_sec = 15;
370d62bc4baSyz147064 tv.tv_nsec = 0;
371d62bc4baSyz147064
372d62bc4baSyz147064 err = dl_op(lh, &mp, DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, dleap,
373d62bc4baSyz147064 &tv);
374d62bc4baSyz147064 if (err == 0) {
375d62bc4baSyz147064 dlpap = (dl_phys_addr_ack_t *)mp->b_rptr;
376d62bc4baSyz147064 paddrlen = dlpap->dl_addr_length;
377d62bc4baSyz147064 paddroff = dlpap->dl_addr_offset;
378d62bc4baSyz147064 if (paddroff == 0 || paddrlen == 0 || paddrlen > *physlenp ||
379d62bc4baSyz147064 !MBLKIN(mp, paddroff, paddrlen)) {
380d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_phys_addr: DL_PHYS_ADDR_ACK: "
381d62bc4baSyz147064 "bad length/offset %d/%d", paddrlen, paddroff);
382d62bc4baSyz147064 err = EBADMSG;
383d62bc4baSyz147064 } else {
384d62bc4baSyz147064 bcopy(mp->b_rptr + paddroff, physaddr, paddrlen);
385d62bc4baSyz147064 *physlenp = paddrlen;
386d62bc4baSyz147064 }
387d62bc4baSyz147064 freemsg(mp);
388d62bc4baSyz147064 }
389d62bc4baSyz147064 return (err);
390d62bc4baSyz147064 }
391d62bc4baSyz147064
392d62bc4baSyz147064 /*
393d62bc4baSyz147064 * Send a DL_INFO_REQ over `lh' and wait for the response. The caller must
394d62bc4baSyz147064 * pass a non-NULL `dliap', which upon success will contain the dl_info_ack_t
395d62bc4baSyz147064 * from the provider. The caller may optionally get the provider's physical
396d62bc4baSyz147064 * address by passing a non-NULL `physaddr' and setting `*physlenp' to its
397d62bc4baSyz147064 * size; upon success they will be updated to contain the actual physical
398d62bc4baSyz147064 * address and its length.
399d62bc4baSyz147064 *
400d62bc4baSyz147064 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
401d62bc4baSyz147064 * caller can get the contents by passing a non-NULL `dleap').
402d62bc4baSyz147064 */
403d62bc4baSyz147064 int
dl_info(ldi_handle_t lh,dl_info_ack_t * dliap,uchar_t * physaddr,size_t * physlenp,dl_error_ack_t * dleap)404d62bc4baSyz147064 dl_info(ldi_handle_t lh, dl_info_ack_t *dliap, uchar_t *physaddr,
405d62bc4baSyz147064 size_t *physlenp, dl_error_ack_t *dleap)
406d62bc4baSyz147064 {
407d62bc4baSyz147064 mblk_t *mp;
408d62bc4baSyz147064 int err;
409d62bc4baSyz147064 int addrlen, addroff;
410d62bc4baSyz147064
411d62bc4baSyz147064 mp = mexchange(NULL, NULL, DL_INFO_REQ_SIZE, M_PCPROTO, DL_INFO_REQ);
412d62bc4baSyz147064 if (mp == NULL)
413d62bc4baSyz147064 return (ENOMEM);
414d62bc4baSyz147064
415d62bc4baSyz147064 err = dl_op(lh, &mp, DL_INFO_ACK, DL_INFO_ACK_SIZE, dleap, NULL);
416d62bc4baSyz147064 if (err != 0)
417d62bc4baSyz147064 return (err);
418d62bc4baSyz147064
419d62bc4baSyz147064 *dliap = *(dl_info_ack_t *)mp->b_rptr;
420d62bc4baSyz147064 if (physaddr != NULL) {
421d62bc4baSyz147064 addrlen = dliap->dl_addr_length - ABS(dliap->dl_sap_length);
422d62bc4baSyz147064 addroff = dliap->dl_addr_offset;
423d62bc4baSyz147064 if (addroff == 0 || addrlen <= 0 || addrlen > *physlenp ||
424d62bc4baSyz147064 !MBLKIN(mp, addroff, dliap->dl_addr_length)) {
425d62bc4baSyz147064 cmn_err(CE_NOTE, "!dl_info: DL_INFO_ACK: "
426d62bc4baSyz147064 "bad length/offset %d/%d", addrlen, addroff);
427d62bc4baSyz147064 freemsg(mp);
428d62bc4baSyz147064 return (EBADMSG);
429d62bc4baSyz147064 }
430d62bc4baSyz147064
431d62bc4baSyz147064 if (dliap->dl_sap_length > 0)
432d62bc4baSyz147064 addroff += dliap->dl_sap_length;
433d62bc4baSyz147064 bcopy(mp->b_rptr + addroff, physaddr, addrlen);
434d62bc4baSyz147064 *physlenp = addrlen;
435d62bc4baSyz147064 }
436d62bc4baSyz147064 freemsg(mp);
437d62bc4baSyz147064 return (err);
438d62bc4baSyz147064 }
439d62bc4baSyz147064
440d62bc4baSyz147064 /*
441d62bc4baSyz147064 * Send a DL_NOTIFY_REQ over `lh' and wait for the response. The caller
442d62bc4baSyz147064 * should set `notesp' to the set of notifications they wish to enable;
443d62bc4baSyz147064 * upon success it will contain the notifications enabled by the provider.
444d62bc4baSyz147064 *
445d62bc4baSyz147064 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
446d62bc4baSyz147064 * caller can get the contents by passing a non-NULL `dleap').
447d62bc4baSyz147064 */
448d62bc4baSyz147064 int
dl_notify(ldi_handle_t lh,uint32_t * notesp,dl_error_ack_t * dleap)449d62bc4baSyz147064 dl_notify(ldi_handle_t lh, uint32_t *notesp, dl_error_ack_t *dleap)
450d62bc4baSyz147064 {
451d62bc4baSyz147064 mblk_t *mp;
452d62bc4baSyz147064 int err;
453d62bc4baSyz147064
454d62bc4baSyz147064 mp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
455d62bc4baSyz147064 if (mp == NULL)
456d62bc4baSyz147064 return (ENOMEM);
457d62bc4baSyz147064
458d62bc4baSyz147064 ((dl_notify_req_t *)mp->b_rptr)->dl_notifications = *notesp;
459d62bc4baSyz147064
460d62bc4baSyz147064 err = dl_op(lh, &mp, DL_NOTIFY_ACK, DL_NOTIFY_ACK_SIZE, dleap, NULL);
461d62bc4baSyz147064 if (err == 0) {
462d62bc4baSyz147064 *notesp = ((dl_notify_ack_t *)mp->b_rptr)->dl_notifications;
463d62bc4baSyz147064 freemsg(mp);
464d62bc4baSyz147064 }
465d62bc4baSyz147064 return (err);
466d62bc4baSyz147064 }
467d62bc4baSyz147064
468d62bc4baSyz147064 const char *
dl_primstr(t_uscalar_t prim)469d62bc4baSyz147064 dl_primstr(t_uscalar_t prim)
470d62bc4baSyz147064 {
471d62bc4baSyz147064 switch (prim) {
472d62bc4baSyz147064 case DL_INFO_REQ: return ("DL_INFO_REQ");
473d62bc4baSyz147064 case DL_INFO_ACK: return ("DL_INFO_ACK");
474d62bc4baSyz147064 case DL_ATTACH_REQ: return ("DL_ATTACH_REQ");
475d62bc4baSyz147064 case DL_DETACH_REQ: return ("DL_DETACH_REQ");
476d62bc4baSyz147064 case DL_BIND_REQ: return ("DL_BIND_REQ");
477d62bc4baSyz147064 case DL_BIND_ACK: return ("DL_BIND_ACK");
478d62bc4baSyz147064 case DL_UNBIND_REQ: return ("DL_UNBIND_REQ");
479d62bc4baSyz147064 case DL_OK_ACK: return ("DL_OK_ACK");
480d62bc4baSyz147064 case DL_ERROR_ACK: return ("DL_ERROR_ACK");
481d62bc4baSyz147064 case DL_ENABMULTI_REQ: return ("DL_ENABMULTI_REQ");
482d62bc4baSyz147064 case DL_DISABMULTI_REQ: return ("DL_DISABMULTI_REQ");
483d62bc4baSyz147064 case DL_PROMISCON_REQ: return ("DL_PROMISCON_REQ");
484d62bc4baSyz147064 case DL_PROMISCOFF_REQ: return ("DL_PROMISCOFF_REQ");
485d62bc4baSyz147064 case DL_UNITDATA_REQ: return ("DL_UNITDATA_REQ");
486d62bc4baSyz147064 case DL_UNITDATA_IND: return ("DL_UNITDATA_IND");
487d62bc4baSyz147064 case DL_UDERROR_IND: return ("DL_UDERROR_IND");
488d62bc4baSyz147064 case DL_PHYS_ADDR_REQ: return ("DL_PHYS_ADDR_REQ");
489d62bc4baSyz147064 case DL_PHYS_ADDR_ACK: return ("DL_PHYS_ADDR_ACK");
490d62bc4baSyz147064 case DL_SET_PHYS_ADDR_REQ: return ("DL_SET_PHYS_ADDR_REQ");
491d62bc4baSyz147064 case DL_NOTIFY_REQ: return ("DL_NOTIFY_REQ");
492d62bc4baSyz147064 case DL_NOTIFY_ACK: return ("DL_NOTIFY_ACK");
493d62bc4baSyz147064 case DL_NOTIFY_IND: return ("DL_NOTIFY_IND");
494*5d460eafSCathy Zhou case DL_NOTIFY_CONF: return ("DL_NOTIFY_CONF");
495d62bc4baSyz147064 case DL_CAPABILITY_REQ: return ("DL_CAPABILITY_REQ");
496d62bc4baSyz147064 case DL_CAPABILITY_ACK: return ("DL_CAPABILITY_ACK");
497d62bc4baSyz147064 case DL_CONTROL_REQ: return ("DL_CONTROL_REQ");
498d62bc4baSyz147064 case DL_CONTROL_ACK: return ("DL_CONTROL_ACK");
499d62bc4baSyz147064 case DL_PASSIVE_REQ: return ("DL_PASSIVE_REQ");
500d62bc4baSyz147064 case DL_INTR_MODE_REQ: return ("DL_INTR_MODE_REQ");
501d62bc4baSyz147064 case DL_UDQOS_REQ: return ("DL_UDQOS_REQ");
502d62bc4baSyz147064 default: return ("<unknown primitive>");
503d62bc4baSyz147064 }
504d62bc4baSyz147064 }
505d62bc4baSyz147064
506d62bc4baSyz147064 const char *
dl_errstr(t_uscalar_t err)507d62bc4baSyz147064 dl_errstr(t_uscalar_t err)
508d62bc4baSyz147064 {
509d62bc4baSyz147064 switch (err) {
510d62bc4baSyz147064 case DL_ACCESS: return ("DL_ACCESS");
511d62bc4baSyz147064 case DL_BADADDR: return ("DL_BADADDR");
512d62bc4baSyz147064 case DL_BADCORR: return ("DL_BADCORR");
513d62bc4baSyz147064 case DL_BADDATA: return ("DL_BADDATA");
514d62bc4baSyz147064 case DL_BADPPA: return ("DL_BADPPA");
515d62bc4baSyz147064 case DL_BADPRIM: return ("DL_BADPRIM");
516d62bc4baSyz147064 case DL_BADQOSPARAM: return ("DL_BADQOSPARAM");
517d62bc4baSyz147064 case DL_BADQOSTYPE: return ("DL_BADQOSTYPE");
518d62bc4baSyz147064 case DL_BADSAP: return ("DL_BADSAP");
519d62bc4baSyz147064 case DL_BADTOKEN: return ("DL_BADTOKEN");
520d62bc4baSyz147064 case DL_BOUND: return ("DL_BOUND");
521d62bc4baSyz147064 case DL_INITFAILED: return ("DL_INITFAILED");
522d62bc4baSyz147064 case DL_NOADDR: return ("DL_NOADDR");
523d62bc4baSyz147064 case DL_NOTINIT: return ("DL_NOTINIT");
524d62bc4baSyz147064 case DL_OUTSTATE: return ("DL_OUTSTATE");
525d62bc4baSyz147064 case DL_SYSERR: return ("DL_SYSERR");
526d62bc4baSyz147064 case DL_UNSUPPORTED: return ("DL_UNSUPPORTED");
527d62bc4baSyz147064 case DL_UNDELIVERABLE: return ("DL_UNDELIVERABLE");
528d62bc4baSyz147064 case DL_NOTSUPPORTED: return ("DL_NOTSUPPORTED ");
529d62bc4baSyz147064 case DL_TOOMANY: return ("DL_TOOMANY");
530d62bc4baSyz147064 case DL_NOTENAB: return ("DL_NOTENAB");
531d62bc4baSyz147064 case DL_BUSY: return ("DL_BUSY");
532d62bc4baSyz147064 case DL_NOAUTO: return ("DL_NOAUTO");
533d62bc4baSyz147064 case DL_NOXIDAUTO: return ("DL_NOXIDAUTO");
534d62bc4baSyz147064 case DL_NOTESTAUTO: return ("DL_NOTESTAUTO");
535d62bc4baSyz147064 case DL_XIDAUTO: return ("DL_XIDAUTO");
536d62bc4baSyz147064 case DL_TESTAUTO: return ("DL_TESTAUTO");
537d62bc4baSyz147064 case DL_PENDING: return ("DL_PENDING");
538d62bc4baSyz147064 default: return ("<unknown error>");
539d62bc4baSyz147064 }
540d62bc4baSyz147064 }
541d62bc4baSyz147064
542d62bc4baSyz147064 const char *
dl_mactypestr(t_uscalar_t mactype)543d62bc4baSyz147064 dl_mactypestr(t_uscalar_t mactype)
544d62bc4baSyz147064 {
545d62bc4baSyz147064 switch (mactype) {
546d62bc4baSyz147064 case DL_CSMACD: return ("CSMA/CD");
547d62bc4baSyz147064 case DL_TPB: return ("Token Bus");
548d62bc4baSyz147064 case DL_TPR: return ("Token Ring");
549d62bc4baSyz147064 case DL_METRO: return ("Metro Net");
550d62bc4baSyz147064 case DL_ETHER: return ("Ethernet");
551d62bc4baSyz147064 case DL_HDLC: return ("HDLC");
552d62bc4baSyz147064 case DL_CHAR: return ("Sync Character");
553d62bc4baSyz147064 case DL_CTCA: return ("CTCA");
554d62bc4baSyz147064 case DL_FDDI: return ("FDDI");
555d62bc4baSyz147064 case DL_FRAME: return ("Frame Relay (LAPF)");
556d62bc4baSyz147064 case DL_MPFRAME: return ("MP Frame Relay");
557d62bc4baSyz147064 case DL_ASYNC: return ("Async Character");
558d62bc4baSyz147064 case DL_IPX25: return ("X.25 (Classic IP)");
559d62bc4baSyz147064 case DL_LOOP: return ("Software Loopback");
560d62bc4baSyz147064 case DL_FC: return ("Fiber Channel");
561d62bc4baSyz147064 case DL_ATM: return ("ATM");
562d62bc4baSyz147064 case DL_IPATM: return ("ATM (Classic IP)");
563d62bc4baSyz147064 case DL_X25: return ("X.25 (LAPB)");
564d62bc4baSyz147064 case DL_ISDN: return ("ISDN");
565d62bc4baSyz147064 case DL_HIPPI: return ("HIPPI");
566d62bc4baSyz147064 case DL_100VG: return ("100BaseVG Ethernet");
567d62bc4baSyz147064 case DL_100VGTPR: return ("100BaseVG Token Ring");
568d62bc4baSyz147064 case DL_ETH_CSMA: return ("Ethernet/IEEE 802.3");
569d62bc4baSyz147064 case DL_100BT: return ("100BaseT");
570d62bc4baSyz147064 case DL_IB: return ("Infiniband");
571d62bc4baSyz147064 case DL_IPV4: return ("IPv4 Tunnel");
572d62bc4baSyz147064 case DL_IPV6: return ("IPv6 Tunnel");
573d62bc4baSyz147064 case DL_WIFI: return ("IEEE 802.11");
574b127ac41SPhilip Kirk case DL_IPNET: return ("IPNET");
575d62bc4baSyz147064 default: return ("<unknown mactype>");
576d62bc4baSyz147064 }
577d62bc4baSyz147064 }
578