Print this page
4823 don't open-code NSEC2MSEC and MSEC2NSEC
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libdlpi/common/libdlpi.c
+++ new/usr/src/lib/libdlpi/common/libdlpi.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Data-Link Provider Interface (Version 2)
28 28 */
29 29 #include <stdio.h>
30 30 #include <stdlib.h>
31 31 #include <string.h>
32 32 #include <sys/types.h>
33 33 #include <sys/stat.h>
34 34 #include <fcntl.h>
35 35 #include <unistd.h>
36 36 #include <poll.h>
37 37 #include <stropts.h>
38 38 #include <sys/dlpi.h>
39 39 #include <errno.h>
40 40 #include <alloca.h>
41 41 #include <sys/sysmacros.h>
42 42 #include <ctype.h>
43 43 #include <net/if_types.h>
44 44 #include <netinet/arp.h>
45 45 #include <libdladm.h>
46 46 #include <libdllink.h>
47 47 #include <libdlpi.h>
48 48 #include <libintl.h>
49 49 #include <libinetutil.h>
50 50 #include <dirent.h>
51 51
52 52 #include "libdlpi_impl.h"
53 53
54 54 static int i_dlpi_open(const char *, int *, uint_t, boolean_t);
55 55 static int i_dlpi_style1_open(dlpi_impl_t *);
56 56 static int i_dlpi_style2_open(dlpi_impl_t *);
57 57 static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t);
58 58 static int i_dlpi_attach(dlpi_impl_t *);
59 59 static void i_dlpi_passive(dlpi_impl_t *);
60 60
61 61 static int i_dlpi_strputmsg(dlpi_impl_t *, const dlpi_msg_t *, const void *,
62 62 size_t, int);
63 63 static int i_dlpi_strgetmsg(dlpi_impl_t *, int, dlpi_msg_t *, t_uscalar_t,
64 64 t_uscalar_t, size_t, void *, size_t *, size_t *);
65 65 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *,
66 66 size_t, int);
67 67
68 68 static size_t i_dlpi_getprimsize(t_uscalar_t);
69 69 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t);
70 70 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t);
71 71 static uint_t i_dlpi_buildsap(uint8_t *, uint_t);
72 72 static void i_dlpi_writesap(void *, uint_t, uint_t);
73 73 static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *);
74 74 static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *);
75 75 static void i_dlpi_deletenotifyid(dlpi_impl_t *);
76 76
77 77 struct i_dlpi_walklink_arg {
78 78 dlpi_walkfunc_t *fn;
79 79 void *arg;
80 80 };
81 81
82 82 static int
83 83 i_dlpi_walk_link(const char *name, void *arg)
84 84 {
85 85 struct i_dlpi_walklink_arg *warg = arg;
86 86
87 87 return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE :
88 88 DLADM_WALK_CONTINUE);
89 89 }
90 90
91 91 /*ARGSUSED*/
92 92 void
93 93 dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags)
94 94 {
95 95 struct i_dlpi_walklink_arg warg;
96 96 struct dirent *d;
97 97 DIR *dp;
98 98 dladm_handle_t handle;
99 99
100 100 warg.fn = fn;
101 101 warg.arg = arg;
102 102
103 103 if (flags & DLPI_DEVIPNET) {
104 104 if ((dp = opendir("/dev/ipnet")) == NULL)
105 105 return;
106 106
107 107 while ((d = readdir(dp)) != NULL) {
108 108 if (d->d_name[0] == '.')
109 109 continue;
110 110
111 111 if (warg.fn(d->d_name, warg.arg))
112 112 break;
113 113 }
114 114
115 115 (void) closedir(dp);
116 116 } else {
117 117 /*
118 118 * Rather than have libdlpi take the libdladm handle,
119 119 * open the handle here.
120 120 */
121 121 if (dladm_open(&handle) != DLADM_STATUS_OK)
122 122 return;
123 123
124 124 (void) dladm_walk(i_dlpi_walk_link, handle, &warg,
125 125 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
126 126 DLADM_OPT_ACTIVE);
127 127
128 128 dladm_close(handle);
129 129 }
130 130 }
131 131
132 132 int
133 133 dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
134 134 {
135 135 int retval, on = 1;
136 136 ifspec_t ifsp;
137 137 dlpi_impl_t *dip;
138 138
139 139 /*
140 140 * Validate linkname, fail if logical unit number (lun) is specified,
141 141 * otherwise decompose the contents into ifsp.
142 142 */
143 143 if (linkname == NULL || (strchr(linkname, ':') != NULL) ||
144 144 !ifparse_ifspec(linkname, &ifsp))
145 145 return (DLPI_ELINKNAMEINVAL);
146 146
147 147 /*
148 148 * Ensure flags values are sane.
149 149 */
150 150 if ((flags & (DLPI_DEVIPNET|DLPI_DEVONLY)) ==
151 151 (DLPI_DEVIPNET|DLPI_DEVONLY))
152 152 return (DLPI_EINVAL);
153 153
154 154 /* Allocate a new dlpi_impl_t. */
155 155 if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL)
156 156 return (DL_SYSERR);
157 157
158 158 /* Fill in known/default libdlpi handle values. */
159 159 dip->dli_timeout = DLPI_DEF_TIMEOUT;
160 160 dip->dli_ppa = ifsp.ifsp_ppa;
161 161 dip->dli_oflags = flags;
162 162 dip->dli_notifylistp = NULL;
163 163 dip->dli_note_processing = B_FALSE;
164 164 if (getenv("DLPI_DEVONLY") != NULL)
165 165 dip->dli_oflags |= DLPI_DEVONLY;
166 166
167 167 /* Copy linkname provided to the function. */
168 168 if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >=
169 169 sizeof (dip->dli_linkname)) {
170 170 free(dip);
171 171 return (DLPI_ELINKNAMEINVAL);
172 172 }
173 173
174 174 /* Copy provider name. */
175 175 (void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm,
176 176 sizeof (dip->dli_provider));
177 177
178 178 /*
179 179 * Special case: DLPI_SERIAL flag is set to indicate a synchronous
180 180 * serial line interface (see syncinit(1M), syncstat(1M),
181 181 * syncloop(1M)), which is not a DLPI link.
182 182 */
183 183 if (dip->dli_oflags & DLPI_SERIAL) {
184 184 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) {
185 185 free(dip);
186 186 return (retval);
187 187 }
188 188
189 189 *dhp = (dlpi_handle_t)dip;
190 190 return (retval);
191 191 }
192 192
193 193 if ((retval = i_dlpi_style1_open(dip)) != DLPI_SUCCESS) {
194 194 if (retval == DLPI_ENOTSTYLE2) {
195 195 /*
196 196 * The error code indicates not to continue the
197 197 * style-2 open. Change the error code back to
198 198 * DL_SYSERR, so that one would know the cause
199 199 * of failure from errno.
200 200 */
201 201 retval = DL_SYSERR;
202 202 } else if (!(dip->dli_oflags & DLPI_DEVIPNET)) {
203 203 retval = i_dlpi_style2_open(dip);
204 204 }
205 205 if (retval != DLPI_SUCCESS) {
206 206 free(dip);
207 207 return (retval);
208 208 }
209 209 }
210 210
211 211 if (dip->dli_oflags & DLPI_PASSIVE)
212 212 i_dlpi_passive(dip);
213 213
214 214 if ((dip->dli_oflags & DLPI_RAW) &&
215 215 ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) {
216 216 dlpi_close((dlpi_handle_t)dip);
217 217 return (DLPI_ERAWNOTSUP);
218 218 }
219 219
220 220 if ((dip->dli_oflags & DLPI_IPNETINFO) &&
221 221 ioctl(dip->dli_fd, DLIOCIPNETINFO, &on) < 0) {
222 222 dlpi_close((dlpi_handle_t)dip);
223 223 return (DLPI_EIPNETINFONOTSUP);
224 224 }
225 225
226 226 /*
227 227 * We intentionally do not care if this request fails, as this
228 228 * indicates the underlying DLPI device does not support Native mode
229 229 * (pre-GLDV3 device drivers).
230 230 */
231 231 if (dip->dli_oflags & DLPI_NATIVE) {
232 232 if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0)
233 233 dip->dli_mactype = retval;
234 234 }
235 235
236 236 *dhp = (dlpi_handle_t)dip;
237 237 return (DLPI_SUCCESS);
238 238 }
239 239
240 240 void
241 241 dlpi_close(dlpi_handle_t dh)
242 242 {
243 243 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
244 244 dlpi_notifyent_t *next, *dnp;
245 245
246 246 if (dip != NULL) {
247 247 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = next) {
248 248 next = dnp->dln_next;
249 249 free(dnp);
250 250 }
251 251
252 252 (void) close(dip->dli_fd);
253 253 free(dip);
254 254 }
255 255 }
256 256
257 257 /*
258 258 * NOTE: The opt argument must be zero and is reserved for future use to extend
259 259 * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)).
260 260 */
261 261 int
262 262 dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt)
263 263 {
264 264 int retval;
265 265 dlpi_msg_t req, ack;
266 266 dl_info_ack_t *infoackp;
267 267 uint8_t *sapp, *addrp;
268 268 caddr_t ackendp, datap;
269 269 t_uscalar_t dataoff, datalen;
270 270 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
271 271
272 272 if (dip == NULL)
273 273 return (DLPI_EINHANDLE);
274 274
275 275 if (infop == NULL || opt != 0)
276 276 return (DLPI_EINVAL);
277 277
278 278 (void) memset(infop, 0, sizeof (dlpi_info_t));
279 279
280 280 /* Set QoS range parameters to default unsupported value. */
281 281 infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
282 282 infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN;
283 283 infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN;
284 284 infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN;
285 285 infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN;
286 286 infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN;
287 287 infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN;
288 288 infop->di_qos_range.dl_residual_error = DL_UNKNOWN;
289 289
290 290 /* Set QoS parameters to default unsupported value. */
291 291 infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
292 292 infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN;
293 293 infop->di_qos_sel.dl_priority = DL_UNKNOWN;
294 294 infop->di_qos_sel.dl_protection = DL_UNKNOWN;
295 295 infop->di_qos_sel.dl_residual_error = DL_UNKNOWN;
296 296
297 297 DLPI_MSG_CREATE(req, DL_INFO_REQ);
298 298 DLPI_MSG_CREATE(ack, DL_INFO_ACK);
299 299
300 300 retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI);
301 301 if (retval != DLPI_SUCCESS)
302 302 return (retval);
303 303
304 304 infoackp = &(ack.dlm_msg->info_ack);
305 305 if (infoackp->dl_version != DL_VERSION_2)
306 306 return (DLPI_EVERNOTSUP);
307 307
308 308 if (infoackp->dl_service_mode != DL_CLDLS)
309 309 return (DLPI_EMODENOTSUP);
310 310
311 311 dip->dli_style = infoackp->dl_provider_style;
312 312 dip->dli_mactype = infoackp->dl_mac_type;
313 313
314 314 ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
315 315
316 316 /* Check and save QoS selection information, if any. */
317 317 datalen = infoackp->dl_qos_length;
318 318 dataoff = infoackp->dl_qos_offset;
319 319 if (dataoff != 0 && datalen != 0) {
320 320 datap = (caddr_t)infoackp + dataoff;
321 321 if (datalen > sizeof (dl_qos_cl_sel1_t) ||
322 322 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
323 323 return (DLPI_EBADMSG);
324 324
325 325 (void) memcpy(&infop->di_qos_sel, datap, datalen);
326 326 if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1)
327 327 return (DLPI_EMODENOTSUP);
328 328 }
329 329
330 330 /* Check and save QoS range information, if any. */
331 331 datalen = infoackp->dl_qos_range_length;
332 332 dataoff = infoackp->dl_qos_range_offset;
333 333 if (dataoff != 0 && datalen != 0) {
334 334 datap = (caddr_t)infoackp + dataoff;
335 335 if (datalen > sizeof (dl_qos_cl_range1_t) ||
336 336 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
337 337 return (DLPI_EBADMSG);
338 338
339 339 (void) memcpy(&infop->di_qos_range, datap, datalen);
340 340 if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1)
341 341 return (DLPI_EMODENOTSUP);
342 342 }
343 343
344 344 /* Check and save physical address and SAP information. */
345 345 dip->dli_saplen = abs(infoackp->dl_sap_length);
346 346 dip->dli_sapbefore = (infoackp->dl_sap_length > 0);
347 347 infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen;
348 348
349 349 if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX ||
350 350 dip->dli_saplen > DLPI_SAPLEN_MAX)
351 351 return (DL_BADADDR);
352 352
353 353 dataoff = infoackp->dl_addr_offset;
354 354 datalen = infoackp->dl_addr_length;
355 355 if (dataoff != 0 && datalen != 0) {
356 356 datap = (caddr_t)infoackp + dataoff;
357 357 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
358 358 return (DLPI_EBADMSG);
359 359
360 360 sapp = addrp = (uint8_t *)datap;
361 361 if (dip->dli_sapbefore)
362 362 addrp += dip->dli_saplen;
363 363 else
364 364 sapp += infop->di_physaddrlen;
365 365
366 366 (void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen);
367 367 infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen);
368 368 }
369 369
370 370 /* Check and save broadcast address information, if any. */
371 371 datalen = infoackp->dl_brdcst_addr_length;
372 372 dataoff = infoackp->dl_brdcst_addr_offset;
373 373 if (dataoff != 0 && datalen != 0) {
374 374 datap = (caddr_t)infoackp + dataoff;
375 375 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
376 376 return (DLPI_EBADMSG);
377 377 if (datalen != infop->di_physaddrlen)
378 378 return (DL_BADADDR);
379 379
380 380 infop->di_bcastaddrlen = datalen;
381 381 (void) memcpy(infop->di_bcastaddr, datap, datalen);
382 382 }
383 383
384 384 infop->di_max_sdu = infoackp->dl_max_sdu;
385 385 infop->di_min_sdu = infoackp->dl_min_sdu;
386 386 infop->di_state = infoackp->dl_current_state;
387 387 infop->di_mactype = infoackp->dl_mac_type;
388 388
389 389 /* Information retrieved from the handle. */
390 390 (void) strlcpy(infop->di_linkname, dip->dli_linkname,
391 391 sizeof (infop->di_linkname));
392 392 infop->di_timeout = dip->dli_timeout;
393 393
394 394 return (DLPI_SUCCESS);
395 395 }
396 396
397 397 /*
398 398 * This function parses 'linkname' and stores the 'provider' name and 'PPA'.
399 399 */
400 400 int
401 401 dlpi_parselink(const char *linkname, char *provider, uint_t *ppa)
402 402 {
403 403 dladm_status_t status;
404 404
405 405 status = dladm_parselink(linkname, provider, ppa);
406 406
407 407 if (status != DLADM_STATUS_OK)
408 408 return (DLPI_ELINKNAMEINVAL);
409 409
410 410 return (DLPI_SUCCESS);
411 411 }
412 412
413 413 /*
414 414 * This function takes a provider name and a PPA and stores a full linkname
415 415 * as 'linkname'. If 'provider' already is a full linkname 'provider' name
416 416 * is stored in 'linkname'.
417 417 */
418 418 int
419 419 dlpi_makelink(char *linkname, const char *provider, uint_t ppa)
420 420 {
421 421 int provlen = strlen(provider);
422 422
423 423 if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX)
424 424 return (DLPI_ELINKNAMEINVAL);
425 425
426 426 if (!isdigit(provider[provlen - 1])) {
427 427 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider,
428 428 ppa);
429 429 } else {
430 430 (void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX);
431 431 }
432 432
433 433 return (DLPI_SUCCESS);
434 434 }
435 435
436 436 int
437 437 dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap)
438 438 {
439 439 int retval;
440 440 dlpi_msg_t req, ack;
441 441 dl_bind_req_t *bindreqp;
442 442 dl_bind_ack_t *bindackp;
443 443 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
444 444
445 445 if (dip == NULL)
446 446 return (DLPI_EINHANDLE);
447 447
448 448 DLPI_MSG_CREATE(req, DL_BIND_REQ);
449 449 DLPI_MSG_CREATE(ack, DL_BIND_ACK);
450 450 bindreqp = &(req.dlm_msg->bind_req);
451 451
452 452 /*
453 453 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on
454 454 * other interface types (SAP 0 has special significance on token ring).
455 455 */
456 456 if (sap == DLPI_ANY_SAP)
457 457 bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0);
458 458 else
459 459 bindreqp->dl_sap = sap;
460 460
461 461 bindreqp->dl_service_mode = DL_CLDLS;
462 462 bindreqp->dl_conn_mgmt = 0;
463 463 bindreqp->dl_max_conind = 0;
464 464 bindreqp->dl_xidtest_flg = 0;
465 465
466 466 retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0);
467 467 if (retval != DLPI_SUCCESS)
468 468 return (retval);
469 469
470 470 bindackp = &(ack.dlm_msg->bind_ack);
471 471 /*
472 472 * Received a DLPI_BIND_ACK, now verify that the bound SAP
473 473 * is equal to the SAP requested. Some DLPI MAC type may bind
474 474 * to a different SAP than requested, in this case 'boundsap'
475 475 * returns the actual bound SAP. For the case where 'boundsap'
476 476 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails.
477 477 */
478 478 if (boundsap != NULL) {
479 479 *boundsap = bindackp->dl_sap;
480 480 } else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) {
481 481 if (dlpi_unbind(dh) != DLPI_SUCCESS)
482 482 return (DLPI_FAILURE);
483 483 else
484 484 return (DLPI_EUNAVAILSAP);
485 485 }
486 486
487 487 dip->dli_sap = bindackp->dl_sap; /* save sap value in handle */
488 488 return (DLPI_SUCCESS);
489 489 }
490 490
491 491 int
492 492 dlpi_unbind(dlpi_handle_t dh)
493 493 {
494 494 dlpi_msg_t req, ack;
495 495 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
496 496
497 497 if (dip == NULL)
498 498 return (DLPI_EINHANDLE);
499 499
500 500 DLPI_MSG_CREATE(req, DL_UNBIND_REQ);
501 501 DLPI_MSG_CREATE(ack, DL_OK_ACK);
502 502
503 503 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
504 504 }
505 505
506 506 /*
507 507 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and
508 508 * based on the "op" value, multicast address is enabled/disabled.
509 509 */
510 510 static int
511 511 i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp,
512 512 size_t addrlen)
513 513 {
514 514 dlpi_msg_t req, ack;
515 515 dl_enabmulti_req_t *multireqp;
516 516 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
517 517
518 518 if (dip == NULL)
519 519 return (DLPI_EINHANDLE);
520 520
521 521 if (addrlen > DLPI_PHYSADDR_MAX)
522 522 return (DLPI_EINVAL);
523 523
524 524 DLPI_MSG_CREATE(req, op);
525 525 DLPI_MSG_CREATE(ack, DL_OK_ACK);
526 526
527 527 multireqp = &(req.dlm_msg->enabmulti_req);
528 528 multireqp->dl_addr_length = addrlen;
529 529 multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t);
530 530 (void) memcpy(&multireqp[1], addrp, addrlen);
531 531
532 532 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
533 533 }
534 534
535 535 int
536 536 dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
537 537 {
538 538 return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen));
539 539 }
540 540
541 541 int
542 542 dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
543 543 {
544 544 return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen));
545 545 }
546 546
547 547 /*
548 548 * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based
549 549 * on the value of 'op', promiscuous mode is turned on/off at the specified
550 550 * 'level'.
551 551 */
552 552 static int
553 553 i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level)
554 554 {
555 555 dlpi_msg_t req, ack;
556 556 dl_promiscon_req_t *promiscreqp;
557 557 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
558 558
559 559 if (dip == NULL)
560 560 return (DLPI_EINHANDLE);
561 561
562 562 DLPI_MSG_CREATE(req, op);
563 563 DLPI_MSG_CREATE(ack, DL_OK_ACK);
564 564
565 565 promiscreqp = &(req.dlm_msg->promiscon_req);
566 566 promiscreqp->dl_level = level;
567 567
568 568 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
569 569 }
570 570
571 571 int
572 572 dlpi_promiscon(dlpi_handle_t dh, uint_t level)
573 573 {
574 574 return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level));
575 575 }
576 576
577 577 int
578 578 dlpi_promiscoff(dlpi_handle_t dh, uint_t level)
579 579 {
580 580 return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level));
581 581 }
582 582
583 583 int
584 584 dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp)
585 585 {
586 586 int retval;
587 587 dlpi_msg_t req, ack;
588 588 dl_phys_addr_req_t *physreqp;
589 589 dl_phys_addr_ack_t *physackp;
590 590 t_uscalar_t dataoff, datalen;
591 591 caddr_t datap, physackendp;
592 592 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
593 593
594 594 if (dip == NULL)
595 595 return (DLPI_EINHANDLE);
596 596
597 597 if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX)
598 598 return (DLPI_EINVAL);
599 599
600 600 DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ);
601 601 DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK);
602 602
603 603 physreqp = &(req.dlm_msg->physaddr_req);
604 604 physreqp->dl_addr_type = type;
605 605
606 606 retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0);
607 607 if (retval != DLPI_SUCCESS)
608 608 return (retval);
609 609
610 610 /* Received DL_PHYS_ADDR_ACK, store the physical address and length. */
611 611 physackp = &(ack.dlm_msg->physaddr_ack);
612 612 physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
613 613 dataoff = physackp->dl_addr_offset;
614 614 datalen = physackp->dl_addr_length;
615 615 if (dataoff != 0 && datalen != 0) {
616 616 datap = (caddr_t)physackp + dataoff;
617 617 if (datalen > DLPI_PHYSADDR_MAX)
618 618 return (DL_BADADDR);
619 619 if (dataoff < DL_PHYS_ADDR_ACK_SIZE ||
620 620 datap + datalen > physackendp)
621 621 return (DLPI_EBADMSG);
622 622
623 623 *addrlenp = physackp->dl_addr_length;
624 624 (void) memcpy(addrp, datap, datalen);
625 625 } else {
626 626 *addrlenp = datalen;
627 627 }
628 628
629 629 return (DLPI_SUCCESS);
630 630 }
631 631
632 632 int
633 633 dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp,
634 634 size_t addrlen)
635 635 {
636 636 dlpi_msg_t req, ack;
637 637 dl_set_phys_addr_req_t *setphysreqp;
638 638 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
639 639
640 640 if (dip == NULL)
641 641 return (DLPI_EINHANDLE);
642 642
643 643 if (addrp == NULL || type != DL_CURR_PHYS_ADDR ||
644 644 addrlen > DLPI_PHYSADDR_MAX)
645 645 return (DLPI_EINVAL);
646 646
647 647 DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ);
648 648 DLPI_MSG_CREATE(ack, DL_OK_ACK);
649 649
650 650 setphysreqp = &(req.dlm_msg->set_physaddr_req);
651 651 setphysreqp->dl_addr_length = addrlen;
652 652 setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
653 653 (void) memcpy(&setphysreqp[1], addrp, addrlen);
654 654
655 655 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
656 656 }
657 657
658 658 int
659 659 dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen,
660 660 const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp)
661 661 {
662 662 dlpi_msg_t req;
663 663 dl_unitdata_req_t *udatareqp;
664 664 uint_t sap;
665 665 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
666 666
667 667 if (dip == NULL)
668 668 return (DLPI_EINHANDLE);
669 669
670 670 if (dip->dli_oflags & DLPI_RAW)
671 671 return (i_dlpi_strputmsg(dip, NULL, msgbuf, msglen, 0));
672 672
673 673 if ((daddrlen > 0 && daddrp == NULL) || daddrlen > DLPI_PHYSADDR_MAX)
674 674 return (DLPI_EINVAL);
675 675
676 676 DLPI_MSG_CREATE(req, DL_UNITDATA_REQ);
677 677 udatareqp = &(req.dlm_msg->unitdata_req);
678 678
679 679 /* Set priority to default priority range. */
680 680 udatareqp->dl_priority.dl_min = 0;
681 681 udatareqp->dl_priority.dl_max = 0;
682 682
683 683 /* Use SAP value if specified otherwise use bound SAP value. */
684 684 if (sendp != NULL) {
685 685 sap = sendp->dsi_sap;
686 686 if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE)
687 687 udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min;
688 688 if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE)
689 689 udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max;
690 690 } else {
691 691 sap = dip->dli_sap;
692 692 }
693 693
694 694 udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen;
695 695 udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
696 696
697 697 /*
698 698 * Since `daddrp' only has the link-layer destination address,
699 699 * we must prepend or append the SAP (according to dli_sapbefore)
700 700 * to make a full DLPI address.
701 701 */
702 702 if (dip->dli_sapbefore) {
703 703 i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen);
704 704 (void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen,
705 705 daddrp, daddrlen);
706 706 } else {
707 707 (void) memcpy(&udatareqp[1], daddrp, daddrlen);
708 708 i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap,
709 709 dip->dli_saplen);
710 710 }
711 711
712 712 return (i_dlpi_strputmsg(dip, &req, msgbuf, msglen, 0));
713 713 }
714 714
715 715 int
716 716 dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf,
717 717 size_t *msglenp, int msec, dlpi_recvinfo_t *recvp)
718 718 {
719 719 int retval;
720 720 dlpi_msg_t ind;
721 721 size_t totmsglen;
722 722 dl_unitdata_ind_t *udatap;
723 723 t_uscalar_t dataoff, datalen;
724 724 caddr_t datap, indendp;
725 725 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
726 726
727 727 if (dip == NULL)
728 728 return (DLPI_EINHANDLE);
729 729 /*
730 730 * If handle is in raw mode ignore everything except total message
731 731 * length.
732 732 */
733 733 if (dip->dli_oflags & DLPI_RAW) {
734 734 retval = i_dlpi_strgetmsg(dip, msec, NULL, 0, 0, 0, msgbuf,
735 735 msglenp, &totmsglen);
736 736
737 737 if (retval == DLPI_SUCCESS && recvp != NULL)
738 738 recvp->dri_totmsglen = totmsglen;
739 739 return (retval);
740 740 }
741 741
742 742 DLPI_MSG_CREATE(ind, DL_UNITDATA_IND);
743 743 udatap = &(ind.dlm_msg->unitdata_ind);
744 744 indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz;
745 745
746 746 if ((retval = i_dlpi_strgetmsg(dip, msec, &ind, DL_UNITDATA_IND,
747 747 DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, msgbuf,
748 748 msglenp, &totmsglen)) != DLPI_SUCCESS)
749 749 return (retval);
750 750
751 751 /*
752 752 * If DLPI link provides source address, store source address in
753 753 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0.
754 754 */
755 755 if (saddrp != NULL && saddrlenp != NULL) {
756 756 if (*saddrlenp < DLPI_PHYSADDR_MAX)
757 757 return (DLPI_EINVAL);
758 758
759 759 dataoff = udatap->dl_src_addr_offset;
760 760 datalen = udatap->dl_src_addr_length;
761 761 if (dataoff != 0 && datalen != 0) {
762 762 datap = (caddr_t)udatap + dataoff;
763 763 if (dataoff < DL_UNITDATA_IND_SIZE ||
764 764 datap + datalen > indendp)
765 765 return (DLPI_EBADMSG);
766 766
767 767 *saddrlenp = datalen - dip->dli_saplen;
768 768 if (*saddrlenp > DLPI_PHYSADDR_MAX)
769 769 return (DL_BADADDR);
770 770
771 771 if (dip->dli_sapbefore)
772 772 datap += dip->dli_saplen;
773 773 (void) memcpy(saddrp, datap, *saddrlenp);
774 774 } else {
775 775 *saddrlenp = 0;
776 776 }
777 777 }
778 778
779 779 /*
780 780 * If destination address requested, check and save destination
781 781 * address, if any.
782 782 */
783 783 if (recvp != NULL) {
784 784 dataoff = udatap->dl_dest_addr_offset;
785 785 datalen = udatap->dl_dest_addr_length;
786 786 if (dataoff != 0 && datalen != 0) {
787 787 datap = (caddr_t)udatap + dataoff;
788 788 if (dataoff < DL_UNITDATA_IND_SIZE ||
789 789 datap + datalen > indendp)
790 790 return (DLPI_EBADMSG);
791 791
792 792 recvp->dri_destaddrlen = datalen - dip->dli_saplen;
793 793 if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX)
794 794 return (DL_BADADDR);
795 795
796 796 if (dip->dli_sapbefore)
797 797 datap += dip->dli_saplen;
798 798 (void) memcpy(recvp->dri_destaddr, datap,
799 799 recvp->dri_destaddrlen);
800 800 } else {
801 801 recvp->dri_destaddrlen = 0;
802 802 }
803 803
804 804 recvp->dri_destaddrtype = udatap->dl_group_address;
805 805 recvp->dri_totmsglen = totmsglen;
806 806 }
807 807
808 808 return (DLPI_SUCCESS);
809 809 }
810 810
811 811 int
812 812 dlpi_enabnotify(dlpi_handle_t dh, uint_t notes, dlpi_notifyfunc_t *funcp,
813 813 void *arg, dlpi_notifyid_t *id)
814 814 {
815 815 int retval;
816 816 dlpi_msg_t req, ack;
817 817 dl_notify_req_t *notifyreqp;
818 818 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
819 819 dlpi_notifyent_t *newnotifp;
820 820 dlpi_info_t dlinfo;
821 821
822 822 if (dip == NULL)
823 823 return (DLPI_EINHANDLE);
824 824
825 825 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
826 826 if (retval != DLPI_SUCCESS)
827 827 return (retval);
828 828
829 829 if (dip->dli_note_processing)
830 830 return (DLPI_FAILURE);
831 831
832 832 if (funcp == NULL || id == NULL)
833 833 return (DLPI_EINVAL);
834 834
835 835 if ((~DLPI_NOTIFICATION_TYPES & notes) ||
836 836 !(notes & DLPI_NOTIFICATION_TYPES))
837 837 return (DLPI_ENOTEINVAL);
838 838
839 839 DLPI_MSG_CREATE(req, DL_NOTIFY_REQ);
840 840 DLPI_MSG_CREATE(ack, DL_NOTIFY_ACK);
841 841
842 842 notifyreqp = &(req.dlm_msg->notify_req);
843 843 notifyreqp->dl_notifications = notes;
844 844 notifyreqp->dl_timelimit = 0;
845 845
846 846 retval = i_dlpi_msg_common(dip, &req, &ack, DL_NOTIFY_ACK_SIZE, 0);
847 847 if (retval == DL_NOTSUPPORTED)
848 848 return (DLPI_ENOTENOTSUP);
849 849
850 850 if (retval != DLPI_SUCCESS)
851 851 return (retval);
852 852
853 853 if ((newnotifp = calloc(1, sizeof (dlpi_notifyent_t))) == NULL)
854 854 return (DL_SYSERR);
855 855
856 856 /* Register notification information. */
857 857 newnotifp->dln_fnp = funcp;
858 858 newnotifp->dln_notes = notes;
859 859 newnotifp->arg = arg;
860 860 newnotifp->dln_rm = B_FALSE;
861 861
862 862 /* Insert notification node at head */
863 863 newnotifp->dln_next = dip->dli_notifylistp;
864 864 dip->dli_notifylistp = newnotifp;
865 865
866 866 *id = (dlpi_notifyid_t)newnotifp;
867 867 return (DLPI_SUCCESS);
868 868 }
869 869
870 870 int
871 871 dlpi_disabnotify(dlpi_handle_t dh, dlpi_notifyid_t id, void **argp)
872 872 {
873 873 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
874 874 dlpi_notifyent_t *remid = (dlpi_notifyent_t *)id;
875 875
876 876 if (dip == NULL)
877 877 return (DLPI_EINHANDLE);
878 878
879 879 /* Walk the notifyentry list to find matching id. */
880 880 if (!(i_dlpi_notifyidexists(dip, remid)))
881 881 return (DLPI_ENOTEIDINVAL);
882 882
883 883 if (argp != NULL)
884 884 *argp = remid->arg;
885 885
886 886 remid->dln_rm = B_TRUE;
887 887 /* Delete node if callbacks are not being processed. */
888 888 if (!dip->dli_note_processing)
889 889 i_dlpi_deletenotifyid(dip);
890 890
891 891 return (DLPI_SUCCESS);
892 892 }
893 893
894 894 int
895 895 dlpi_fd(dlpi_handle_t dh)
896 896 {
897 897 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
898 898
899 899 return (dip != NULL ? dip->dli_fd : -1);
900 900 }
901 901
902 902 int
903 903 dlpi_set_timeout(dlpi_handle_t dh, int sec)
904 904 {
905 905 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
906 906
907 907 if (dip == NULL)
908 908 return (DLPI_EINHANDLE);
909 909
910 910 dip->dli_timeout = sec;
911 911 return (DLPI_SUCCESS);
912 912 }
913 913
914 914 const char *
915 915 dlpi_linkname(dlpi_handle_t dh)
916 916 {
917 917 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
918 918
919 919 return (dip != NULL ? dip->dli_linkname : NULL);
920 920 }
921 921
922 922 /*
923 923 * Returns DLPI style stored in the handle.
924 924 * Note: This function is used for test purposes only. Do not remove without
925 925 * fixing the DLPI testsuite.
926 926 */
927 927 uint_t
928 928 dlpi_style(dlpi_handle_t dh)
929 929 {
930 930 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
931 931
932 932 return (dip->dli_style);
933 933 }
934 934
935 935 uint_t
936 936 dlpi_arptype(uint_t dlpitype)
937 937 {
938 938 switch (dlpitype) {
939 939
940 940 case DL_ETHER:
941 941 return (ARPHRD_ETHER);
942 942
943 943 case DL_FRAME:
944 944 return (ARPHRD_FRAME);
945 945
946 946 case DL_ATM:
947 947 return (ARPHRD_ATM);
948 948
949 949 case DL_IPATM:
950 950 return (ARPHRD_IPATM);
951 951
952 952 case DL_HDLC:
953 953 return (ARPHRD_HDLC);
954 954
955 955 case DL_FC:
956 956 return (ARPHRD_FC);
957 957
958 958 case DL_CSMACD: /* ieee 802 networks */
959 959 case DL_TPB:
960 960 case DL_TPR:
961 961 case DL_METRO:
962 962 case DL_FDDI:
963 963 return (ARPHRD_IEEE802);
964 964
965 965 case DL_IB:
966 966 return (ARPHRD_IB);
967 967
968 968 case DL_IPV4:
969 969 case DL_IPV6:
970 970 return (ARPHRD_TUNNEL);
971 971 }
972 972
973 973 return (0);
974 974 }
975 975
976 976 uint_t
977 977 dlpi_iftype(uint_t dlpitype)
978 978 {
979 979 switch (dlpitype) {
980 980
981 981 case DL_ETHER:
982 982 return (IFT_ETHER);
983 983
984 984 case DL_ATM:
985 985 return (IFT_ATM);
986 986
987 987 case DL_CSMACD:
988 988 return (IFT_ISO88023);
989 989
990 990 case DL_TPB:
991 991 return (IFT_ISO88024);
992 992
993 993 case DL_TPR:
994 994 return (IFT_ISO88025);
995 995
996 996 case DL_FDDI:
997 997 return (IFT_FDDI);
998 998
999 999 case DL_IB:
1000 1000 return (IFT_IB);
1001 1001
1002 1002 case DL_OTHER:
1003 1003 return (IFT_OTHER);
1004 1004 }
1005 1005
1006 1006 return (0);
1007 1007 }
1008 1008
1009 1009 /*
1010 1010 * This function attempts to open a device under the following namespaces:
1011 1011 * /dev/ipnet - if DLPI_DEVIPNET is specified
1012 1012 * /dev/net - if a data-link with the specified name exists
1013 1013 * /dev - if DLPI_DEVONLY is specified, or if there is no
1014 1014 * data-link with the specified name (could be /dev/ip)
1015 1015 *
1016 1016 * In particular, if DLPI_DEVIPNET is not specified, this function is used to
1017 1017 * open a data-link node, or "/dev/ip" node. It is usually be called firstly
1018 1018 * with style1 being B_TRUE, and if that fails and the return value is not
1019 1019 * DLPI_ENOTSTYLE2, the function will again be called with style1 being
1020 1020 * B_FALSE (style-1 open attempt first, then style-2 open attempt).
1021 1021 *
1022 1022 * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node
1023 1023 * directly.
1024 1024 *
1025 1025 * Otherwise, for style-1 attempt, the function will try to open the style-1
1026 1026 * /dev/net node, and perhaps fallback to open the style-1 /dev node if the
1027 1027 * give name is not a data-link name (e.g., it is /dev/ip). Note that the
1028 1028 * fallback and the subsequent style-2 attempt will not happen if:
1029 1029 * 1. style-1 opening of the /dev/net node succeeds;
1030 1030 * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT,
1031 1031 * which means that the specific /dev/net node exist, but the attempt fails
1032 1032 * for some other reason;
1033 1033 * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is
1034 1034 * a known device name or its VLAN PPA hack name. (for example, assuming
1035 1035 * device bge0 is renamed to net0, opening /dev/net/bge1000 would return
1036 1036 * ENOENT, but we should not fallback to open /dev/bge1000 in this case,
1037 1037 * as VLAN 1 over the bge0 device should be named as net1000.
1038 1038 *
1039 1039 * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed
1040 1040 * the second style-2 open attempt.
1041 1041 */
1042 1042 static int
1043 1043 i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
1044 1044 {
1045 1045 char path[MAXPATHLEN];
1046 1046 int oflags;
1047 1047
1048 1048 errno = ENOENT;
1049 1049 oflags = O_RDWR;
1050 1050 if (flags & DLPI_EXCL)
1051 1051 oflags |= O_EXCL;
1052 1052
1053 1053 if (flags & DLPI_DEVIPNET) {
1054 1054 (void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider);
1055 1055 if ((*fd = open(path, oflags)) != -1)
1056 1056 return (DLPI_SUCCESS);
1057 1057 else
1058 1058 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1059 1059 } else if (style1 && !(flags & DLPI_DEVONLY)) {
1060 1060 char driver[DLPI_LINKNAME_MAX];
1061 1061 char device[DLPI_LINKNAME_MAX];
1062 1062 datalink_id_t linkid;
1063 1063 uint_t ppa;
1064 1064 dladm_handle_t handle;
1065 1065
1066 1066 /*
1067 1067 * This is not a valid style-1 name. It could be "ip" module
1068 1068 * for example. Fallback to open the /dev node.
1069 1069 */
1070 1070 if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS)
1071 1071 goto fallback;
1072 1072
1073 1073 (void) snprintf(path, sizeof (path), "/dev/net/%s", provider);
1074 1074 if ((*fd = open(path, oflags)) != -1)
1075 1075 return (DLPI_SUCCESS);
1076 1076
1077 1077 /*
1078 1078 * We don't fallback to open the /dev node when it returns
1079 1079 * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2
1080 1080 * is returned to indicate not to continue the style-2 open.
1081 1081 */
1082 1082 if (errno != ENOENT)
1083 1083 return (DLPI_ENOTSTYLE2);
1084 1084
1085 1085 /*
1086 1086 * We didn't find the /dev/net node. Then we check whether
1087 1087 * the given name is a device name or its VLAN PPA hack name
1088 1088 * of a known link. If the answer is yes, and this link
1089 1089 * supports vanity naming, then the link (or the VLAN) should
1090 1090 * also have its /dev/net node but perhaps with another vanity
1091 1091 * name (for example, when bge0 is renamed to net0). In this
1092 1092 * case, although attempt to open the /dev/net/<devname> fails,
1093 1093 * we should not fallback to open the /dev/<devname> node.
1094 1094 */
1095 1095 (void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver,
1096 1096 ppa >= 1000 ? ppa % 1000 : ppa);
1097 1097
1098 1098 /* open libdladm handle rather than taking it as input */
1099 1099 if (dladm_open(&handle) != DLADM_STATUS_OK)
1100 1100 goto fallback;
1101 1101
1102 1102 if (dladm_dev2linkid(handle, device, &linkid) ==
1103 1103 DLADM_STATUS_OK) {
1104 1104 dladm_phys_attr_t dpa;
1105 1105
1106 1106 if ((dladm_phys_info(handle, linkid, &dpa,
1107 1107 DLADM_OPT_ACTIVE)) == DLADM_STATUS_OK &&
1108 1108 !dpa.dp_novanity) {
1109 1109 dladm_close(handle);
1110 1110 return (DLPI_ENOTSTYLE2);
1111 1111 }
1112 1112 }
1113 1113 dladm_close(handle);
1114 1114 }
1115 1115
1116 1116 fallback:
1117 1117 (void) snprintf(path, sizeof (path), "/dev/%s", provider);
1118 1118 if ((*fd = open(path, oflags)) != -1)
1119 1119 return (DLPI_SUCCESS);
1120 1120
1121 1121 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1122 1122 }
1123 1123
1124 1124 /*
1125 1125 * Open a style 1 link. PPA is implicitly attached.
1126 1126 */
1127 1127 static int
1128 1128 i_dlpi_style1_open(dlpi_impl_t *dip)
1129 1129 {
1130 1130 int retval, save_errno;
1131 1131 int fd;
1132 1132
1133 1133 retval = i_dlpi_open(dip->dli_linkname, &fd, dip->dli_oflags, B_TRUE);
1134 1134 if (retval != DLPI_SUCCESS)
1135 1135 return (retval);
1136 1136 dip->dli_fd = fd;
1137 1137
1138 1138 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) {
1139 1139 save_errno = errno;
1140 1140 (void) close(dip->dli_fd);
1141 1141 errno = save_errno;
1142 1142 }
1143 1143
1144 1144 return (retval);
1145 1145 }
1146 1146
1147 1147 /*
1148 1148 * Open a style 2 link. PPA must be explicitly attached.
1149 1149 */
1150 1150 static int
1151 1151 i_dlpi_style2_open(dlpi_impl_t *dip)
1152 1152 {
1153 1153 int fd;
1154 1154 int retval, save_errno;
1155 1155
1156 1156 retval = i_dlpi_open(dip->dli_provider, &fd, dip->dli_oflags, B_FALSE);
1157 1157 if (retval != DLPI_SUCCESS)
1158 1158 return (retval);
1159 1159 dip->dli_fd = fd;
1160 1160
1161 1161 /*
1162 1162 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a
1163 1163 * DLPI link so attach and ignore rest.
1164 1164 */
1165 1165 if (dip->dli_oflags & DLPI_SERIAL)
1166 1166 goto attach;
1167 1167
1168 1168 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS)
1169 1169 goto failure;
1170 1170
1171 1171 /*
1172 1172 * Succeeded opening the link and verified it is style2. Now attach to
1173 1173 * PPA only if DLPI_NOATTACH is not set.
1174 1174 */
1175 1175 if (dip->dli_oflags & DLPI_NOATTACH)
1176 1176 return (DLPI_SUCCESS);
1177 1177
1178 1178 attach:
1179 1179 if ((retval = i_dlpi_attach(dip)) == DLPI_SUCCESS)
1180 1180 return (DLPI_SUCCESS);
1181 1181
1182 1182 failure:
1183 1183 save_errno = errno;
1184 1184 (void) close(dip->dli_fd);
1185 1185 errno = save_errno;
1186 1186 return (retval);
1187 1187 }
1188 1188
1189 1189 /*
1190 1190 * Verify with DLPI that the link is the expected DLPI 'style' device,
1191 1191 * dlpi_info sets the DLPI style in the DLPI handle.
1192 1192 */
1193 1193 static int
1194 1194 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style)
1195 1195 {
1196 1196 int retval;
1197 1197 dlpi_info_t dlinfo;
1198 1198
1199 1199 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
1200 1200 if (retval == DLPI_SUCCESS && dip->dli_style != style)
1201 1201 retval = DLPI_EBADLINK;
1202 1202
1203 1203 return (retval);
1204 1204 }
1205 1205
1206 1206 /*
1207 1207 * For DLPI style 2 providers, an explicit attach of PPA is required.
1208 1208 */
1209 1209 static int
1210 1210 i_dlpi_attach(dlpi_impl_t *dip)
1211 1211 {
1212 1212 dlpi_msg_t req, ack;
1213 1213 dl_attach_req_t *attachreqp;
1214 1214
1215 1215 /*
1216 1216 * Special case: DLPI_SERIAL flag (synchronous serial lines)
1217 1217 * is not a DLPI link so ignore DLPI style.
1218 1218 */
1219 1219 if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL))
1220 1220 return (DLPI_ENOTSTYLE2);
1221 1221
1222 1222 DLPI_MSG_CREATE(req, DL_ATTACH_REQ);
1223 1223 DLPI_MSG_CREATE(ack, DL_OK_ACK);
1224 1224
1225 1225 attachreqp = &(req.dlm_msg->attach_req);
1226 1226 attachreqp->dl_ppa = dip->dli_ppa;
1227 1227
1228 1228 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
1229 1229 }
1230 1230
1231 1231 /*
1232 1232 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care
1233 1233 * if this request fails, as this indicates the underlying DLPI device does
1234 1234 * not support link aggregation (pre-GLDV3 device drivers), and thus will
1235 1235 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing
1236 1236 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p).
1237 1237 */
1238 1238 static void
1239 1239 i_dlpi_passive(dlpi_impl_t *dip)
1240 1240 {
1241 1241 dlpi_msg_t req, ack;
1242 1242
1243 1243 DLPI_MSG_CREATE(req, DL_PASSIVE_REQ);
1244 1244 DLPI_MSG_CREATE(ack, DL_OK_ACK);
1245 1245
1246 1246 (void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0);
1247 1247 }
1248 1248
1249 1249 /*
1250 1250 * Send a dlpi control message and/or data message on a stream. The inputs
1251 1251 * for this function are:
1252 1252 * dlpi_impl_t *dip: internal dlpi handle to open stream
1253 1253 * const dlpi_msg_t *dlreqp: request message structure
1254 1254 * void *databuf: data buffer
1255 1255 * size_t datalen: data buffer len
1256 1256 * int flags: flags to set for putmsg()
1257 1257 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure.
1258 1258 */
1259 1259 static int
1260 1260 i_dlpi_strputmsg(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1261 1261 const void *databuf, size_t datalen, int flags)
1262 1262 {
1263 1263 int retval;
1264 1264 int fd = dip->dli_fd;
1265 1265 struct strbuf ctl;
1266 1266 struct strbuf data;
1267 1267
1268 1268 if (dlreqp != NULL) {
1269 1269 ctl.buf = (void *)dlreqp->dlm_msg;
1270 1270 ctl.len = dlreqp->dlm_msgsz;
1271 1271 }
1272 1272
1273 1273 data.buf = (void *)databuf;
1274 1274 data.len = datalen;
1275 1275
1276 1276 retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl),
1277 1277 (databuf == NULL ? NULL : &data), flags);
1278 1278
1279 1279 return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR);
1280 1280 }
1281 1281
1282 1282 /*
1283 1283 * Get a DLPI control message and/or data message from a stream. The inputs
1284 1284 * for this function are:
1285 1285 * dlpi_impl_t *dip: internal dlpi handle
1286 1286 * int msec: timeout to wait for message
1287 1287 * dlpi_msg_t *dlreplyp: reply message structure, the message size
1288 1288 * member on return stores actual size received
1289 1289 * t_uscalar_t dlreqprim: requested primitive
1290 1290 * t_uscalar_t dlreplyprim:acknowledged primitive in response to request
1291 1291 * size_t dlreplyminsz: minimum size of acknowledged primitive size
1292 1292 * void *databuf: data buffer
1293 1293 * size_t *datalenp: data buffer len
1294 1294 * size_t *totdatalenp: total data received. Greater than 'datalenp' if
1295 1295 * actual data received is larger than 'databuf'
1296 1296 * Function returns DLPI_SUCCESS if requested message is retrieved
1297 1297 * otherwise returns error code or timeouts. If a notification arrives on
1298 1298 * the stream the callback is notified. However, error returned during the
1299 1299 * handling of notification is ignored as it would be confusing to actual caller
1300 1300 * of this function.
1301 1301 */
1302 1302 static int
1303 1303 i_dlpi_strgetmsg(dlpi_impl_t *dip, int msec, dlpi_msg_t *dlreplyp,
1304 1304 t_uscalar_t dlreqprim, t_uscalar_t dlreplyprim, size_t dlreplyminsz,
1305 1305 void *databuf, size_t *datalenp, size_t *totdatalenp)
1306 1306 {
1307 1307 int retval;
1308 1308 int flags;
1309 1309 int fd = dip->dli_fd;
1310 1310 struct strbuf ctl, data;
1311 1311 struct pollfd pfd;
1312 1312 hrtime_t start, current;
1313 1313 long bufc[DLPI_CHUNKSIZE / sizeof (long)];
1314 1314 long bufd[DLPI_CHUNKSIZE / sizeof (long)];
1315 1315 union DL_primitives *dlprim;
1316 1316 dl_notify_ind_t *dlnotif;
1317 1317 boolean_t infinite = (msec < 0); /* infinite timeout */
1318 1318
1319 1319 /*
1320 1320 * dlreplyp and databuf can be NULL at the same time, to force a check
1321 1321 * for pending events on the DLPI link instance; dlpi_enabnotify(3DLPI).
1322 1322 * this will be true more so for DLPI_RAW mode with notifications
1323 1323 * enabled.
1324 1324 */
1325 1325 if ((databuf == NULL && datalenp != NULL) ||
1326 1326 (databuf != NULL && datalenp == NULL))
1327 1327 return (DLPI_EINVAL);
1328 1328
1329 1329 pfd.fd = fd;
1330 1330 pfd.events = POLLIN | POLLPRI;
1331 1331
↓ open down ↓ |
1331 lines elided |
↑ open up ↑ |
1332 1332 ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg;
1333 1333 ctl.len = 0;
1334 1334 ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz;
1335 1335
1336 1336 data.buf = (databuf == NULL) ? bufd : databuf;
1337 1337 data.len = 0;
1338 1338 data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp;
1339 1339
1340 1340 for (;;) {
1341 1341 if (!infinite)
1342 - start = gethrtime() / (NANOSEC / MILLISEC);
1342 + start = NSEC2MSEC(gethrtime());
1343 1343
1344 1344 switch (poll(&pfd, 1, msec)) {
1345 1345 default:
1346 1346 if (pfd.revents & POLLHUP)
1347 1347 return (DL_SYSERR);
1348 1348 break;
1349 1349 case 0:
1350 1350 return (DLPI_ETIMEDOUT);
1351 1351 case -1:
1352 1352 return (DL_SYSERR);
1353 1353 }
1354 1354
1355 1355 flags = 0;
1356 1356 if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0)
1357 1357 return (DL_SYSERR);
1358 1358
1359 1359 if (totdatalenp != NULL)
1360 1360 *totdatalenp = data.len;
1361 1361
1362 1362 /*
1363 1363 * The supplied DLPI_CHUNKSIZE sized buffers are large enough
1364 1364 * to retrieve all valid DLPI responses in one iteration.
1365 1365 * If MORECTL or MOREDATA is set, we are not interested in the
1366 1366 * remainder of the message. Temporary buffers are used to
1367 1367 * drain the remainder of this message.
1368 1368 * The special case we have to account for is if
1369 1369 * a higher priority messages is enqueued whilst handling
1370 1370 * this condition. We use a change in the flags parameter
1371 1371 * returned by getmsg() to indicate the message has changed.
1372 1372 */
1373 1373 while (retval & (MORECTL | MOREDATA)) {
1374 1374 struct strbuf cscratch, dscratch;
1375 1375 int oflags = flags;
1376 1376
1377 1377 cscratch.buf = (char *)bufc;
1378 1378 dscratch.buf = (char *)bufd;
1379 1379 cscratch.len = dscratch.len = 0;
1380 1380 cscratch.maxlen = dscratch.maxlen =
1381 1381 sizeof (bufc);
1382 1382
1383 1383 if ((retval = getmsg(fd, &cscratch, &dscratch,
1384 1384 &flags)) < 0)
1385 1385 return (DL_SYSERR);
1386 1386
1387 1387 if (totdatalenp != NULL)
1388 1388 *totdatalenp += dscratch.len;
1389 1389 /*
1390 1390 * In the special case of higher priority
1391 1391 * message received, the low priority message
1392 1392 * received earlier is discarded, if no data
1393 1393 * or control message is left.
1394 1394 */
1395 1395 if ((flags != oflags) &&
1396 1396 !(retval & (MORECTL | MOREDATA)) &&
1397 1397 (cscratch.len != 0)) {
1398 1398 ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE);
1399 1399 if (dlreplyp != NULL)
1400 1400 (void) memcpy(dlreplyp->dlm_msg, bufc,
1401 1401 ctl.len);
1402 1402 break;
1403 1403 }
1404 1404 }
1405 1405
1406 1406 /*
1407 1407 * Check if DL_NOTIFY_IND message received. If there is one,
1408 1408 * notify the callback function(s) and continue processing the
1409 1409 * requested message.
1410 1410 */
1411 1411 if (dip->dli_notifylistp != NULL &&
1412 1412 ctl.len >= (int)(sizeof (t_uscalar_t)) &&
1413 1413 *(t_uscalar_t *)(void *)ctl.buf == DL_NOTIFY_IND) {
1414 1414 /* process properly-formed DL_NOTIFY_IND messages */
1415 1415 if (ctl.len >= DL_NOTIFY_IND_SIZE) {
1416 1416 dlnotif = (dl_notify_ind_t *)(void *)ctl.buf;
1417 1417 (void) i_dlpi_notifyind_process(dip, dlnotif);
1418 1418 }
1419 1419 goto update_timer;
1420 1420 }
1421 1421
1422 1422 /*
1423 1423 * If we were expecting a data message, and we got one, set
1424 1424 * *datalenp. If we aren't waiting on a control message, then
1425 1425 * we're done.
1426 1426 */
1427 1427 if (databuf != NULL && data.len >= 0) {
1428 1428 *datalenp = data.len;
1429 1429 if (dlreplyp == NULL)
1430 1430 break;
1431 1431 }
1432 1432
1433 1433 /*
1434 1434 * If we were expecting a control message, and the message
1435 1435 * we received is at least big enough to be a DLPI message,
1436 1436 * then verify it's a reply to something we sent. If it
1437 1437 * is a reply to something we sent, also verify its size.
1438 1438 */
1439 1439 if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) {
1440 1440 dlprim = dlreplyp->dlm_msg;
1441 1441 if (dlprim->dl_primitive == dlreplyprim) {
1442 1442 if (ctl.len < dlreplyminsz)
1443 1443 return (DLPI_EBADMSG);
1444 1444 dlreplyp->dlm_msgsz = ctl.len;
1445 1445 break;
1446 1446 } else if (dlprim->dl_primitive == DL_ERROR_ACK) {
1447 1447 if (ctl.len < DL_ERROR_ACK_SIZE)
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
1448 1448 return (DLPI_EBADMSG);
1449 1449
1450 1450 /* Is it ours? */
1451 1451 if (dlprim->error_ack.dl_error_primitive ==
1452 1452 dlreqprim)
1453 1453 break;
1454 1454 }
1455 1455 }
1456 1456 update_timer:
1457 1457 if (!infinite) {
1458 - current = gethrtime() / (NANOSEC / MILLISEC);
1458 + current = NSEC2MSEC(gethrtime());
1459 1459 msec -= (current - start);
1460 1460
1461 1461 if (msec <= 0)
1462 1462 return (DLPI_ETIMEDOUT);
1463 1463 }
1464 1464 }
1465 1465
1466 1466 return (DLPI_SUCCESS);
1467 1467 }
1468 1468
1469 1469 /*
1470 1470 * Common routine invoked by all DLPI control routines. The inputs for this
1471 1471 * function are:
1472 1472 * dlpi_impl_t *dip: internal dlpi handle
1473 1473 * const dlpi_msg_t *dlreqp: request message structure
1474 1474 * dlpi_msg_t *dlreplyp: reply message structure
1475 1475 * size_t dlreplyminsz: minimum size of reply primitive
1476 1476 * int flags: flags to be set to send a message
1477 1477 * This routine succeeds if the message is an expected request/acknowledged
1478 1478 * message. However, if DLPI notification has been enabled via
1479 1479 * dlpi_enabnotify(), DL_NOTIFY_IND messages are handled before handling
1480 1480 * expected messages. Otherwise, any other unexpected asynchronous messages will
1481 1481 * be discarded.
1482 1482 */
1483 1483 static int
1484 1484 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1485 1485 dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags)
1486 1486 {
1487 1487 int retval;
1488 1488 t_uscalar_t dlreqprim = dlreqp->dlm_msg->dl_primitive;
1489 1489 t_uscalar_t dlreplyprim = dlreplyp->dlm_msg->dl_primitive;
1490 1490
1491 1491 /* Put the requested primitive on the stream. */
1492 1492 retval = i_dlpi_strputmsg(dip, dlreqp, NULL, 0, flags);
1493 1493 if (retval != DLPI_SUCCESS)
1494 1494 return (retval);
1495 1495
1496 1496 /* Retrieve acknowledged message for requested primitive. */
1497 1497 retval = i_dlpi_strgetmsg(dip, (dip->dli_timeout * MILLISEC),
1498 1498 dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL);
1499 1499 if (retval != DLPI_SUCCESS)
1500 1500 return (retval);
1501 1501
1502 1502 /*
1503 1503 * If primitive is DL_ERROR_ACK, set errno.
1504 1504 */
1505 1505 if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) {
1506 1506 errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno;
1507 1507 retval = dlreplyp->dlm_msg->error_ack.dl_errno;
1508 1508 }
1509 1509
1510 1510 return (retval);
1511 1511 }
1512 1512
1513 1513 /*
1514 1514 * DLPI error codes.
1515 1515 */
1516 1516 static const char *dlpi_errlist[] = {
1517 1517 "bad LSAP selector", /* DL_BADSAP 0x00 */
1518 1518 "DLSAP address in improper format or invalid", /* DL_BADADDR 0x01 */
1519 1519 "improper permissions for request", /* DL_ACCESS 0x02 */
1520 1520 "primitive issued in improper state", /* DL_OUTSTATE 0x03 */
1521 1521 NULL, /* DL_SYSERR 0x04 */
1522 1522 "sequence number not from outstanding DL_CONN_IND",
1523 1523 /* DL_BADCORR 0x05 */
1524 1524 "user data exceeded provider limit", /* DL_BADDATA 0x06 */
1525 1525 "requested service not supplied by provider",
1526 1526 /* DL_UNSUPPORTED 0x07 */
1527 1527 "specified PPA was invalid", /* DL_BADPPA 0x08 */
1528 1528 "primitive received not known by provider", /* DL_BADPRIM 0x09 */
1529 1529 "QoS parameters contained invalid values",
1530 1530 /* DL_BADQOSPARAM 0x0a */
1531 1531 "QoS structure type is unknown/unsupported", /* DL_BADQOSTYPE 0x0b */
1532 1532 "token used not an active stream", /* DL_BADTOKEN 0x0c */
1533 1533 "attempted second bind with dl_max_conind", /* DL_BOUND 0x0d */
1534 1534 "physical link initialization failed", /* DL_INITFAILED 0x0e */
1535 1535 "provider couldn't allocate alternate address", /* DL_NOADDR 0x0f */
1536 1536 "physical link not initialized", /* DL_NOTINIT 0x10 */
1537 1537 "previous data unit could not be delivered",
1538 1538 /* DL_UNDELIVERABLE 0x11 */
1539 1539 "primitive is known but unsupported",
1540 1540 /* DL_NOTSUPPORTED 0x12 */
1541 1541 "limit exceeded", /* DL_TOOMANY 0x13 */
1542 1542 "promiscuous mode not enabled", /* DL_NOTENAB 0x14 */
1543 1543 "other streams for PPA in post-attached", /* DL_BUSY 0x15 */
1544 1544 "automatic handling XID&TEST unsupported", /* DL_NOAUTO 0x16 */
1545 1545 "automatic handling of XID unsupported", /* DL_NOXIDAUTO 0x17 */
1546 1546 "automatic handling of TEST unsupported", /* DL_NOTESTAUTO 0x18 */
1547 1547 "automatic handling of XID response", /* DL_XIDAUTO 0x19 */
1548 1548 "automatic handling of TEST response", /* DL_TESTAUTO 0x1a */
1549 1549 "pending outstanding connect indications" /* DL_PENDING 0x1b */
1550 1550 };
1551 1551
1552 1552 /*
1553 1553 * libdlpi error codes.
1554 1554 */
1555 1555 static const char *libdlpi_errlist[] = {
1556 1556 "DLPI operation succeeded", /* DLPI_SUCCESS */
1557 1557 "invalid argument", /* DLPI_EINVAL */
1558 1558 "invalid DLPI linkname", /* DLPI_ELINKNAMEINVAL */
1559 1559 "DLPI link does not exist", /* DLPI_ENOLINK */
1560 1560 "bad DLPI link", /* DLPI_EBADLINK */
1561 1561 "invalid DLPI handle", /* DLPI_EINHANDLE */
1562 1562 "DLPI operation timed out", /* DLPI_ETIMEDOUT */
1563 1563 "unsupported DLPI version", /* DLPI_EVERNOTSUP */
1564 1564 "unsupported DLPI connection mode", /* DLPI_EMODENOTSUP */
1565 1565 "unavailable DLPI SAP", /* DLPI_EUNAVAILSAP */
1566 1566 "DLPI operation failed", /* DLPI_FAILURE */
1567 1567 "DLPI style-2 node reports style-1", /* DLPI_ENOTSTYLE2 */
1568 1568 "bad DLPI message", /* DLPI_EBADMSG */
1569 1569 "DLPI raw mode not supported", /* DLPI_ERAWNOTSUP */
1570 1570 "DLPI notification not supported by link",
1571 1571 /* DLPI_ENOTENOTSUP */
1572 1572 "invalid DLPI notification type", /* DLPI_ENOTEINVAL */
1573 1573 "invalid DLPI notification id", /* DLPI_ENOTEIDINVAL */
1574 1574 "DLPI_IPNETINFO not supported" /* DLPI_EIPNETINFONOTSUP */
1575 1575 };
1576 1576
1577 1577 const char *
1578 1578 dlpi_strerror(int err)
1579 1579 {
1580 1580 if (err == DL_SYSERR)
1581 1581 return (strerror(errno));
1582 1582 else if (err >= 0 && err < NELEMS(dlpi_errlist))
1583 1583 return (dgettext(TEXT_DOMAIN, dlpi_errlist[err]));
1584 1584 else if (err >= DLPI_SUCCESS && err < DLPI_ERRMAX)
1585 1585 return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err -
1586 1586 DLPI_SUCCESS]));
1587 1587 else
1588 1588 return (dgettext(TEXT_DOMAIN, "Unknown DLPI error"));
1589 1589 }
1590 1590
1591 1591 /*
1592 1592 * Each table entry comprises a DLPI/Private mactype and the description.
1593 1593 */
1594 1594 static const dlpi_mactype_t dlpi_mactypes[] = {
1595 1595 { DL_CSMACD, "CSMA/CD" },
1596 1596 { DL_TPB, "Token Bus" },
1597 1597 { DL_TPR, "Token Ring" },
1598 1598 { DL_METRO, "Metro Net" },
1599 1599 { DL_ETHER, "Ethernet" },
1600 1600 { DL_HDLC, "HDLC" },
1601 1601 { DL_CHAR, "Sync Character" },
1602 1602 { DL_CTCA, "CTCA" },
1603 1603 { DL_FDDI, "FDDI" },
1604 1604 { DL_FRAME, "Frame Relay (LAPF)" },
1605 1605 { DL_MPFRAME, "MP Frame Relay" },
1606 1606 { DL_ASYNC, "Async Character" },
1607 1607 { DL_IPX25, "X.25 (Classic IP)" },
1608 1608 { DL_LOOP, "Software Loopback" },
1609 1609 { DL_FC, "Fiber Channel" },
1610 1610 { DL_ATM, "ATM" },
1611 1611 { DL_IPATM, "ATM (Classic IP)" },
1612 1612 { DL_X25, "X.25 (LAPB)" },
1613 1613 { DL_ISDN, "ISDN" },
1614 1614 { DL_HIPPI, "HIPPI" },
1615 1615 { DL_100VG, "100BaseVG Ethernet" },
1616 1616 { DL_100VGTPR, "100BaseVG Token Ring" },
1617 1617 { DL_ETH_CSMA, "Ethernet/IEEE 802.3" },
1618 1618 { DL_100BT, "100BaseT" },
1619 1619 { DL_IB, "Infiniband" },
1620 1620 { DL_IPV4, "IPv4 Tunnel" },
1621 1621 { DL_IPV6, "IPv6 Tunnel" },
1622 1622 { DL_WIFI, "IEEE 802.11" },
1623 1623 { DL_IPNET, "IPNET" }
1624 1624 };
1625 1625
1626 1626 const char *
1627 1627 dlpi_mactype(uint_t mactype)
1628 1628 {
1629 1629 int i;
1630 1630
1631 1631 for (i = 0; i < NELEMS(dlpi_mactypes); i++) {
1632 1632 if (dlpi_mactypes[i].dm_mactype == mactype)
1633 1633 return (dlpi_mactypes[i].dm_desc);
1634 1634 }
1635 1635
1636 1636 return ("Unknown MAC Type");
1637 1637 }
1638 1638
1639 1639 /*
1640 1640 * Each table entry comprises a DLPI primitive and the maximum buffer
1641 1641 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details).
1642 1642 */
1643 1643 static const dlpi_primsz_t dlpi_primsizes[] = {
1644 1644 { DL_INFO_REQ, DL_INFO_REQ_SIZE },
1645 1645 { DL_INFO_ACK, DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) +
1646 1646 DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))},
1647 1647 { DL_ATTACH_REQ, DL_ATTACH_REQ_SIZE },
1648 1648 { DL_BIND_REQ, DL_BIND_REQ_SIZE },
1649 1649 { DL_BIND_ACK, DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX +
1650 1650 DLPI_SAPLEN_MAX },
1651 1651 { DL_UNBIND_REQ, DL_UNBIND_REQ_SIZE },
1652 1652 { DL_ENABMULTI_REQ, DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX },
1653 1653 { DL_DISABMULTI_REQ, DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX },
1654 1654 { DL_PROMISCON_REQ, DL_PROMISCON_REQ_SIZE },
1655 1655 { DL_PROMISCOFF_REQ, DL_PROMISCOFF_REQ_SIZE },
1656 1656 { DL_PASSIVE_REQ, DL_PASSIVE_REQ_SIZE },
1657 1657 { DL_UNITDATA_REQ, DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX +
1658 1658 DLPI_SAPLEN_MAX },
1659 1659 { DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX +
1660 1660 DLPI_SAPLEN_MAX)) },
1661 1661 { DL_PHYS_ADDR_REQ, DL_PHYS_ADDR_REQ_SIZE },
1662 1662 { DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX },
1663 1663 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX },
1664 1664 { DL_OK_ACK, MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE) },
1665 1665 { DL_NOTIFY_REQ, DL_NOTIFY_REQ_SIZE },
1666 1666 { DL_NOTIFY_ACK, MAX(DL_ERROR_ACK_SIZE, DL_NOTIFY_ACK_SIZE) },
1667 1667 { DL_NOTIFY_IND, DL_NOTIFY_IND_SIZE + DLPI_PHYSADDR_MAX +
1668 1668 DLPI_SAPLEN_MAX }
1669 1669 };
1670 1670
1671 1671 /*
1672 1672 * Refers to the dlpi_primsizes[] table to return corresponding maximum
1673 1673 * buffer size.
1674 1674 */
1675 1675 static size_t
1676 1676 i_dlpi_getprimsize(t_uscalar_t prim)
1677 1677 {
1678 1678 int i;
1679 1679
1680 1680 for (i = 0; i < NELEMS(dlpi_primsizes); i++) {
1681 1681 if (dlpi_primsizes[i].dp_prim == prim)
1682 1682 return (dlpi_primsizes[i].dp_primsz);
1683 1683 }
1684 1684
1685 1685 return (sizeof (t_uscalar_t));
1686 1686 }
1687 1687
1688 1688 /*
1689 1689 * sap values vary in length and are in host byte order, build sap value
1690 1690 * by writing saplen bytes, so that the sap value is left aligned.
1691 1691 */
1692 1692 static uint_t
1693 1693 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen)
1694 1694 {
1695 1695 int i;
1696 1696 uint_t sap = 0;
1697 1697
1698 1698 #ifdef _LITTLE_ENDIAN
1699 1699 for (i = saplen - 1; i >= 0; i--) {
1700 1700 #else
1701 1701 for (i = 0; i < saplen; i++) {
1702 1702 #endif
1703 1703 sap <<= 8;
1704 1704 sap |= sapp[i];
1705 1705 }
1706 1706
1707 1707 return (sap);
1708 1708 }
1709 1709
1710 1710 /*
1711 1711 * Copy sap value to a buffer in host byte order. saplen is the number of
1712 1712 * bytes to copy.
1713 1713 */
1714 1714 static void
1715 1715 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen)
1716 1716 {
1717 1717 uint8_t *sapp;
1718 1718
1719 1719 #ifdef _LITTLE_ENDIAN
1720 1720 sapp = (uint8_t *)&sap;
1721 1721 #else
1722 1722 sapp = (uint8_t *)&sap + (sizeof (sap) - saplen);
1723 1723 #endif
1724 1724
1725 1725 (void) memcpy(dstbuf, sapp, saplen);
1726 1726 }
1727 1727
1728 1728 /*
1729 1729 * Fill notification payload and callback each registered functions.
1730 1730 * Delete nodes if any was called while processing.
1731 1731 */
1732 1732 static int
1733 1733 i_dlpi_notifyind_process(dlpi_impl_t *dip, dl_notify_ind_t *dlnotifyindp)
1734 1734 {
1735 1735 dlpi_notifyinfo_t notifinfo;
1736 1736 t_uscalar_t dataoff, datalen;
1737 1737 caddr_t datap;
1738 1738 dlpi_notifyent_t *dnp;
1739 1739 uint_t note = dlnotifyindp->dl_notification;
1740 1740 uint_t deletenode = B_FALSE;
1741 1741
1742 1742 notifinfo.dni_note = note;
1743 1743
1744 1744 switch (note) {
1745 1745 case DL_NOTE_SPEED:
1746 1746 notifinfo.dni_speed = dlnotifyindp->dl_data;
1747 1747 break;
1748 1748 case DL_NOTE_SDU_SIZE:
1749 1749 notifinfo.dni_size = dlnotifyindp->dl_data;
1750 1750 break;
1751 1751 case DL_NOTE_PHYS_ADDR:
1752 1752 /*
1753 1753 * libdlpi currently only supports notifications for
1754 1754 * DL_CURR_PHYS_ADDR.
1755 1755 */
1756 1756 if (dlnotifyindp->dl_data != DL_CURR_PHYS_ADDR)
1757 1757 return (DLPI_ENOTENOTSUP);
1758 1758
1759 1759 dataoff = dlnotifyindp->dl_addr_offset;
1760 1760 datalen = dlnotifyindp->dl_addr_length;
1761 1761
1762 1762 if (dataoff == 0 || datalen == 0)
1763 1763 return (DLPI_EBADMSG);
1764 1764
1765 1765 datap = (caddr_t)dlnotifyindp + dataoff;
1766 1766 if (dataoff < DL_NOTIFY_IND_SIZE)
1767 1767 return (DLPI_EBADMSG);
1768 1768
1769 1769 notifinfo.dni_physaddrlen = datalen - dip->dli_saplen;
1770 1770
1771 1771 if (notifinfo.dni_physaddrlen > DLPI_PHYSADDR_MAX)
1772 1772 return (DL_BADADDR);
1773 1773
1774 1774 (void) memcpy(notifinfo.dni_physaddr, datap,
1775 1775 notifinfo.dni_physaddrlen);
1776 1776 break;
1777 1777 }
1778 1778
1779 1779 dip->dli_note_processing = B_TRUE;
1780 1780
1781 1781 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
1782 1782 if (note & dnp->dln_notes)
1783 1783 dnp->dln_fnp((dlpi_handle_t)dip, ¬ifinfo, dnp->arg);
1784 1784 if (dnp->dln_rm)
1785 1785 deletenode = B_TRUE;
1786 1786 }
1787 1787
1788 1788 dip->dli_note_processing = B_FALSE;
1789 1789
1790 1790 /* Walk the notifyentry list to unregister marked entries. */
1791 1791 if (deletenode)
1792 1792 i_dlpi_deletenotifyid(dip);
1793 1793
1794 1794 return (DLPI_SUCCESS);
1795 1795 }
1796 1796 /*
1797 1797 * Find registered notification.
1798 1798 */
1799 1799 static boolean_t
1800 1800 i_dlpi_notifyidexists(dlpi_impl_t *dip, dlpi_notifyent_t *id)
1801 1801 {
1802 1802 dlpi_notifyent_t *dnp;
1803 1803
1804 1804 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
1805 1805 if (id == dnp)
1806 1806 return (B_TRUE);
1807 1807 }
1808 1808
1809 1809 return (B_FALSE);
1810 1810 }
1811 1811
1812 1812 /*
1813 1813 * Walk the list of notifications and deleted nodes marked to be deleted.
1814 1814 */
1815 1815 static void
1816 1816 i_dlpi_deletenotifyid(dlpi_impl_t *dip)
1817 1817 {
1818 1818 dlpi_notifyent_t *prev, *dnp;
1819 1819
1820 1820 prev = NULL;
1821 1821 dnp = dip->dli_notifylistp;
1822 1822 while (dnp != NULL) {
1823 1823 if (!dnp->dln_rm) {
1824 1824 prev = dnp;
1825 1825 dnp = dnp->dln_next;
1826 1826 } else if (prev == NULL) {
1827 1827 dip->dli_notifylistp = dnp->dln_next;
1828 1828 free(dnp);
1829 1829 dnp = dip->dli_notifylistp;
1830 1830 } else {
1831 1831 prev->dln_next = dnp->dln_next;
1832 1832 free(dnp);
1833 1833 dnp = prev->dln_next;
1834 1834 }
1835 1835 }
1836 1836 }
↓ open down ↓ |
368 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX