Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/llc1.c
+++ new/usr/src/uts/common/io/llc1.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 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26
27 27 /*
28 28 * llc1 - an LLC Class 1 MUX compatible with SunConnect LLC2 uses DLPI
29 29 * interface. Its primary use is to support RPL for network boot but can be
30 30 * used by other protocols.
31 31 */
32 32
33 33 #include <sys/types.h>
34 34 #include <sys/errno.h>
35 35 #include <sys/param.h>
36 36 #include <sys/mkdev.h>
37 37 #include <sys/sysmacros.h>
38 38 #include <sys/systm.h>
39 39 #include <sys/stropts.h>
40 40 #include <sys/stream.h>
41 41 #include <sys/kmem.h>
42 42 #include <sys/conf.h>
43 43 #include <sys/ddi.h>
44 44 #include <sys/devops.h>
45 45 #include <sys/sunddi.h>
46 46 #include <sys/ksynch.h>
47 47 #include <sys/dlpi.h>
48 48 #include <sys/ethernet.h>
49 49 #include <sys/strsun.h>
50 50 #include <sys/stat.h>
51 51 #include <netinet/in.h> /* for byteorder macros on machines that define them */
52 52 #include <sys/llc1.h>
53 53 #include <sys/kstat.h>
54 54 #include <sys/debug.h>
55 55
56 56 /*
57 57 * function prototypes, etc.
58 58 */
59 59 static int llc1_open(queue_t *q, dev_t *dev, int flag, int sflag,
60 60 cred_t *cred);
61 61 static int llc1_close(queue_t *q, int flag, cred_t *cred);
62 62 static int llc1_uwput(queue_t *q, mblk_t *mp);
63 63 static int llc1_uwsrv(queue_t *q);
64 64 static int llc1_lrsrv(queue_t *q);
65 65 static int llc1_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
66 66 static int llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
67 67 static int llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
68 68
69 69 static mblk_t *llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo,
70 70 mblk_t *mp);
71 71 static mblk_t *llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
72 72 static mblk_t *llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
73 73 mblk_t *mp);
74 74 static mblk_t *llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap);
75 75 static mblk_t *llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo,
76 76 mblk_t *mp);
77 77
78 78 static void llc1_ioctl(queue_t *q, mblk_t *mp);
79 79 static void llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp);
80 80 static void llc1_req_raw(llc_mac_info_t *macinfo);
81 81 static void llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim);
82 82
83 83 static minor_t llc1_findminor(llc1dev_t *device);
84 84 static void llc1_send_disable_multi(llc_mac_info_t *, llc_mcast_t *);
85 85
86 86 static void llc1insque(void *elem, void *pred);
87 87 static void llc1remque(void *arg);
88 88 static void llc1error();
89 89 static int llc1_subs_unbind(void);
90 90 static void llc1_init_kstat(llc_mac_info_t *macinfo);
91 91 static void llc1_uninit_kstat(llc_mac_info_t *macinfo);
92 92 static int llc1_update_kstat(kstat_t *ksp, int rw);
93 93 static int llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo);
94 94 static int llc1_unbind(queue_t *q, mblk_t *mp);
95 95 static int llc1_subs_bind(queue_t *q, mblk_t *mp);
96 96 static int llc1_unitdata(queue_t *q, mblk_t *mp);
97 97 static int llc1_inforeq(queue_t *q, mblk_t *mp);
98 98 static int llc1attach(queue_t *q, mblk_t *mp);
99 99 static void llc1_send_bindreq(llc_mac_info_t *macinfo);
100 100 static int llc1_req_info(queue_t *q);
101 101 static int llc1_cmds(queue_t *q, mblk_t *mp);
102 102 static int llc1_setppa(struct ll_snioc *snioc);
103 103 static int llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc);
104 104 static int llc1_bind(queue_t *q, mblk_t *mp);
105 105 static int llc1unattach(queue_t *q, mblk_t *mp);
106 106 static int llc1_enable_multi(queue_t *q, mblk_t *mp);
107 107 static int llc1_disable_multi(queue_t *q, mblk_t *mp);
108 108 static int llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res);
109 109 static int llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res);
110 110 static int llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo);
111 111 static int llc1_snap_match(llc1_t *lld, struct snaphdr *snap);
112 112
113 113 /*
114 114 * the standard streams glue for defining the type of streams entity and the
115 115 * operational parameters.
116 116 */
117 117
118 118 static struct module_info llc1_minfo = {
119 119 LLC1IDNUM,
120 120 "llc1",
121 121 0,
122 122 LLC1_DEFMAX,
123 123 LLC1_HIWATER, /* high water mark */
124 124 LLC1_LOWATER, /* low water mark */
125 125 };
126 126
127 127 static struct qinit llc1_rint = {
128 128 NULL,
129 129 NULL,
130 130 llc1_open,
131 131 llc1_close,
132 132 NULL,
133 133 &llc1_minfo,
134 134 NULL
135 135 };
136 136
137 137 static struct qinit llc1_wint = {
138 138 llc1_uwput,
139 139 llc1_uwsrv,
140 140 NULL,
141 141 NULL,
142 142 NULL,
143 143 &llc1_minfo,
144 144 NULL
145 145 };
146 146
147 147 static struct qinit llc1_muxrint = {
148 148 putq,
149 149 llc1_lrsrv,
150 150 NULL,
151 151 NULL,
152 152 NULL,
153 153 &llc1_minfo,
154 154 NULL
155 155 };
156 156
157 157 static struct qinit llc1_muxwint = {
158 158 NULL,
159 159 NULL,
160 160 NULL,
161 161 NULL,
162 162 NULL,
163 163 &llc1_minfo,
164 164 NULL
165 165 };
166 166
167 167 struct streamtab llc1_info = {
168 168 &llc1_rint,
169 169 &llc1_wint,
170 170 &llc1_muxrint,
171 171 &llc1_muxwint
172 172 };
173 173
174 174 /*
175 175 * loadable module/driver wrapper this allows llc1 to be unloaded later
176 176 */
177 177
178 178 #if !defined(BUILD_STATIC)
179 179 #include <sys/modctl.h>
180 180
181 181 /* define the "ops" structure for a STREAMS driver */
182 182 DDI_DEFINE_STREAM_OPS(llc1_ops, nulldev, nulldev, llc1_attach,
183 183 llc1_detach, nodev, llc1_getinfo, D_MP | D_MTPERMOD, &llc1_info,
184 184 ddi_quiesce_not_supported);
185 185
↓ open down ↓ |
185 lines elided |
↑ open up ↑ |
186 186 /*
187 187 * Module linkage information for the kernel.
188 188 */
189 189 static struct modldrv modldrv = {
190 190 &mod_driverops, /* Type of module. This one is a driver */
191 191 "LLC Class 1 Driver",
192 192 &llc1_ops, /* driver ops */
193 193 };
194 194
195 195 static struct modlinkage modlinkage = {
196 - MODREV_1, (void *)&modldrv, NULL
196 + MODREV_1, { (void *)&modldrv, NULL }
197 197 };
198 198
199 199 int
200 200 _init(void)
201 201 {
202 202 return (mod_install(&modlinkage));
203 203 }
204 204
205 205 int
206 206 _fini(void)
207 207 {
208 208 return (mod_remove(&modlinkage));
209 209 }
210 210
211 211 int
212 212 _info(struct modinfo *modinfop)
213 213 {
214 214 return (mod_info(&modlinkage, modinfop));
215 215 }
216 216
217 217 #endif
218 218
219 219 #ifdef LLC1_DEBUG
220 220 extern int llc1_debug = 0x0;
221 221
222 222 #endif
223 223
224 224 /*
225 225 * Allocate and zero-out "number" structures each of type "structure" in
226 226 * kernel memory.
227 227 */
228 228 #define GETSTRUCT(structure, number) \
229 229 (kmem_zalloc(sizeof (structure) * (number), KM_NOSLEEP))
230 230 #define GETBUF(structure, size) \
231 231 (kmem_zalloc(size, KM_NOSLEEP))
232 232
233 233 static struct llc1device llc1_device_list;
234 234
235 235 /*
236 236 * llc1_attach - init time attach support When the hardware specific attach
237 237 * is called, it must call this procedure with the device class structure
238 238 */
239 239
240 240 static int
241 241 llc1_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
242 242 {
243 243 if (cmd != DDI_ATTACH)
244 244 return (DDI_FAILURE);
245 245
246 246 /*
247 247 * there isn't any hardware but we do need to initialize things
248 248 */
249 249 if (!(llc1_device_list.llc1_status & LLC1_ATTACHED)) {
250 250 llc1_device_list.llc1_status |= LLC1_ATTACHED;
251 251 rw_init(&llc1_device_list.llc1_rwlock, NULL, RW_DRIVER, NULL);
252 252
253 253 /* make sure minor device lists are initialized */
254 254 llc1_device_list.llc1_str_next =
255 255 llc1_device_list.llc1_str_prev =
256 256 (llc1_t *)&llc1_device_list.llc1_str_next;
257 257
258 258 /* make sure device list is initialized */
259 259 llc1_device_list.llc1_mac_next =
260 260 llc1_device_list.llc1_mac_prev =
261 261 (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
262 262 }
263 263
264 264 /*
265 265 * now do all the DDI stuff necessary
266 266 */
267 267
268 268 ddi_set_driver_private(devinfo, &llc1_device_list);
269 269
270 270 /*
271 271 * create the file system device node
272 272 */
273 273 if (ddi_create_minor_node(devinfo, "llc1", S_IFCHR,
274 274 0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
275 275 llc1error(devinfo, "ddi_create_minor_node failed");
276 276 ddi_remove_minor_node(devinfo, NULL);
277 277 return (DDI_FAILURE);
278 278 }
279 279 llc1_device_list.llc1_multisize = ddi_getprop(DDI_DEV_T_NONE,
280 280 devinfo, 0, "multisize", 0);
281 281 if (llc1_device_list.llc1_multisize == 0)
282 282 llc1_device_list.llc1_multisize = LLC1_MAX_MULTICAST;
283 283
284 284 ddi_report_dev(devinfo);
285 285 return (DDI_SUCCESS);
286 286 }
287 287
288 288 /*
289 289 * llc1_detach standard kernel interface routine
290 290 */
291 291
292 292 static int
293 293 llc1_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
294 294 {
295 295 if (cmd != DDI_DETACH) {
296 296 return (DDI_FAILURE);
297 297 }
298 298 if (llc1_device_list.llc1_ndevice > 0)
299 299 return (DDI_FAILURE);
300 300 /* remove all mutex and locks */
301 301 rw_destroy(&llc1_device_list.llc1_rwlock);
302 302 llc1_device_list.llc1_status = 0; /* no longer attached */
303 303 ddi_remove_minor_node(dev, NULL);
304 304 return (DDI_SUCCESS);
305 305 }
306 306
307 307 /*
308 308 * llc1_devinfo(dev, cmd, arg, result) standard kernel devinfo lookup
309 309 * function
310 310 */
311 311 /*ARGSUSED2*/
312 312 static int
313 313 llc1_getinfo(dev_info_t *dev, ddi_info_cmd_t cmd, void *arg, void **result)
314 314 {
315 315 int error;
316 316
317 317 switch (cmd) {
318 318 case DDI_INFO_DEVT2DEVINFO:
319 319 if (dev == NULL) {
320 320 error = DDI_FAILURE;
321 321 } else {
322 322 *result = (void *)dev;
323 323 error = DDI_SUCCESS;
324 324 }
325 325 break;
326 326 case DDI_INFO_DEVT2INSTANCE:
327 327 *result = (void *)0;
328 328 error = DDI_SUCCESS;
329 329 break;
330 330 default:
331 331 error = DDI_FAILURE;
332 332 }
333 333 return (error);
334 334 }
335 335
336 336 /*
337 337 * llc1_open()
338 338 * LLC1 open routine, called when device is opened by the user
339 339 */
340 340
341 341 /*ARGSUSED2*/
342 342 static int
343 343 llc1_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
344 344 {
345 345 llc1_t *llc1;
346 346 minor_t minordev;
347 347 int status = 0;
348 348
349 349 ASSERT(q);
350 350
351 351 /*
352 352 * Stream already open, sucess.
353 353 */
354 354 if (q->q_ptr)
355 355 return (0);
356 356 /*
357 357 * Serialize access through open/close this will serialize across all
358 358 * llc1 devices, but open and close are not frequent so should not
359 359 * induce much, if any delay.
360 360 */
361 361 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
362 362
363 363 if (sflag == CLONEOPEN) {
364 364 /* need to find a minor dev */
365 365 minordev = llc1_findminor(&llc1_device_list);
366 366 if (minordev == 0) {
367 367 rw_exit(&llc1_device_list.llc1_rwlock);
368 368 return (ENXIO);
369 369 }
370 370 *dev = makedevice(getmajor(*dev), minordev);
371 371 } else {
372 372 minordev = getminor (*dev);
373 373 if ((minordev > MAXMIN32) || (minordev == 0)) {
374 374 rw_exit(&llc1_device_list.llc1_rwlock);
375 375 return (ENXIO);
376 376 }
377 377 }
378 378
379 379 /*
380 380 * get a per-stream structure and link things together so we
381 381 * can easily find them later.
382 382 */
383 383
384 384 llc1 = kmem_zalloc(sizeof (llc1_t), KM_SLEEP);
385 385 llc1->llc_qptr = q;
386 386 WR(q)->q_ptr = q->q_ptr = (caddr_t)llc1;
387 387 /*
388 388 * fill in the structure and state info
389 389 */
390 390 llc1->llc_state = DL_UNATTACHED;
391 391 llc1->llc_style = DL_STYLE2;
392 392 llc1->llc_minor = minordev;
393 393
394 394 mutex_init(&llc1->llc_lock, NULL, MUTEX_DRIVER, NULL);
395 395 llc1insque(llc1, llc1_device_list.llc1_str_prev);
396 396 rw_exit(&llc1_device_list.llc1_rwlock);
397 397 qprocson(q); /* start the queues running */
398 398 return (status);
399 399 }
400 400
401 401 /*
402 402 * llc1_close(q)
403 403 * normal stream close call checks current status and cleans up
404 404 * data structures that were dynamically allocated
405 405 */
406 406 /*ARGSUSED1*/
407 407 static int
408 408 llc1_close(queue_t *q, int flag, cred_t *cred)
409 409 {
410 410 llc1_t *llc1;
411 411
412 412 ASSERT(q);
413 413 ASSERT(q->q_ptr);
414 414
415 415 qprocsoff(q);
416 416 llc1 = (llc1_t *)q->q_ptr;
417 417 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
418 418 /* completely disassociate the stream from the device */
419 419 q->q_ptr = WR(q)->q_ptr = NULL;
420 420
421 421 (void) llc1remque(llc1); /* remove from active list */
422 422 rw_exit(&llc1_device_list.llc1_rwlock);
423 423
424 424 mutex_enter(&llc1->llc_lock);
425 425 if (llc1->llc_state == DL_IDLE || llc1->llc_state == DL_UNBOUND) {
426 426 llc1->llc_state = DL_UNBOUND; /* force the issue */
427 427 }
428 428
429 429 if (llc1->llc_mcast != NULL) {
430 430 int i;
431 431
432 432 for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
433 433 llc_mcast_t *mcast;
434 434
435 435 if ((mcast = llc1->llc_mcast[i]) != NULL) {
436 436 /*
437 437 * disable from stream and possibly
438 438 * lower stream
439 439 */
440 440 if (llc1->llc_mac_info &&
441 441 llc1->llc_mac_info->llcp_flags &
442 442 LLC1_AVAILABLE)
443 443 llc1_send_disable_multi(
444 444 llc1->llc_mac_info,
445 445 mcast);
446 446 llc1->llc_mcast[i] = NULL;
447 447 }
448 448 }
449 449 kmem_free(llc1->llc_mcast,
450 450 sizeof (llc_mcast_t *) * llc1->llc_multicnt);
451 451 llc1->llc_mcast = NULL;
452 452 }
453 453 llc1->llc_state = DL_UNATTACHED;
454 454
455 455 mutex_exit(&llc1->llc_lock);
456 456
457 457 mutex_destroy(&llc1->llc_lock);
458 458
459 459 kmem_free(llc1, sizeof (llc1_t));
460 460
461 461 return (0);
462 462 }
463 463
464 464 /*
465 465 * llc1_uwput()
466 466 * general llc stream write put routine. Receives ioctl's from
467 467 * user level and data from upper modules and processes them immediately.
468 468 * M_PROTO/M_PCPROTO are queued for later processing by the service
469 469 * procedure.
470 470 */
471 471
472 472 static int
473 473 llc1_uwput(queue_t *q, mblk_t *mp)
474 474 {
475 475 llc1_t *ld = (llc1_t *)(q->q_ptr);
476 476
477 477 #ifdef LLC1_DEBUG
478 478 if (llc1_debug & LLCTRACE)
479 479 printf("llc1_wput(%x %x): type %d\n", q, mp, DB_TYPE(mp));
480 480 #endif
481 481 switch (DB_TYPE(mp)) {
482 482
483 483 case M_IOCTL: /* no waiting in ioctl's */
484 484 (void) llc1_ioctl(q, mp);
485 485 break;
486 486
487 487 case M_FLUSH: /* canonical flush handling */
488 488 if (*mp->b_rptr & FLUSHW)
489 489 flushq(q, 0);
490 490
491 491 if (*mp->b_rptr & FLUSHR) {
492 492 flushq(RD(q), 0);
493 493 *mp->b_rptr &= ~FLUSHW;
494 494 qreply(q, mp);
495 495 } else
496 496 freemsg(mp);
497 497 break;
498 498
499 499 /* for now, we will always queue */
500 500 case M_PROTO:
501 501 case M_PCPROTO:
502 502 (void) putq(q, mp);
503 503 break;
504 504
505 505 case M_DATA:
506 506 /* fast data / raw support */
507 507 if ((ld->llc_flags & (LLC_RAW | LLC_FAST)) == 0 ||
508 508 ld->llc_state != DL_IDLE) {
509 509 (void) merror(q, mp, EPROTO);
510 510 break;
511 511 }
512 512 /* need to do further checking */
513 513 (void) putq(q, mp);
514 514 break;
515 515
516 516 default:
517 517 #ifdef LLC1_DEBUG
518 518 if (llc1_debug & LLCERRS)
519 519 printf("llc1: Unexpected packet type from queue: %d\n",
520 520 mp->b_datap->db_type);
521 521 #endif
522 522 freemsg(mp);
523 523 }
524 524 return (0);
525 525 }
526 526
527 527 /*
528 528 * llc1_lrsrv()
529 529 * called when data is put into the service queue from below.
530 530 * Determines additional processing that might be needed and sends the data
531 531 * upstream in the form of a Data Indication packet.
532 532 */
533 533 static int
534 534 llc1_lrsrv(queue_t *q)
535 535 {
536 536 mblk_t *mp;
537 537 union DL_primitives *prim;
538 538 llc_mac_info_t *macinfo = (llc_mac_info_t *)q->q_ptr;
539 539 struct iocblk *iocp;
540 540
541 541 #ifdef LLC1_DEBUG
542 542 if (llc1_debug & LLCTRACE)
543 543 printf("llc1_rsrv(%x)\n", q);
544 544 if (llc1_debug & LLCRECV) {
545 545 printf("llc1_lrsrv: q=%x macinfo=%x", q, macinfo);
546 546 if (macinfo == NULL) {
547 547 printf("NULL macinfo");
548 548 panic("null macinfo in lrsrv");
549 549 /*NOTREACHED*/
550 550 }
551 551 printf("\n");
552 552 }
553 553 #endif
554 554
555 555 /*
556 556 * determine where message goes, then call the proper handler
557 557 */
558 558
559 559 while ((mp = getq(q)) != NULL) {
560 560 switch (DB_TYPE(mp)) {
561 561 case M_PROTO:
562 562 case M_PCPROTO:
563 563 prim = (union DL_primitives *)mp->b_rptr;
564 564 /* only some primitives ever get passed through */
565 565 switch (prim->dl_primitive) {
566 566 case DL_INFO_ACK:
567 567 if (macinfo->llcp_flags & LLC1_LINKED) {
568 568 /*
569 569 * we are in the midst of completing
570 570 * the I_LINK/I_PLINK and needed this
571 571 * info
572 572 */
573 573 macinfo->llcp_flags &= ~LLC1_LINKED;
574 574 macinfo->llcp_flags |= LLC1_AVAILABLE;
575 575 macinfo->llcp_maxpkt =
576 576 prim->info_ack.dl_max_sdu;
577 577 macinfo->llcp_minpkt =
578 578 prim->info_ack.dl_min_sdu;
579 579 macinfo->llcp_type =
580 580 prim->info_ack.dl_mac_type;
581 581 if (macinfo->llcp_type == DL_ETHER) {
582 582 macinfo->llcp_type = DL_CSMACD;
583 583 /*
584 584 * size of max header
585 585 * (including SNAP)
586 586 */
587 587 macinfo->llcp_maxpkt -= 8;
588 588 }
589 589 macinfo->llcp_addrlen =
590 590 prim->info_ack.dl_addr_length -
591 591 ABS(prim->info_ack.dl_sap_length);
592 592
593 593 bcopy(mp->b_rptr +
594 594 prim->info_ack.dl_addr_offset,
595 595 macinfo->llcp_macaddr,
596 596 macinfo->llcp_addrlen);
597 597 bcopy(mp->b_rptr +
598 598 prim->info_ack.
599 599 dl_brdcst_addr_offset,
600 600 macinfo->llcp_broadcast,
601 601 prim->info_ack.
602 602 dl_brdcst_addr_length);
603 603
604 604 if (prim->info_ack.dl_current_state ==
605 605 DL_UNBOUND)
606 606 llc1_send_bindreq(macinfo);
607 607 freemsg(mp);
608 608 /*
609 609 * need to put the lower stream into
610 610 * DLRAW mode. Currently only DL_ETHER
611 611 * or DL_CSMACD
612 612 */
613 613 switch (macinfo->llcp_type) {
614 614 case DL_ETHER:
615 615 case DL_CSMACD:
616 616 /*
617 617 * raw mode is optimal so ask
618 618 * for it * we might not get
619 619 * it but that's OK
620 620 */
621 621 llc1_req_raw(macinfo);
622 622 break;
623 623 default:
624 624 /*
625 625 * don't want raw mode so don't
626 626 * ask for it
627 627 */
628 628 break;
629 629 }
630 630 } else {
631 631 if (prim->info_ack.dl_current_state ==
632 632 DL_IDLE)
633 633 /* address was wrong before */
634 634 bcopy(mp->b_rptr +
635 635 prim->info_ack.dl_addr_offset,
636 636 macinfo->llcp_macaddr,
637 637 macinfo->llcp_addrlen);
638 638 freemsg(mp);
639 639 }
640 640 break;
641 641 case DL_BIND_ACK:
642 642 /*
643 643 * if we had to bind, the macaddr is wrong
644 644 * so get it again
645 645 */
646 646 freemsg(mp);
647 647 (void) llc1_req_info(q);
648 648 break;
649 649 case DL_UNITDATA_IND:
650 650 /* when not using raw mode we get these */
651 651 (void) llc1_recv(macinfo, mp);
652 652 break;
653 653 case DL_ERROR_ACK:
654 654 /* binding is a special case */
655 655 if (prim->error_ack.dl_error_primitive ==
656 656 DL_BIND_REQ) {
657 657 freemsg(mp);
658 658 if (macinfo->llcp_flags & LLC1_BINDING)
659 659 llc1_send_bindreq(macinfo);
660 660 } else
661 661 llc1_find_waiting(macinfo, mp,
662 662 prim->error_ack.dl_error_primitive);
663 663 break;
664 664 case DL_PHYS_ADDR_ACK:
665 665 llc1_find_waiting(macinfo, mp,
666 666 DL_PHYS_ADDR_REQ);
667 667 break;
668 668 case DL_OK_ACK:
669 669 if (prim->ok_ack.dl_correct_primitive ==
670 670 DL_BIND_REQ)
671 671 macinfo->llcp_flags &= ~LLC1_BINDING;
672 672 /* FALLTHROUGH */
673 673 default:
674 674 freemsg(mp);
675 675 }
676 676 break;
677 677
678 678 case M_IOCACK:
679 679 /* probably our DLIOCRAW completing */
680 680 iocp = (struct iocblk *)mp->b_rptr;
681 681 if ((macinfo->llcp_flags & LLC1_RAW_WAIT) &&
682 682 macinfo->llcp_iocid == iocp->ioc_id) {
683 683 macinfo->llcp_flags &= ~LLC1_RAW_WAIT;
684 684 /* we can use this form */
685 685 macinfo->llcp_flags |= LLC1_USING_RAW;
686 686 freemsg(mp);
687 687 break;
688 688 }
689 689 /* need to find the correct queue */
690 690 freemsg(mp);
691 691 break;
692 692 case M_IOCNAK:
693 693 iocp = (struct iocblk *)mp->b_rptr;
694 694 if ((macinfo->llcp_flags & LLC1_RAW_WAIT) &&
695 695 macinfo->llcp_iocid == iocp->ioc_id) {
696 696 macinfo->llcp_flags &= ~LLC1_RAW_WAIT;
697 697 freemsg(mp);
698 698 break;
699 699 }
700 700 /* need to find the correct queue */
701 701 freemsg(mp);
702 702 break;
703 703 case M_DATA:
704 704 llc1_recv(macinfo, mp);
705 705 break;
706 706 }
707 707 }
708 708 return (0);
709 709 }
710 710
711 711 /*
712 712 * llc1_uwsrv - Incoming messages are processed according to the DLPI
713 713 * protocol specification
714 714 */
715 715
716 716 static int
717 717 llc1_uwsrv(queue_t *q)
718 718 {
719 719 mblk_t *mp;
720 720 llc1_t *lld = (llc1_t *)q->q_ptr;
721 721 union DL_primitives *prim;
722 722 int err;
723 723
724 724 #ifdef LLC1_DEBUG
725 725 if (llc1_debug & LLCTRACE)
726 726 printf("llc1_wsrv(%x)\n", q);
727 727 #endif
728 728
729 729
730 730 while ((mp = getq(q)) != NULL) {
731 731 switch (mp->b_datap->db_type) {
732 732 case M_PROTO: /* Will be an DLPI message of some type */
733 733 case M_PCPROTO:
734 734 if ((err = llc1_cmds(q, mp)) != LLCE_OK) {
735 735 prim = (union DL_primitives *)mp->b_rptr;
736 736 if (err == LLCE_NOBUFFER || err == DL_SYSERR) {
737 737 /* quit while we're ahead */
738 738 lld->llc_stats->llcs_nobuffer++;
739 739 #ifdef LLC1_DEBUG
740 740 if (llc1_debug & LLCERRS)
741 741 printf(
742 742 "llc1_cmds: nonfatal err=%d\n",
743 743 err);
744 744 #endif
745 745 (void) putbq(q, mp);
746 746 return (0);
747 747
748 748 } else {
749 749 dlerrorack(q, mp,
750 750 prim->dl_primitive,
751 751 err, 0);
752 752 }
753 753 }
754 754 break;
755 755 case M_DATA:
756 756 /*
757 757 * retry of a previously processed
758 758 * UNITDATA_REQ or is a RAW message from
759 759 * above
760 760 */
761 761
762 762 mutex_enter(&lld->llc_lock);
763 763 putnext(lld->llc_mac_info->llcp_queue, mp);
764 764 mutex_exit(&lld->llc_lock);
765 765 freemsg(mp); /* free on success */
766 766 break;
767 767
768 768 /* This should never happen */
769 769 default:
770 770 #ifdef LLC1_DEBUG
771 771 if (llc1_debug & LLCERRS)
772 772 printf("llc1_wsrv: type(%x) not supported\n",
773 773 mp->b_datap->db_type);
774 774 #endif
775 775 freemsg(mp); /* unknown types are discarded */
776 776 break;
777 777 }
778 778 }
779 779 return (0);
780 780 }
781 781
782 782 /*
783 783 * llc1_multicast used to determine if the address is a multicast address for
784 784 * this user.
785 785 */
786 786 int
787 787 llc1_multicast(struct ether_addr *addr, llc1_t *lld)
788 788 {
789 789 int i;
790 790
791 791 if (lld->llc_mcast)
792 792 for (i = 0; i < lld->llc_multicnt; i++)
793 793 if (lld->llc_mcast[i] &&
794 794 lld->llc_mcast[i]->llcm_refcnt &&
795 795 bcmp(lld->llc_mcast[i]->llcm_addr,
796 796 addr->ether_addr_octet, ETHERADDRL) == 0)
797 797 return (1);
798 798 return (0);
799 799 }
800 800
801 801 /*
802 802 * llc1_ioctl handles all ioctl requests passed downstream. This routine is
803 803 * passed a pointer to the message block with the ioctl request in it, and a
804 804 * pointer to the queue so it can respond to the ioctl request with an ack.
805 805 */
806 806
807 807 int llc1_doreqinfo;
808 808
809 809 static void
810 810 llc1_ioctl(queue_t *q, mblk_t *mp)
811 811 {
812 812 struct iocblk *iocp;
813 813 llc1_t *lld;
814 814 struct linkblk *link;
815 815 llc_mac_info_t *macinfo;
816 816 mblk_t *tmp;
817 817 int error;
818 818
819 819 #ifdef LLC1_DEBUG
820 820 if (llc1_debug & LLCTRACE)
821 821 printf("llc1_ioctl(%x %x)\n", q, mp);
822 822 #endif
823 823 lld = (llc1_t *)q->q_ptr;
824 824 iocp = (struct iocblk *)mp->b_rptr;
825 825 switch (iocp->ioc_cmd) {
826 826 /* XXX need to lock the data structures */
827 827 case I_PLINK:
828 828 case I_LINK:
829 829 link = (struct linkblk *)mp->b_cont->b_rptr;
830 830 tmp = allocb(sizeof (llc_mac_info_t), BPRI_MED);
831 831 if (tmp == NULL) {
832 832 (void) miocnak(q, mp, 0, ENOSR);
833 833 return;
834 834 }
835 835 bzero(tmp->b_rptr, sizeof (llc_mac_info_t));
836 836 macinfo = (llc_mac_info_t *)tmp->b_rptr;
837 837 macinfo->llcp_mb = tmp;
838 838 macinfo->llcp_next = macinfo->llcp_prev = macinfo;
839 839 macinfo->llcp_queue = link->l_qbot;
840 840 macinfo->llcp_lindex = link->l_index;
841 841 /* tentative */
842 842 macinfo->llcp_ppa = --llc1_device_list.llc1_nextppa;
843 843 llc1_device_list.llc1_ndevice++;
844 844 macinfo->llcp_flags |= LLC1_LINKED | LLC1_DEF_PPA;
845 845 macinfo->llcp_lqtop = q;
846 846 macinfo->llcp_data = NULL;
847 847
848 848 /* need to do an info_req before an info_req or attach */
849 849
850 850 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
851 851 llc1insque(macinfo, llc1_device_list.llc1_mac_prev);
852 852 macinfo->llcp_queue->q_ptr = RD(macinfo->llcp_queue)->q_ptr =
853 853 (caddr_t)macinfo;
854 854 llc1_init_kstat(macinfo);
855 855 rw_exit(&llc1_device_list.llc1_rwlock);
856 856
857 857 /* initiate getting the info */
858 858 (void) llc1_req_info(macinfo->llcp_queue);
859 859
860 860 miocack(q, mp, 0, 0);
861 861 return;
862 862
863 863 case I_PUNLINK:
864 864 case I_UNLINK:
865 865 link = (struct linkblk *)mp->b_cont->b_rptr;
866 866 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
867 867 for (macinfo = llc1_device_list.llc1_mac_next;
868 868 macinfo != NULL &&
869 869 macinfo !=
870 870 (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
871 871 macinfo = macinfo->llcp_next) {
872 872 if (macinfo->llcp_lindex == link->l_index &&
873 873 macinfo->llcp_queue == link->l_qbot) {
874 874 /* found it */
875 875
876 876 ASSERT(macinfo->llcp_next);
877 877
878 878 /* remove from device list */
879 879 llc1_device_list.llc1_ndevice--;
880 880 llc1remque(macinfo);
881 881
882 882 /* remove any mcast structs */
883 883 if (macinfo->llcp_mcast != NULL) {
884 884 kmem_free(macinfo->llcp_mcast,
885 885 sizeof (llc_mcast_t) *
886 886 llc1_device_list.llc1_multisize);
887 887 macinfo->llcp_mcast = NULL;
888 888 }
889 889
890 890 /* remove any kstat counters */
891 891 if (macinfo->llcp_kstatp != NULL)
892 892 llc1_uninit_kstat(macinfo);
893 893 if (macinfo->llcp_mb != NULL)
894 894 freeb(macinfo->llcp_mb);
895 895
896 896 lld->llc_mac_info = NULL;
897 897
898 898 miocack(q, mp, 0, 0);
899 899
900 900 /* finish any necessary setup */
901 901 if (llc1_device_list.llc1_ndevice == 0)
902 902 llc1_device_list.llc1_nextppa = 0;
903 903
904 904 rw_exit(&llc1_device_list.llc1_rwlock);
905 905 return;
906 906 }
907 907 }
908 908 rw_exit(&llc1_device_list.llc1_rwlock);
909 909 /*
910 910 * what should really be done here -- force errors on all
911 911 * streams?
912 912 */
913 913 miocnak(q, mp, 0, EINVAL);
914 914 return;
915 915
916 916 case L_SETPPA:
917 917 error = miocpullup(mp, sizeof (struct ll_snioc));
918 918 if (error != 0) {
919 919 miocnak(q, mp, 0, error);
920 920 return;
921 921 }
922 922
923 923 if (llc1_setppa((struct ll_snioc *)mp->b_cont->b_rptr) >= 0) {
924 924 miocack(q, mp, 0, 0);
925 925 return;
926 926 }
927 927 miocnak(q, mp, 0, EINVAL);
928 928 return;
929 929
930 930 case L_GETPPA:
931 931 if (mp->b_cont == NULL) {
932 932 mp->b_cont = allocb(sizeof (struct ll_snioc), BPRI_MED);
933 933 if (mp->b_cont == NULL) {
934 934 miocnak(q, mp, 0, ENOSR);
935 935 return;
936 936 }
937 937 mp->b_cont->b_wptr =
938 938 mp->b_cont->b_rptr + sizeof (struct ll_snioc);
939 939 } else {
940 940 error = miocpullup(mp, sizeof (struct ll_snioc));
941 941 if (error != 0) {
942 942 miocnak(q, mp, 0, error);
943 943 return;
944 944 }
945 945 }
946 946
947 947 lld = (llc1_t *)q->q_ptr;
948 948 if (llc1_getppa(lld->llc_mac_info,
949 949 (struct ll_snioc *)mp->b_cont->b_rptr) >= 0)
950 950 miocack(q, mp, 0, 0);
951 951 else
952 952 miocnak(q, mp, 0, EINVAL);
953 953 return;
954 954 default:
955 955 miocnak(q, mp, 0, EINVAL);
956 956 }
957 957 }
958 958
959 959 /*
960 960 * llc1_setppa(snioc) this function sets the real PPA number for a previously
961 961 * I_LINKED stream. Be careful to select the macinfo struct associated
962 962 * with our llc struct, to avoid erroneous references.
963 963 */
964 964
965 965 static int
966 966 llc1_setppa(struct ll_snioc *snioc)
967 967 {
968 968 llc_mac_info_t *macinfo;
969 969
970 970 for (macinfo = llc1_device_list.llc1_mac_next;
971 971 macinfo != (llc_mac_info_t *)&llc1_device_list.llc1_mac_next;
972 972 macinfo = macinfo->llcp_next)
973 973 if (macinfo->llcp_lindex == snioc->lli_index &&
974 974 (macinfo->llcp_flags & LLC1_DEF_PPA)) {
975 975 macinfo->llcp_flags &= ~LLC1_DEF_PPA;
976 976 macinfo->llcp_ppa = snioc->lli_ppa;
977 977 return (0);
978 978 }
979 979 return (-1);
980 980 }
981 981
982 982 /*
983 983 * llc1_getppa(macinfo, snioc) returns the PPA for this stream
984 984 */
985 985 static int
986 986 llc1_getppa(llc_mac_info_t *macinfo, struct ll_snioc *snioc)
987 987 {
988 988 if (macinfo == NULL)
989 989 return (-1);
990 990 snioc->lli_ppa = macinfo->llcp_ppa;
991 991 snioc->lli_index = macinfo->llcp_lindex;
992 992 return (0);
993 993 }
994 994
995 995 /*
996 996 * llc1_cmds - process the DL commands as defined in dlpi.h
997 997 */
998 998 static int
999 999 llc1_cmds(queue_t *q, mblk_t *mp)
1000 1000 {
1001 1001 union DL_primitives *dlp;
1002 1002 llc1_t *llc = (llc1_t *)q->q_ptr;
1003 1003 int result = 0;
1004 1004 llc_mac_info_t *macinfo = llc->llc_mac_info;
1005 1005
1006 1006 dlp = (union DL_primitives *)mp->b_rptr;
1007 1007 #ifdef LLC1_DEBUG
1008 1008 if (llc1_debug & LLCTRACE)
1009 1009 printf("llc1_cmds(%x, %x):dlp=%x, dlp->dl_primitive=%d\n",
1010 1010 q, mp, dlp, dlp->dl_primitive);
1011 1011 #endif
1012 1012 mutex_enter(&llc->llc_lock);
1013 1013 rw_enter(&llc1_device_list.llc1_rwlock, RW_READER);
1014 1014
1015 1015 switch (dlp->dl_primitive) {
1016 1016 case DL_BIND_REQ:
1017 1017 result = llc1_bind(q, mp);
1018 1018 break;
1019 1019
1020 1020 case DL_UNBIND_REQ:
1021 1021 result = llc1_unbind(q, mp);
1022 1022 break;
1023 1023
1024 1024 case DL_SUBS_BIND_REQ:
1025 1025 result = llc1_subs_bind(q, mp);
1026 1026 break;
1027 1027
1028 1028 case DL_SUBS_UNBIND_REQ:
1029 1029 result = llc1_subs_unbind();
1030 1030 break;
1031 1031
1032 1032 case DL_UNITDATA_REQ:
1033 1033 result = llc1_unitdata(q, mp);
1034 1034 break;
1035 1035
1036 1036 case DL_INFO_REQ:
1037 1037 result = llc1_inforeq(q, mp);
1038 1038 break;
1039 1039
1040 1040 case DL_ATTACH_REQ:
1041 1041 result = llc1attach(q, mp);
1042 1042 break;
1043 1043
1044 1044 case DL_DETACH_REQ:
1045 1045 result = llc1unattach(q, mp);
1046 1046 break;
1047 1047
1048 1048 case DL_ENABMULTI_REQ:
1049 1049 result = llc1_enable_multi(q, mp);
1050 1050 break;
1051 1051
1052 1052 case DL_DISABMULTI_REQ:
1053 1053 result = llc1_disable_multi(q, mp);
1054 1054 break;
1055 1055
1056 1056 case DL_XID_REQ:
1057 1057 result = llc1_xid_req_res(q, mp, 0);
1058 1058 break;
1059 1059
1060 1060 case DL_XID_RES:
1061 1061 result = llc1_xid_req_res(q, mp, 1);
1062 1062 break;
1063 1063
1064 1064 case DL_TEST_REQ:
1065 1065 result = llc1_test_req_res(q, mp, 0);
1066 1066 break;
1067 1067
1068 1068 case DL_TEST_RES:
1069 1069 result = llc1_test_req_res(q, mp, 1);
1070 1070 break;
1071 1071
1072 1072 case DL_SET_PHYS_ADDR_REQ:
1073 1073 result = DL_NOTSUPPORTED;
1074 1074 break;
1075 1075
1076 1076 case DL_PHYS_ADDR_REQ:
1077 1077 if (llc->llc_state != DL_UNATTACHED && macinfo) {
1078 1078 llc->llc_waiting_for = dlp->dl_primitive;
1079 1079 putnext(WR(macinfo->llcp_queue), mp);
1080 1080 result = LLCE_OK;
1081 1081 } else {
1082 1082 result = DL_OUTSTATE;
1083 1083 }
1084 1084 break;
1085 1085
1086 1086 case DL_PROMISCON_REQ:
1087 1087 case DL_PROMISCOFF_REQ:
1088 1088 result = DL_NOTSUPPORTED;
1089 1089 break;
1090 1090
1091 1091 default:
1092 1092 #ifdef LLC1_DEBUG
1093 1093 if (llc1_debug & LLCERRS)
1094 1094 printf("llc1_cmds: Received unknown primitive: %d\n",
1095 1095 dlp->dl_primitive);
1096 1096 #endif
1097 1097 result = DL_BADPRIM;
1098 1098 break;
1099 1099 }
1100 1100 rw_exit(&llc1_device_list.llc1_rwlock);
1101 1101 mutex_exit(&llc->llc_lock);
1102 1102 return (result);
1103 1103 }
1104 1104
1105 1105 /*
1106 1106 * llc1_bind - determine if a SAP is already allocated and whether it is
1107 1107 * legal to do the bind at this time
1108 1108 */
1109 1109 static int
1110 1110 llc1_bind(queue_t *q, mblk_t *mp)
1111 1111 {
1112 1112 int sap;
1113 1113 dl_bind_req_t *dlp;
1114 1114 llc1_t *lld = (llc1_t *)q->q_ptr;
1115 1115
1116 1116 ASSERT(lld);
1117 1117
1118 1118 #ifdef LLC1_DEBUG
1119 1119 if (llc1_debug & LLCTRACE)
1120 1120 printf("llc1_bind(%x %x)\n", q, mp);
1121 1121 #endif
1122 1122
1123 1123 dlp = (dl_bind_req_t *)mp->b_rptr;
1124 1124 sap = dlp->dl_sap;
1125 1125
1126 1126 #ifdef LLC1_DEBUG
1127 1127 if (llc1_debug & LLCPROT)
1128 1128 printf("llc1_bind: lsap=%x\n", sap);
1129 1129 #endif
1130 1130
1131 1131 if (lld->llc_mac_info == NULL)
1132 1132 return (DL_OUTSTATE);
1133 1133
1134 1134 if (lld->llc_qptr && lld->llc_state != DL_UNBOUND) {
1135 1135 #ifdef LLC1_DEBUG
1136 1136 if (llc1_debug & LLCERRS)
1137 1137 printf("llc1_bind: stream bound/not attached (%d)\n",
1138 1138 lld->llc_state);
1139 1139 #endif
1140 1140 return (DL_OUTSTATE);
1141 1141 }
1142 1142
1143 1143 if (dlp->dl_service_mode != DL_CLDLS || dlp->dl_max_conind != 0) {
1144 1144 return (DL_UNSUPPORTED);
1145 1145 }
1146 1146 /*
1147 1147 * prohibit group saps. An exception is the broadcast sap which is,
1148 1148 * unfortunately, used by SUNSelect to indicate Novell Netware in
1149 1149 * 802.3 mode. Really should use a very non-802.2 SAP like 0xFFFF
1150 1150 * or -2.
1151 1151 */
1152 1152
1153 1153 if (sap == 0 || (sap <= 0xFF && (sap & 1 && sap != 0xFF)) ||
1154 1154 sap > 0xFFFF) {
1155 1155 return (DL_BADSAP);
1156 1156 }
1157 1157 lld->llc_state = DL_BIND_PENDING;
1158 1158
1159 1159 /* if we fall through, then the SAP is legal */
1160 1160 if (sap == 0xFF) {
1161 1161 if (lld->llc_mac_info->llcp_type == DL_CSMACD)
1162 1162 sap = LLC_NOVELL_SAP;
1163 1163 else
1164 1164 return (DL_BADSAP);
1165 1165 }
1166 1166 lld->llc_sap = sap;
1167 1167
1168 1168 if (sap > 0xFF) {
1169 1169 ushort_t snapsap = htons(sap);
1170 1170 /* this is SNAP, so set things up */
1171 1171 lld->llc_snap[3] = ((uchar_t *)&snapsap)[0];
1172 1172 lld->llc_snap[4] = ((uchar_t *)&snapsap)[1];
1173 1173 /* mark as SNAP but allow OID to be added later */
1174 1174 lld->llc_flags |= LLC_SNAP;
1175 1175 lld->llc_sap = LLC_SNAP_SAP;
1176 1176 }
1177 1177
1178 1178 #ifdef LLC1_DEBUG
1179 1179 if (llc1_debug & LLCPROT)
1180 1180 printf("llc1_bind: ok - type = %d\n", lld->llc_type);
1181 1181 #endif
1182 1182
1183 1183 if (dlp->dl_xidtest_flg & DL_AUTO_XID)
1184 1184 lld->llc_flags |= LLC1_AUTO_XID;
1185 1185 if (dlp->dl_xidtest_flg & DL_AUTO_TEST)
1186 1186 lld->llc_flags |= LLC1_AUTO_TEST;
1187 1187
1188 1188 /* ACK the BIND, if possible */
1189 1189
1190 1190 dlbindack(q, mp, sap, lld->llc_mac_info->llcp_macaddr, 6, 0, 0);
1191 1191
1192 1192 lld->llc_state = DL_IDLE; /* bound and ready */
1193 1193
1194 1194 return (LLCE_OK);
1195 1195 }
1196 1196
1197 1197 /*
1198 1198 * llc1_unbind - perform an unbind of an LSAP or ether type on the stream.
1199 1199 * The stream is still open and can be re-bound.
1200 1200 */
1201 1201 static int
1202 1202 llc1_unbind(queue_t *q, mblk_t *mp)
1203 1203 {
1204 1204 llc1_t *lld;
1205 1205
1206 1206 #ifdef LLC1_DEBUG
1207 1207 if (llc1_debug & LLCTRACE)
1208 1208 printf("llc1_unbind(%x %x)\n", q, mp);
1209 1209 #endif
1210 1210 lld = (llc1_t *)q->q_ptr;
1211 1211
1212 1212 if (lld->llc_mac_info == NULL)
1213 1213 return (DL_OUTSTATE);
1214 1214
1215 1215 if (lld->llc_state != DL_IDLE) {
1216 1216 #ifdef LLC1_DEBUG
1217 1217 if (llc1_debug & LLCERRS)
1218 1218 printf("llc1_unbind: wrong state (%d)\n",
1219 1219 lld->llc_state);
1220 1220 #endif
1221 1221 return (DL_OUTSTATE);
1222 1222 }
1223 1223 lld->llc_state = DL_UNBIND_PENDING;
1224 1224 lld->llc_flags &= ~(LLC_SNAP|LLC_SNAP_OID); /* just in case */
1225 1225 dlokack(q, mp, DL_UNBIND_REQ);
1226 1226 lld->llc_state = DL_UNBOUND;
1227 1227 return (LLCE_OK);
1228 1228 }
1229 1229
1230 1230 /*
1231 1231 * llc1_inforeq - generate the response to an info request
1232 1232 */
1233 1233 static int
1234 1234 llc1_inforeq(queue_t *q, mblk_t *mp)
1235 1235 {
1236 1236 llc1_t *lld;
1237 1237 mblk_t *nmp;
1238 1238 dl_info_ack_t *dlp;
1239 1239 int bufsize;
1240 1240
1241 1241 #ifdef LLC1_DEBUG
1242 1242 if (llc1_debug & LLCTRACE)
1243 1243 printf("llc1_inforeq(%x %x)\n", q, mp);
1244 1244 #endif
1245 1245 lld = (llc1_t *)q->q_ptr;
1246 1246 ASSERT(lld);
1247 1247 if (lld->llc_mac_info == NULL)
1248 1248 bufsize = sizeof (dl_info_ack_t) + ETHERADDRL;
1249 1249 else
1250 1250 bufsize = sizeof (dl_info_ack_t) +
1251 1251 2 * lld->llc_mac_info->llcp_addrlen + 2;
1252 1252
1253 1253 nmp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK);
1254 1254
1255 1255 if (nmp) {
1256 1256 nmp->b_wptr = nmp->b_rptr + sizeof (dl_info_ack_t);
1257 1257 dlp = (dl_info_ack_t *)nmp->b_rptr;
1258 1258 bzero(dlp, DL_INFO_ACK_SIZE);
1259 1259 dlp->dl_primitive = DL_INFO_ACK;
1260 1260 if (lld->llc_mac_info)
1261 1261 dlp->dl_max_sdu = lld->llc_mac_info->llcp_maxpkt;
1262 1262 dlp->dl_min_sdu = 0;
1263 1263 dlp->dl_mac_type = lld->llc_type;
1264 1264 dlp->dl_service_mode = DL_CLDLS;
1265 1265 dlp->dl_current_state = lld->llc_state;
1266 1266 dlp->dl_provider_style =
1267 1267 (lld->llc_style == 0) ? lld->llc_style : DL_STYLE2;
1268 1268
1269 1269 /* now append physical address */
1270 1270 if (lld->llc_mac_info) {
1271 1271 dlp->dl_addr_length = lld->llc_mac_info->llcp_addrlen;
1272 1272 dlp->dl_addr_offset = DL_INFO_ACK_SIZE;
1273 1273 nmp->b_wptr += dlp->dl_addr_length + 1;
1274 1274 bcopy(lld->llc_mac_info->llcp_macaddr,
1275 1275 ((caddr_t)dlp) + dlp->dl_addr_offset,
1276 1276 lld->llc_mac_info->llcp_addrlen);
1277 1277 if (lld->llc_state == DL_IDLE) {
1278 1278 dlp->dl_sap_length = -1; /* 1 byte on end */
1279 1279 *(((caddr_t)dlp) + dlp->dl_addr_offset +
1280 1280 dlp->dl_addr_length) = lld->llc_sap;
1281 1281 dlp->dl_addr_length += 1;
1282 1282 }
1283 1283 /* and the broadcast address */
1284 1284 dlp->dl_brdcst_addr_length =
1285 1285 lld->llc_mac_info->llcp_addrlen;
1286 1286 dlp->dl_brdcst_addr_offset =
1287 1287 dlp->dl_addr_offset + dlp->dl_addr_length;
1288 1288 nmp->b_wptr += dlp->dl_brdcst_addr_length;
1289 1289 bcopy(lld->llc_mac_info->llcp_broadcast,
1290 1290 ((caddr_t)dlp) + dlp->dl_brdcst_addr_offset,
1291 1291 lld->llc_mac_info->llcp_addrlen);
1292 1292 } else {
1293 1293 dlp->dl_addr_length = 0; /* not attached yet */
1294 1294 dlp->dl_addr_offset = NULL;
1295 1295 dlp->dl_sap_length = 0; /* 1 bytes on end */
1296 1296 }
1297 1297 dlp->dl_version = DL_VERSION_2;
1298 1298 qreply(q, nmp);
1299 1299 }
1300 1300 return (LLCE_OK);
1301 1301 }
1302 1302
1303 1303 /*
1304 1304 * llc1_unitdata
1305 1305 * send a datagram. Destination address/lsap is in M_PROTO
1306 1306 * message (first mblock), data is in remainder of message.
1307 1307 *
1308 1308 * NOTE: We are reusing the DL_unitdata_req mblock; if llc header gets any
1309 1309 * bigger, recheck to make sure it still fits! We assume that we have a
1310 1310 * 64-byte dblock for this, since a DL_unitdata_req is 20 bytes and the next
1311 1311 * larger dblock size is 64.
1312 1312 */
1313 1313 static int
1314 1314 llc1_unitdata(queue_t *q, mblk_t *mp)
1315 1315 {
1316 1316 llc1_t *lld = (llc1_t *)q->q_ptr;
1317 1317 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1318 1318 struct ether_header *hdr;
1319 1319 struct llcaddr *llcp;
1320 1320 mblk_t *nmp;
1321 1321 long msglen;
1322 1322 struct llchdr *llchdr;
1323 1323 llc_mac_info_t *macinfo;
1324 1324 int xmt_type = 0;
1325 1325
1326 1326 #ifdef LLC1_DEBUG
1327 1327 if (llc1_debug & LLCTRACE)
1328 1328 printf("llc1_unitdata(%x %x)\n", q, mp);
1329 1329 #endif
1330 1330
1331 1331 if ((macinfo = lld->llc_mac_info) == NULL)
1332 1332 return (DL_OUTSTATE);
1333 1333
1334 1334 if (lld->llc_state != DL_IDLE) {
1335 1335 #ifdef LLC1_DEBUG
1336 1336 if (llc1_debug & LLCERRS)
1337 1337 printf("llc1_unitdata: wrong state (%d)\n",
1338 1338 lld->llc_state);
1339 1339 #endif
1340 1340 return (DL_OUTSTATE);
1341 1341 }
1342 1342
1343 1343 /* need the destination address in all cases */
1344 1344 llcp = (struct llcaddr *)((caddr_t)dlp + dlp->dl_dest_addr_offset);
1345 1345
1346 1346 if (macinfo->llcp_flags & LLC1_USING_RAW) {
1347 1347 /*
1348 1348 * make a valid header for transmission
1349 1349 */
1350 1350
1351 1351 /* need a buffer big enough for the headers */
1352 1352 nmp = allocb(macinfo->llcp_addrlen * 2 + 2 + 8, BPRI_MED);
1353 1353 hdr = (struct ether_header *)nmp->b_rptr;
1354 1354 msglen = msgdsize(mp);
1355 1355
1356 1356 /* fill in type dependent fields */
1357 1357 switch (lld->llc_type) {
1358 1358 case DL_CSMACD: /* 802.3 CSMA/CD */
1359 1359 nmp->b_wptr = nmp->b_rptr + LLC1_CSMACD_HDR_SIZE;
1360 1360 llchdr = (struct llchdr *)nmp->b_wptr;
1361 1361 bcopy(llcp->llca_addr,
1362 1362 hdr->ether_dhost.ether_addr_octet,
1363 1363 ETHERADDRL);
1364 1364 bcopy(macinfo->llcp_macaddr,
1365 1365 hdr->ether_shost.ether_addr_octet,
1366 1366 ETHERADDRL);
1367 1367
1368 1368 if (lld->llc_sap != LLC_NOVELL_SAP) {
1369 1369 /* set length with llc header size */
1370 1370 hdr->ether_type = ntohs(msglen +
1371 1371 sizeof (struct llchdr));
1372 1372
1373 1373 /* need an LLC header, otherwise is Novell */
1374 1374 /* bound sap is always source */
1375 1375 llchdr->llc_ssap = lld->llc_sap;
1376 1376
1377 1377 /* destination sap */
1378 1378 llchdr->llc_dsap = llcp->llca_sap;
1379 1379
1380 1380 /* always Unnumbered Information */
1381 1381 llchdr->llc_ctl = LLC_UI;
1382 1382
1383 1383 nmp->b_wptr += sizeof (struct llchdr);
1384 1384
1385 1385 if (lld->llc_flags & LLC_SNAP) {
1386 1386 bcopy(lld->llc_snap, nmp->b_wptr, 5);
1387 1387 llchdr->llc_dsap = LLC_SNAP_SAP;
1388 1388 nmp->b_wptr += 5;
1389 1389 }
1390 1390 } else {
1391 1391 /* set length without llc header size */
1392 1392 hdr->ether_type = ntohs(msglen);
1393 1393
1394 1394 /* we don't do anything else for Netware */
1395 1395 }
1396 1396
1397 1397 if (ismulticast(hdr->ether_dhost.ether_addr_octet)) {
1398 1398 if (bcmp(hdr->ether_dhost.ether_addr_octet,
1399 1399 macinfo->llcp_broadcast, ETHERADDRL) == 0)
1400 1400 xmt_type = 2;
1401 1401 else
1402 1402 xmt_type = 1;
1403 1403 }
1404 1404
1405 1405 break;
1406 1406
1407 1407 default: /* either RAW or unknown, send as is */
1408 1408 break;
1409 1409 }
1410 1410 DB_TYPE(nmp) = M_DATA; /* ether/llc header is data */
1411 1411 nmp->b_cont = mp->b_cont; /* use the data given */
1412 1412 freeb(mp);
1413 1413 mp = nmp;
1414 1414 } else {
1415 1415 /* need to format a DL_UNITDATA_REQ with LLC1 header inserted */
1416 1416 nmp = allocb(sizeof (struct llchdr)+sizeof (struct snaphdr),
1417 1417 BPRI_MED);
1418 1418 if (nmp == NULL)
1419 1419 return (DL_UNDELIVERABLE);
1420 1420 llchdr = (struct llchdr *)(nmp->b_rptr);
1421 1421 nmp->b_wptr += sizeof (struct llchdr);
1422 1422 llchdr->llc_dsap = llcp->llca_sap;
1423 1423 llchdr->llc_ssap = lld->llc_sap;
1424 1424 llchdr->llc_ctl = LLC_UI;
1425 1425
1426 1426 /*
1427 1427 * if we are using SNAP, insert the header here
1428 1428 */
1429 1429 if (lld->llc_flags & LLC_SNAP) {
1430 1430 bcopy(lld->llc_snap, nmp->b_wptr, 5);
1431 1431 nmp->b_wptr += 5;
1432 1432 }
1433 1433 nmp->b_cont = mp->b_cont;
1434 1434 mp->b_cont = nmp;
1435 1435 nmp = mp;
1436 1436 if (ismulticast(llcp->llca_addr)) {
1437 1437 if (bcmp(llcp->llca_addr,
1438 1438 macinfo->llcp_broadcast, ETHERADDRL) == 0)
1439 1439 xmt_type = 2;
1440 1440 else
1441 1441 xmt_type = 1;
1442 1442 }
1443 1443 }
1444 1444 if (canput(macinfo->llcp_queue)) {
1445 1445 lld->llc_stats->llcs_bytexmt += msgdsize(mp);
1446 1446 lld->llc_stats->llcs_pktxmt++;
1447 1447 switch (xmt_type) {
1448 1448 case 1:
1449 1449 macinfo->llcp_stats.llcs_multixmt++;
1450 1450 break;
1451 1451 case 2:
1452 1452 macinfo->llcp_stats.llcs_brdcstxmt++;
1453 1453 break;
1454 1454 }
1455 1455
1456 1456 putnext(macinfo->llcp_queue, mp);
1457 1457 return (LLCE_OK); /* this is almost correct, the result */
1458 1458 } else {
1459 1459 lld->llc_stats->llcs_nobuffer++;
1460 1460 }
1461 1461 if (nmp != NULL)
1462 1462 freemsg(nmp); /* free on failure */
1463 1463 return (LLCE_OK);
1464 1464 }
1465 1465
1466 1466 /*
1467 1467 * llc1_recv(macinfo, mp)
1468 1468 * called with an ethernet packet in a mblock; must decide
1469 1469 * whether packet is for us and which streams to queue it to. This routine is
1470 1470 * called with locally originated packets for loopback.
1471 1471 */
1472 1472 static void
1473 1473 llc1_recv(llc_mac_info_t *macinfo, mblk_t *mp)
1474 1474 {
1475 1475 struct ether_addr *addr;
1476 1476 llc1_t *lld;
1477 1477 mblk_t *nmp, *udmp;
1478 1478 int i, nmcast = 0, statcnt_normal = 0, statcnt_brdcst = 0;
1479 1479 int valid, msgsap;
1480 1480 struct llchdr *llchdr;
1481 1481
1482 1482 #ifdef LLC1_DEBUG
1483 1483 if (llc1_debug & LLCTRACE)
1484 1484 printf("llc1_recv(%x, %x)\n", mp, macinfo);
1485 1485 #endif
1486 1486
1487 1487 if (DB_TYPE(mp) == M_PROTO) {
1488 1488 dl_unitdata_ind_t *udata;
1489 1489
1490 1490 /* check to see if really LLC1 XXX */
1491 1491 /* also need to make sure to keep address info */
1492 1492 nmp = mp;
1493 1493 udata = (dl_unitdata_ind_t *)(nmp->b_rptr);
1494 1494 addr = (struct ether_addr *)(nmp->b_rptr +
1495 1495 udata->dl_dest_addr_offset);
1496 1496 llchdr = (struct llchdr *)(nmp->b_cont->b_rptr);
1497 1497 if (macinfo->llcp_type == DL_CSMACD) {
1498 1498 i = ((struct llcsaddr *)addr)->llca_ssap;
1499 1499 if (i < 60) {
1500 1500 valid = adjmsg(mp->b_cont, i - msgdsize(mp));
1501 1501 }
1502 1502 }
1503 1503 } else {
1504 1504 struct ether_header *hdr;
1505 1505
1506 1506 /* Note that raw mode currently assumes Ethernet */
1507 1507 nmp = NULL;
1508 1508 hdr = (struct ether_header *)mp->b_rptr;
1509 1509 addr = &hdr->ether_dhost;
1510 1510 llchdr = (struct llchdr *)(mp->b_rptr +
1511 1511 sizeof (struct ether_header));
1512 1512 i = (ushort_t)ntohs(hdr->ether_type);
1513 1513 if (i < 60) {
1514 1514 (void) adjmsg(mp, i + sizeof (struct ether_header) -
1515 1515 msgdsize(mp));
1516 1516 }
1517 1517 }
1518 1518 udmp = NULL;
1519 1519
1520 1520 msgsap = llchdr->llc_dsap;
1521 1521
1522 1522 #ifdef LLC1_DEBUG
1523 1523 if (llc1_debug & LLCRECV) {
1524 1524 printf("llc1_recv: machdr=<%s>\n", ether_sprintf(addr));
1525 1525 }
1526 1526 #endif
1527 1527
1528 1528 if (llc1_broadcast(addr, macinfo)) {
1529 1529 valid = 2; /* 2 means valid but multicast */
1530 1530 statcnt_brdcst = 1;
1531 1531 } else {
1532 1532 valid = llc1_local(addr, macinfo);
1533 1533 statcnt_normal = msgdsize(mp);
1534 1534 }
1535 1535
1536 1536 /*
1537 1537 * Note that the NULL SAP is a special case. It is associated with
1538 1538 * the MAC layer and not the LLC layer so should be handled
1539 1539 * independently of any STREAM.
1540 1540 */
1541 1541 if (msgsap == LLC_NULL_SAP) {
1542 1542 /* only XID and TEST ever processed, UI is dropped */
1543 1543 if ((llchdr->llc_ctl & ~LLC_P) == LLC_XID)
1544 1544 mp = llc1_xid_reply(macinfo, mp, 0);
1545 1545 else if ((llchdr->llc_ctl & ~LLC_P) == LLC_TEST)
1546 1546 mp = llc1_test_reply(macinfo, mp, 0);
1547 1547 } else
1548 1548 for (lld = llc1_device_list.llc1_str_next;
1549 1549 lld != (llc1_t *)&llc1_device_list.llc1_str_next;
1550 1550 lld = lld->llc_next) {
1551 1551
1552 1552 /*
1553 1553 * is this a potentially usable SAP on the
1554 1554 * right MAC layer?
1555 1555 */
1556 1556 if (lld->llc_qptr == NULL ||
1557 1557 lld->llc_state != DL_IDLE ||
1558 1558 lld->llc_mac_info != macinfo) {
1559 1559 continue;
1560 1560 }
1561 1561 #ifdef LLC1_DEBUG
1562 1562 if (llc1_debug & LLCRECV)
1563 1563 printf(
1564 1564 "llc1_recv: type=%d, sap=%x, pkt-dsap=%x\n",
1565 1565 lld->llc_type, lld->llc_sap,
1566 1566 msgsap);
1567 1567 #endif
1568 1568 if (!valid && ismulticast(addr->ether_addr_octet) &&
1569 1569 lld->llc_multicnt > 0 &&
1570 1570 llc1_multicast(addr, lld)) {
1571 1571 valid |= 4;
1572 1572 } else if (lld->llc_flags & LLC_PROM)
1573 1573 /* promiscuous mode */
1574 1574 valid = 1;
1575 1575
1576 1576 if ((lld->llc_flags & LLC_PROM) ||
1577 1577 /* promiscuous streams */
1578 1578 (valid &&
1579 1579 (lld->llc_sap == msgsap ||
1580 1580 msgsap == LLC_GLOBAL_SAP))) {
1581 1581 /* sap matches */
1582 1582 if (msgsap == LLC_SNAP_SAP &&
1583 1583 (lld->llc_flags & (LLC_SNAP|LLC_PROM)) ==
1584 1584 LLC_SNAP) {
1585 1585 if (!llc1_snap_match(lld,
1586 1586 (struct snaphdr *)(llchdr+1)))
1587 1587 continue;
1588 1588 }
1589 1589 if (!canputnext(RD(lld->llc_qptr))) {
1590 1590 #ifdef LLC1_DEBUG
1591 1591 if (llc1_debug & LLCRECV)
1592 1592 printf(
1593 1593 "llc1_recv: canput failed\n");
1594 1594 #endif
1595 1595 lld->llc_stats->llcs_blocked++;
1596 1596 continue;
1597 1597 }
1598 1598 /* check for Novell special handling */
1599 1599 if (msgsap == LLC_GLOBAL_SAP &&
1600 1600 lld->llc_sap == LLC_NOVELL_SAP &&
1601 1601 llchdr->llc_ssap == LLC_GLOBAL_SAP) {
1602 1602
1603 1603 /* A Novell packet */
1604 1604 nmp = llc1_form_udata(lld, macinfo, mp);
1605 1605 continue;
1606 1606 }
1607 1607 switch (llchdr->llc_ctl) {
1608 1608 case LLC_UI:
1609 1609 /*
1610 1610 * this is an Unnumbered Information
1611 1611 * packet so form a DL_UNITDATA_IND and
1612 1612 * send to user
1613 1613 */
1614 1614 nmp = llc1_form_udata(lld, macinfo, mp);
1615 1615 break;
1616 1616
1617 1617 case LLC_XID:
1618 1618 case LLC_XID | LLC_P:
1619 1619 /*
1620 1620 * this is either an XID request or
1621 1621 * response. We either handle directly
1622 1622 * (if user hasn't requested to handle
1623 1623 * itself) or send to user. We also
1624 1624 * must check if a response if user
1625 1625 * handled so that we can send correct
1626 1626 * message form
1627 1627 */
1628 1628 if (lld->llc_flags & LLC1_AUTO_XID) {
1629 1629 nmp = llc1_xid_reply(macinfo,
1630 1630 mp, lld->llc_sap);
1631 1631 } else {
1632 1632 /*
1633 1633 * hand to the user for
1634 1634 * handling. if this is a
1635 1635 * "request", generate a
1636 1636 * DL_XID_IND. If it is a
1637 1637 * "response" to one of our
1638 1638 * requests, generate a
1639 1639 * DL_XID_CON.
1640 1640 */
1641 1641 nmp = llc1_xid_ind_con(lld,
1642 1642 macinfo, mp);
1643 1643 }
1644 1644 macinfo->llcp_stats.llcs_xidrcv++;
1645 1645 break;
1646 1646
1647 1647 case LLC_TEST:
1648 1648 case LLC_TEST | LLC_P:
1649 1649 /*
1650 1650 * this is either a TEST request or
1651 1651 * response. We either handle
1652 1652 * directly (if user hasn't
1653 1653 * requested to handle itself)
1654 1654 * or send to user. We also
1655 1655 * must check if a response if
1656 1656 * user handled so that we can
1657 1657 * send correct message form
1658 1658 */
1659 1659 if (lld->llc_flags & LLC1_AUTO_TEST) {
1660 1660 nmp = llc1_test_reply(macinfo,
1661 1661 mp, lld->llc_sap);
1662 1662 } else {
1663 1663 /*
1664 1664 * hand to the user for
1665 1665 * handling. if this is
1666 1666 * a "request",
1667 1667 * generate a
1668 1668 * DL_TEST_IND. If it
1669 1669 * is a "response" to
1670 1670 * one of our requests,
1671 1671 * generate a
1672 1672 * DL_TEST_CON.
1673 1673 */
1674 1674 nmp = llc1_test_ind_con(lld,
1675 1675 macinfo, mp);
1676 1676 }
1677 1677 macinfo->llcp_stats.llcs_testrcv++;
1678 1678 break;
1679 1679 default:
1680 1680 nmp = mp;
1681 1681 break;
1682 1682 }
1683 1683 mp = nmp;
1684 1684 }
1685 1685 }
1686 1686 if (mp != NULL)
1687 1687 freemsg(mp);
1688 1688 if (udmp != NULL)
1689 1689 freeb(udmp);
1690 1690 if (nmcast > 0)
1691 1691 macinfo->llcp_stats.llcs_multircv++;
1692 1692 if (statcnt_brdcst) {
1693 1693 macinfo->llcp_stats.llcs_brdcstrcv++;
1694 1694 }
1695 1695 if (statcnt_normal) {
1696 1696 macinfo->llcp_stats.llcs_bytercv += statcnt_normal;
1697 1697 macinfo->llcp_stats.llcs_pktrcv++;
1698 1698 }
1699 1699 }
1700 1700
1701 1701 /*
1702 1702 * llc1_local - check to see if the message is addressed to this system by
1703 1703 * comparing with the board's address.
1704 1704 */
1705 1705 static int
1706 1706 llc1_local(struct ether_addr *addr, llc_mac_info_t *macinfo)
1707 1707 {
1708 1708 return (bcmp(addr->ether_addr_octet, macinfo->llcp_macaddr,
1709 1709 macinfo->llcp_addrlen) == 0);
1710 1710 }
1711 1711
1712 1712 /*
1713 1713 * llc1_broadcast - check to see if a broadcast address is the destination of
1714 1714 * this received packet
1715 1715 */
1716 1716 static int
1717 1717 llc1_broadcast(struct ether_addr *addr, llc_mac_info_t *macinfo)
1718 1718 {
1719 1719 return (bcmp(addr->ether_addr_octet, macinfo->llcp_broadcast,
1720 1720 macinfo->llcp_addrlen) == 0);
1721 1721 }
1722 1722
1723 1723 /*
1724 1724 * llc1attach(q, mp) DLPI DL_ATTACH_REQ this attaches the stream to a PPA
1725 1725 */
1726 1726 static int
1727 1727 llc1attach(queue_t *q, mblk_t *mp)
1728 1728 {
1729 1729 dl_attach_req_t *at;
1730 1730 llc_mac_info_t *mac;
1731 1731 llc1_t *llc = (llc1_t *)q->q_ptr;
1732 1732
1733 1733 at = (dl_attach_req_t *)mp->b_rptr;
1734 1734
1735 1735 if (llc->llc_state != DL_UNATTACHED) {
1736 1736 return (DL_OUTSTATE);
1737 1737 }
1738 1738 llc->llc_state = DL_ATTACH_PENDING;
1739 1739
1740 1740 if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
1741 1741 /*
1742 1742 * someone else has a lock held. To avoid deadlock,
1743 1743 * release the READER lock and block on a WRITER
1744 1744 * lock. This will let things continue safely.
1745 1745 */
1746 1746 rw_exit(&llc1_device_list.llc1_rwlock);
1747 1747 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
1748 1748 }
1749 1749
1750 1750 for (mac = llc1_device_list.llc1_mac_next;
1751 1751 mac != (llc_mac_info_t *)(&llc1_device_list.llc1_mac_next);
1752 1752 mac = mac->llcp_next) {
1753 1753 ASSERT(mac);
1754 1754 if (mac->llcp_ppa == at->dl_ppa && mac->llcp_lqtop == q) {
1755 1755 /*
1756 1756 * We may have found the correct PPA
1757 1757 * check to see if linking has finished.
1758 1758 * Use explicit flag checks for incorrect
1759 1759 * state, and use negative values for "tenative"
1760 1760 * llcp_ppas, to avoid erroneous attaches.
1761 1761 */
1762 1762 if (mac->llcp_flags &
1763 1763 (LLC1_LINKED|LLC1_DEF_PPA)) {
1764 1764 return (DL_INITFAILED);
1765 1765 } else if (!(mac->llcp_flags & LLC1_AVAILABLE)) {
1766 1766 return (DL_BADPPA);
1767 1767 }
1768 1768
1769 1769 /* this links us to the PPA */
1770 1770 mac->llcp_nstreams++;
1771 1771 llc->llc_mac_info = mac;
1772 1772
1773 1773 llc->llc_state = DL_UNBOUND; /* now ready for action */
1774 1774 llc->llc_stats = &mac->llcp_stats;
1775 1775 dlokack(q, mp, DL_ATTACH_REQ);
1776 1776
1777 1777 return (LLCE_OK);
1778 1778 }
1779 1779 }
1780 1780 llc->llc_state = DL_UNATTACHED;
1781 1781 return (DL_BADPPA);
1782 1782 }
1783 1783
1784 1784 /*
1785 1785 * llc1unattach(q, mp) DLPI DL_DETACH_REQ detaches the mac layer from the
1786 1786 * stream
1787 1787 */
1788 1788 static int
1789 1789 llc1unattach(queue_t *q, mblk_t *mp)
1790 1790 {
1791 1791 llc1_t *llc = (llc1_t *)q->q_ptr;
1792 1792 int state;
1793 1793 int i;
1794 1794
1795 1795 state = llc->llc_state;
1796 1796 if (state != DL_UNBOUND)
1797 1797 return (DL_OUTSTATE);
1798 1798
1799 1799 /* can now detach from the PPA */
1800 1800 llc->llc_state = DL_DETACH_PENDING;
1801 1801
1802 1802 if (rw_tryupgrade(&llc1_device_list.llc1_rwlock) == 0) {
1803 1803 /*
1804 1804 * someone else has a lock held. To avoid deadlock,
1805 1805 * release the READER lock and block on a WRITER
1806 1806 * lock. This will let things continue safely.
1807 1807 */
1808 1808 rw_exit(&llc1_device_list.llc1_rwlock);
1809 1809 rw_enter(&llc1_device_list.llc1_rwlock, RW_WRITER);
1810 1810 }
1811 1811
1812 1812 if (llc->llc_mcast) {
1813 1813 for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1814 1814 llc_mcast_t *mcast;
1815 1815
1816 1816 if ((mcast = llc->llc_mcast[i]) != NULL) {
1817 1817 /* disable from stream and possibly lower */
1818 1818 llc1_send_disable_multi(llc->llc_mac_info,
1819 1819 mcast);
1820 1820 llc->llc_mcast[i] = NULL;
1821 1821 }
1822 1822 }
1823 1823 kmem_free(llc->llc_mcast,
1824 1824 sizeof (llc_mcast_t *) * llc->llc_multicnt);
1825 1825 llc->llc_mcast = NULL;
1826 1826 }
1827 1827 if (llc->llc_mac_info)
1828 1828 llc->llc_mac_info->llcp_nstreams--;
1829 1829 llc->llc_sap = 0;
1830 1830 llc->llc_state = DL_UNATTACHED;
1831 1831 if (mp) {
1832 1832 dlokack(q, mp, DL_DETACH_REQ);
1833 1833 }
1834 1834 return (LLCE_OK);
1835 1835 }
1836 1836
1837 1837 /*
1838 1838 * llc1_enable_multi enables multicast address on the stream if the mac layer
1839 1839 * isn't enabled for this address, enable at that level as well.
1840 1840 */
1841 1841 static int
1842 1842 llc1_enable_multi(queue_t *q, mblk_t *mp)
1843 1843 {
1844 1844 llc1_t *llc;
1845 1845 llc_mac_info_t *macinfo;
1846 1846 struct ether_addr *maddr;
1847 1847 dl_enabmulti_req_t *multi;
1848 1848 llc_mcast_t *mcast;
1849 1849 int status = DL_BADADDR;
1850 1850 int i;
1851 1851
1852 1852 #if defined(LLC1_DEBUG)
1853 1853 if (llc1_debug & LLCPROT) {
1854 1854 printf("llc1_enable_multi(%x, %x)\n", q, mp);
1855 1855 }
1856 1856 #endif
1857 1857
1858 1858 llc = (llc1_t *)q->q_ptr;
1859 1859
1860 1860 if (llc->llc_state == DL_UNATTACHED)
1861 1861 return (DL_OUTSTATE);
1862 1862
1863 1863 macinfo = llc->llc_mac_info;
1864 1864 multi = (dl_enabmulti_req_t *)mp->b_rptr;
1865 1865 maddr = (struct ether_addr *)(mp->b_rptr + multi->dl_addr_offset);
1866 1866
1867 1867 /*
1868 1868 * check to see if this multicast address is valid if it is, then
1869 1869 * check to see if it is already in the per stream table and the per
1870 1870 * device table if it is already in the per stream table, if it isn't
1871 1871 * in the per device, add it. If it is, just set a pointer. If it
1872 1872 * isn't, allocate what's necessary.
1873 1873 */
1874 1874
1875 1875 if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) &&
1876 1876 MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) &&
1877 1877 multi->dl_addr_length == macinfo->llcp_addrlen &&
1878 1878 ismulticast(maddr->ether_addr_octet)) {
1879 1879 /* request appears to be valid */
1880 1880 /* does this address appear in current table? */
1881 1881 if (llc->llc_mcast == NULL) {
1882 1882 /* no mcast addresses -- allocate table */
1883 1883 llc->llc_mcast =
1884 1884 GETSTRUCT(llc_mcast_t *,
1885 1885 llc1_device_list.llc1_multisize);
1886 1886 if (llc->llc_mcast == NULL)
1887 1887 return (DL_SYSERR);
1888 1888 llc->llc_multicnt = llc1_device_list.llc1_multisize;
1889 1889 } else {
1890 1890 for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1891 1891 if (llc->llc_mcast[i] &&
1892 1892 bcmp(llc->llc_mcast[i]->llcm_addr,
1893 1893 maddr->ether_addr_octet, ETHERADDRL)) {
1894 1894 /* this is a match -- just succeed */
1895 1895 dlokack(q, mp, DL_ENABMULTI_REQ);
1896 1896 return (LLCE_OK);
1897 1897 }
1898 1898 }
1899 1899 }
1900 1900 /*
1901 1901 * there wasn't one so check to see if the mac layer has one
1902 1902 */
1903 1903 if (macinfo->llcp_mcast == NULL) {
1904 1904 macinfo->llcp_mcast =
1905 1905 GETSTRUCT(llc_mcast_t,
1906 1906 llc1_device_list.llc1_multisize);
1907 1907 if (macinfo->llcp_mcast == NULL)
1908 1908 return (DL_SYSERR);
1909 1909 }
1910 1910 for (mcast = NULL, i = 0;
1911 1911 i < llc1_device_list.llc1_multisize; i++) {
1912 1912 if (macinfo->llcp_mcast[i].llcm_refcnt &&
1913 1913 bcmp(macinfo->llcp_mcast[i].llcm_addr,
1914 1914 maddr->ether_addr_octet, ETHERADDRL) == 0) {
1915 1915 mcast = &macinfo->llcp_mcast[i];
1916 1916 break;
1917 1917 }
1918 1918 }
1919 1919 if (mcast == NULL) {
1920 1920 mblk_t *nmp;
1921 1921
1922 1922 nmp = dupmsg(mp);
1923 1923 if (nmp) {
1924 1924 nmp->b_cont = NULL;
1925 1925 DB_TYPE(nmp) = M_PROTO;
1926 1926 putnext(WR(macinfo->llcp_queue), nmp);
1927 1927 }
1928 1928 /* find an empty slot to fill in */
1929 1929 for (mcast = macinfo->llcp_mcast, i = 0;
1930 1930 i < llc1_device_list.llc1_multisize; i++, mcast++) {
1931 1931 if (mcast->llcm_refcnt == 0) {
1932 1932 bcopy(maddr->ether_addr_octet,
1933 1933 mcast->llcm_addr, ETHERADDRL);
1934 1934 break;
1935 1935 }
1936 1936 }
1937 1937 }
1938 1938 if (mcast != NULL) {
1939 1939 for (i = 0; i < llc1_device_list.llc1_multisize; i++) {
1940 1940 if (llc->llc_mcast[i] == NULL) {
1941 1941 llc->llc_mcast[i] = mcast;
1942 1942 mcast->llcm_refcnt++;
1943 1943 dlokack(q, mp, DL_ENABMULTI_REQ);
1944 1944 return (LLCE_OK);
1945 1945 }
1946 1946 }
1947 1947 }
1948 1948 status = DL_TOOMANY;
1949 1949 }
1950 1950 return (status);
1951 1951 }
1952 1952
1953 1953 /*
1954 1954 * llc1_disable_multi disable the multicast address on the stream if last
1955 1955 * reference for the mac layer, disable there as well
1956 1956 */
1957 1957 static int
1958 1958 llc1_disable_multi(queue_t *q, mblk_t *mp)
1959 1959 {
1960 1960 llc1_t *llc;
1961 1961 llc_mac_info_t *macinfo;
1962 1962 struct ether_addr *maddr;
1963 1963 dl_enabmulti_req_t *multi;
1964 1964 int status = DL_BADADDR, i;
1965 1965 llc_mcast_t *mcast;
1966 1966
1967 1967 #if defined(LLC1_DEBUG)
1968 1968 if (llc1_debug & LLCPROT) {
1969 1969 printf("llc1_enable_multi(%x, %x)\n", q, mp);
1970 1970 }
1971 1971 #endif
1972 1972
1973 1973 llc = (llc1_t *)q->q_ptr;
1974 1974
1975 1975 if (llc->llc_state == DL_UNATTACHED)
1976 1976 return (DL_OUTSTATE);
1977 1977
1978 1978 macinfo = llc->llc_mac_info;
1979 1979 multi = (dl_enabmulti_req_t *)mp->b_rptr;
1980 1980 maddr = (struct ether_addr *)(multi + 1);
1981 1981
1982 1982 if (MBLKL(mp) >= sizeof (dl_enabmulti_req_t) &&
1983 1983 MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length)) {
1984 1984 /* request appears to be valid */
1985 1985 /* does this address appear in current table? */
1986 1986 if (llc->llc_mcast != NULL) {
1987 1987 for (i = 0; i < llc->llc_multicnt; i++)
1988 1988 if (((mcast = llc->llc_mcast[i]) != NULL) &&
1989 1989 mcast->llcm_refcnt &&
1990 1990 bcmp(mcast->llcm_addr,
1991 1991 maddr->ether_addr_octet, ETHERADDRL) == 0) {
1992 1992 llc1_send_disable_multi(macinfo,
1993 1993 mcast);
1994 1994 llc->llc_mcast[i] = NULL;
1995 1995 dlokack(q, mp, DL_DISABMULTI_REQ);
1996 1996 return (LLCE_OK);
1997 1997 }
1998 1998 status = DL_NOTENAB;
1999 1999 }
2000 2000 }
2001 2001 return (status);
2002 2002 }
2003 2003
2004 2004 /*
2005 2005 * llc1_send_disable_multi(llc, macinfo, mcast) this function is used to
2006 2006 * disable a multicast address if the reference count goes to zero. The
2007 2007 * disable request will then be forwarded to the lower stream.
2008 2008 */
2009 2009 static void
2010 2010 llc1_send_disable_multi(llc_mac_info_t *macinfo, llc_mcast_t *mcast)
2011 2011 {
2012 2012 mblk_t *mp;
2013 2013 dl_disabmulti_req_t *dis;
2014 2014
2015 2015 if (mcast == NULL) {
2016 2016 return;
2017 2017 }
2018 2018 if (macinfo == NULL || macinfo->llcp_queue == NULL) {
2019 2019 return;
2020 2020 }
2021 2021 if (--mcast->llcm_refcnt > 0)
2022 2022 return;
2023 2023
2024 2024 mp = allocb(sizeof (dl_disabmulti_req_t) + ETHERADDRL, BPRI_MED);
2025 2025 if (mp) {
2026 2026 dis = (dl_disabmulti_req_t *)mp->b_rptr;
2027 2027 mp->b_wptr =
2028 2028 mp->b_rptr + sizeof (dl_disabmulti_req_t) + ETHERADDRL;
2029 2029 dis->dl_primitive = DL_DISABMULTI_REQ;
2030 2030 dis->dl_addr_offset = sizeof (dl_disabmulti_req_t);
2031 2031 dis->dl_addr_length = ETHERADDRL;
2032 2032 bcopy(mcast->llcm_addr,
2033 2033 (mp->b_rptr + sizeof (dl_disabmulti_req_t)), ETHERADDRL);
2034 2034 DB_TYPE(mp) = M_PROTO;
2035 2035 putnext(WR(macinfo->llcp_queue), mp);
2036 2036 }
2037 2037 }
2038 2038
2039 2039 /*
2040 2040 * llc1_findminor(device) searches the per device class list of STREAMS for
2041 2041 * the first minor number not used. Note that we currently don't allocate
2042 2042 * minor 0.
2043 2043 */
2044 2044
2045 2045 static minor_t
2046 2046 llc1_findminor(llc1dev_t *device)
2047 2047 {
2048 2048 llc1_t *next;
2049 2049 minor_t minor;
2050 2050
2051 2051 ASSERT(device != NULL);
2052 2052 for (minor = 1; minor <= MAXMIN32; minor++) {
2053 2053 for (next = device->llc1_str_next;
2054 2054 next != NULL && next != (llc1_t *)&device->llc1_str_next;
2055 2055 next = next->llc_next) {
2056 2056 if (minor == next->llc_minor)
2057 2057 goto nextminor;
2058 2058 }
2059 2059 return (minor);
2060 2060 nextminor:
2061 2061 /* don't need to do anything */
2062 2062 ;
2063 2063 }
2064 2064 /*NOTREACHED*/
2065 2065 return (0);
2066 2066 }
2067 2067
2068 2068 /*
2069 2069 * llc1_req_info(q) simply construct a DL_INFO_REQ to be sent to the lower
2070 2070 * stream this is used to populate the macinfo structure.
2071 2071 */
2072 2072 static int
2073 2073 llc1_req_info(queue_t *q)
2074 2074 {
2075 2075 dl_info_req_t *info;
2076 2076 mblk_t *mp;
2077 2077
2078 2078 mp = allocb(DL_INFO_REQ_SIZE, BPRI_MED);
2079 2079 if (mp == NULL)
2080 2080 return (-1);
2081 2081 DB_TYPE(mp) = M_PCPROTO;
2082 2082 info = (dl_info_req_t *)mp->b_rptr;
2083 2083 mp->b_wptr = mp->b_rptr + DL_INFO_REQ_SIZE;
2084 2084 info->dl_primitive = DL_INFO_REQ;
2085 2085 putnext(q, mp);
2086 2086 return (0);
2087 2087 }
2088 2088
2089 2089 /*
2090 2090 * llc1_req_raw(macinfo) request that the lower stream enter DLIOCRAW mode
2091 2091 */
2092 2092 static void
2093 2093 llc1_req_raw(llc_mac_info_t *macinfo)
2094 2094 {
2095 2095 mblk_t *mp;
2096 2096
2097 2097 mp = mkiocb(DLIOCRAW);
2098 2098 if (mp == NULL)
2099 2099 return;
2100 2100
2101 2101 macinfo->llcp_iocid = ((struct iocblk *)mp->b_rptr)->ioc_id;
2102 2102
2103 2103 putnext(macinfo->llcp_queue, mp);
2104 2104 macinfo->llcp_flags |= LLC1_RAW_WAIT;
2105 2105 }
2106 2106
2107 2107 /*
2108 2108 * llc1_send_bindreq
2109 2109 * if lower stream isn't bound, bind it to something appropriate
2110 2110 */
2111 2111 static void
2112 2112 llc1_send_bindreq(llc_mac_info_t *macinfo)
2113 2113 {
2114 2114 mblk_t *mp;
2115 2115 dl_bind_req_t *bind;
2116 2116
2117 2117 if (macinfo->llcp_sap >= 0xFF) {
2118 2118 /* have to quite sometime if the world is failing */
2119 2119 macinfo->llcp_sap &= ~(LLC1_BINDING|LLC1_AVAILABLE);
2120 2120 return;
2121 2121 }
2122 2122
2123 2123 mp = allocb(sizeof (dl_bind_req_t), BPRI_MED);
2124 2124 if (mp == NULL)
2125 2125 return;
2126 2126
2127 2127 bind = (dl_bind_req_t *)mp->b_rptr;
2128 2128 mp->b_wptr = mp->b_rptr + sizeof (dl_bind_req_t);
2129 2129
2130 2130 bind->dl_primitive = DL_BIND_REQ;
2131 2131 bind->dl_sap = macinfo->llcp_sap += 2; /* starts at 2, inc by 2 */
2132 2132 macinfo->llcp_flags |= LLC1_BINDING;
2133 2133 bind->dl_max_conind = 0;
2134 2134 bind->dl_service_mode = DL_CLDLS;
2135 2135 bind->dl_conn_mgmt = 0;
2136 2136 bind->dl_xidtest_flg = 0;
2137 2137 putnext(macinfo->llcp_queue, mp);
2138 2138 }
2139 2139
2140 2140 /*
2141 2141 * llc1_form_udata(lld, macinfo, mp) format a DL_UNITDATA_IND message to be
2142 2142 * sent to the user
2143 2143 */
2144 2144 static mblk_t *
2145 2145 llc1_form_udata(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2146 2146 {
2147 2147 mblk_t *udmp, *nmp;
2148 2148 dl_unitdata_ind_t *udata;
2149 2149 struct ether_header *hdr;
2150 2150 struct llchdr *llchdr;
2151 2151 struct snaphdr *snap;
2152 2152
2153 2153 if (macinfo->llcp_flags & LLC1_USING_RAW) {
2154 2154 hdr = (struct ether_header *)mp->b_rptr;
2155 2155 llchdr = (struct llchdr *)(hdr + 1);
2156 2156
2157 2157 /* allocate the DL_UNITDATA_IND M_PROTO header */
2158 2158 udmp = allocb(sizeof (dl_unitdata_ind_t) +
2159 2159 2 * (macinfo->llcp_addrlen + 5), BPRI_MED);
2160 2160 if (udmp == NULL) {
2161 2161 /* might as well discard since we can't go further */
2162 2162 freemsg(mp);
2163 2163 return (NULL);
2164 2164 }
2165 2165 udata = (dl_unitdata_ind_t *)udmp->b_rptr;
2166 2166 udmp->b_wptr += sizeof (dl_unitdata_ind_t);
2167 2167
2168 2168 nmp = dupmsg(mp); /* make a copy for future streams */
2169 2169 if (lld->llc_sap != LLC_NOVELL_SAP)
2170 2170 mp->b_rptr += sizeof (struct ether_header) +
2171 2171 sizeof (struct llchdr);
2172 2172 else
2173 2173 mp->b_rptr += sizeof (struct ether_header);
2174 2174
2175 2175 if (lld->llc_flags & LLC_SNAP) {
2176 2176 mp->b_rptr += sizeof (struct snaphdr);
2177 2177 snap = (struct snaphdr *)(llchdr + 1);
2178 2178 }
2179 2179
2180 2180 /*
2181 2181 * now setup the DL_UNITDATA_IND header
2182 2182 */
2183 2183 DB_TYPE(udmp) = M_PROTO;
2184 2184 udata->dl_primitive = DL_UNITDATA_IND;
2185 2185 udata->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2186 2186 bcopy(hdr->ether_dhost.ether_addr_octet,
2187 2187 LLCADDR(udata, udata->dl_dest_addr_offset)->llca_addr,
2188 2188 macinfo->llcp_addrlen);
2189 2189
2190 2190 if (lld->llc_flags & LLC_SNAP) {
2191 2191 udata->dl_dest_addr_length = macinfo->llcp_addrlen + 2;
2192 2192 LLCSADDR(udata, udata->dl_dest_addr_offset)->llca_ssap =
2193 2193 ntohs(*(ushort_t *)snap->snap_type);
2194 2194 } else {
2195 2195 udata->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2196 2196 LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap =
2197 2197 llchdr->llc_dsap;
2198 2198 }
2199 2199 udmp->b_wptr += udata->dl_dest_addr_length;
2200 2200 udata->dl_src_addr_offset = udata->dl_dest_addr_length +
2201 2201 udata->dl_dest_addr_offset;
2202 2202 bcopy(hdr->ether_shost.ether_addr_octet,
2203 2203 LLCADDR(udata, udata->dl_src_addr_offset)->llca_addr,
2204 2204 macinfo->llcp_addrlen);
2205 2205 if (lld->llc_flags & LLC_SNAP) {
2206 2206 udata->dl_src_addr_length = macinfo->llcp_addrlen + 2;
2207 2207 LLCSADDR(udata, udata->dl_src_addr_offset)->llca_ssap =
2208 2208 ntohs(*(ushort_t *)snap->snap_type);
2209 2209 } else {
2210 2210 udata->dl_src_addr_length = macinfo->llcp_addrlen + 1;
2211 2211 LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap =
2212 2212 llchdr->llc_ssap;
2213 2213 }
2214 2214 udata->dl_group_address = hdr->ether_dhost.ether_addr_octet[0] &
2215 2215 0x1;
2216 2216 udmp->b_wptr += udata->dl_src_addr_length;
2217 2217 udmp->b_cont = mp;
2218 2218 } else {
2219 2219 dl_unitdata_ind_t *ud2;
2220 2220 if (mp->b_cont == NULL) {
2221 2221 return (mp); /* we can't do anything */
2222 2222 }
2223 2223 /* if we end up here, we only want to patch the existing M_PROTO */
2224 2224 nmp = dupmsg(mp); /* make a copy for future streams */
2225 2225 udata = (dl_unitdata_ind_t *)(mp->b_rptr);
2226 2226 udmp = allocb(MBLKL(mp) + 4, BPRI_MED);
2227 2227 bcopy(mp->b_rptr, udmp->b_rptr, sizeof (dl_unitdata_ind_t));
2228 2228 ud2 = (dl_unitdata_ind_t *)(udmp->b_rptr);
2229 2229 udmp->b_wptr += sizeof (dl_unitdata_ind_t);
2230 2230 bcopy((caddr_t)mp->b_rptr + udata->dl_dest_addr_offset,
2231 2231 udmp->b_wptr, macinfo->llcp_addrlen);
2232 2232 ud2->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2233 2233 ud2->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2234 2234 udmp->b_wptr += ud2->dl_dest_addr_length;
2235 2235 bcopy((caddr_t)udmp->b_rptr + udata->dl_src_addr_offset,
2236 2236 udmp->b_wptr, macinfo->llcp_addrlen);
2237 2237 ud2->dl_src_addr_length = ud2->dl_dest_addr_length;
2238 2238 udmp->b_wptr += ud2->dl_src_addr_length;
2239 2239 udmp->b_cont = mp->b_cont;
2240 2240 if (lld->llc_sap != LLC_NOVELL_SAP)
2241 2241 mp->b_cont->b_rptr += sizeof (struct llchdr);
2242 2242 freeb(mp);
2243 2243
2244 2244 DB_TYPE(udmp) = M_PROTO;
2245 2245 udata = (dl_unitdata_ind_t *)(mp->b_rptr);
2246 2246 llchdr = (struct llchdr *)(mp->b_cont->b_rptr);
2247 2247 LLCADDR(udata, udata->dl_dest_addr_offset)->llca_sap =
2248 2248 llchdr->llc_dsap;
2249 2249 LLCADDR(udata, udata->dl_src_addr_offset)->llca_sap =
2250 2250 llchdr->llc_ssap;
2251 2251 }
2252 2252 #ifdef LLC1_DEBUG
2253 2253 if (llc1_debug & LLCRECV)
2254 2254 printf("llc1_recv: queued message to %x (%d)\n",
2255 2255 lld->llc_qptr, lld->llc_minor);
2256 2256 #endif
2257 2257 /* enqueue for the service routine to process */
2258 2258 putnext(RD(lld->llc_qptr), udmp);
2259 2259 mp = nmp;
2260 2260 return (mp);
2261 2261 }
2262 2262
2263 2263 /*
2264 2264 * llc1_xid_reply(macinfo, mp) automatic reply to an XID command
2265 2265 */
2266 2266 static mblk_t *
2267 2267 llc1_xid_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
2268 2268 {
2269 2269 mblk_t *nmp, *rmp;
2270 2270 struct ether_header *hdr, *msgether;
2271 2271 struct llchdr *llchdr;
2272 2272 struct llchdr *msgllc;
2273 2273 struct llchdr_xid *xid;
2274 2274
2275 2275 if (DB_TYPE(mp) == M_DATA) {
2276 2276 hdr = (struct ether_header *)mp->b_rptr;
2277 2277 llchdr = (struct llchdr *)(hdr + 1);
2278 2278 } else {
2279 2279 if (mp->b_cont == NULL)
2280 2280 return (mp);
2281 2281 llchdr = (struct llchdr *)(mp->b_cont->b_rptr);
2282 2282 }
2283 2283
2284 2284 /* we only want to respond to commands to avoid response loops */
2285 2285 if (llchdr->llc_ssap & LLC_RESPONSE)
2286 2286 return (mp);
2287 2287
2288 2288 nmp = allocb(msgdsize(mp) + LLC_XID_INFO_SIZE, BPRI_MED);
2289 2289 if (nmp == NULL) {
2290 2290 return (mp);
2291 2291 }
2292 2292
2293 2293 /*
2294 2294 * now construct the XID reply frame
2295 2295 */
2296 2296 if (DB_TYPE(mp) == M_DATA) {
2297 2297 msgether = (struct ether_header *)nmp->b_rptr;
2298 2298 nmp->b_wptr += sizeof (struct ether_header);
2299 2299 bcopy(hdr->ether_shost.ether_addr_octet,
2300 2300 msgether->ether_dhost.ether_addr_octet,
2301 2301 macinfo->llcp_addrlen);
2302 2302 bcopy(macinfo->llcp_macaddr,
2303 2303 msgether->ether_shost.ether_addr_octet,
2304 2304 macinfo->llcp_addrlen);
2305 2305 msgether->ether_type = htons(sizeof (struct llchdr_xid) +
2306 2306 sizeof (struct llchdr));
2307 2307 rmp = nmp;
2308 2308 } else {
2309 2309 dl_unitdata_req_t *ud;
2310 2310 dl_unitdata_ind_t *rud;
2311 2311 rud = (dl_unitdata_ind_t *)mp->b_rptr;
2312 2312
2313 2313 rmp = allocb(sizeof (dl_unitdata_req_t) +
2314 2314 macinfo->llcp_addrlen + 5, BPRI_MED);
2315 2315 if (rmp == NULL)
2316 2316 return (mp);
2317 2317
2318 2318 DB_TYPE(rmp) = M_PROTO;
2319 2319 bzero(rmp->b_rptr, sizeof (dl_unitdata_req_t));
2320 2320 ud = (dl_unitdata_req_t *)rmp->b_rptr;
2321 2321 ud->dl_primitive = DL_UNITDATA_REQ;
2322 2322 ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
2323 2323 ud->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2324 2324
2325 2325 rmp->b_wptr += sizeof (dl_unitdata_req_t);
2326 2326 bcopy(LLCADDR(mp->b_rptr, rud->dl_src_addr_offset),
2327 2327 LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset),
2328 2328 macinfo->llcp_addrlen);
2329 2329 LLCADDR(rmp->b_rptr, ud->dl_dest_addr_offset)->llca_sap =
2330 2330 LLCADDR(mp->b_rptr, rud->dl_src_addr_offset)->llca_sap;
2331 2331 rmp->b_wptr += sizeof (struct llcaddr);
2332 2332 rmp->b_cont = nmp;
2333 2333 }
2334 2334
2335 2335 msgllc = (struct llchdr *)nmp->b_wptr;
2336 2336 xid = (struct llchdr_xid *)(msgllc + 1);
2337 2337 nmp->b_wptr += sizeof (struct llchdr);
2338 2338
2339 2339 msgllc->llc_dsap = llchdr->llc_ssap;
2340 2340
2341 2341 /* mark it a response */
2342 2342 msgllc->llc_ssap = sap | LLC_RESPONSE;
2343 2343
2344 2344 msgllc->llc_ctl = llchdr->llc_ctl;
2345 2345 xid->llcx_format = LLC_XID_FMTID;
2346 2346 xid->llcx_class = LLC_XID_TYPE_1;
2347 2347 xid->llcx_window = 0; /* we don't have connections yet */
2348 2348
2349 2349 nmp->b_wptr += sizeof (struct llchdr_xid);
2350 2350 macinfo->llcp_stats.llcs_xidxmt++;
2351 2351 putnext(WR(macinfo->llcp_queue), rmp);
2352 2352 return (mp);
2353 2353 }
2354 2354
2355 2355 /*
2356 2356 * llc1_xid_ind_con(lld, macinfo, mp) form a DL_XID_IND or DL_XID_CON message
2357 2357 * to send to the user since it was requested that the user process these
2358 2358 * messages
2359 2359 */
2360 2360 static mblk_t *
2361 2361 llc1_xid_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2362 2362 {
2363 2363 mblk_t *nmp;
2364 2364 dl_xid_ind_t *xid;
2365 2365 struct ether_header *hdr;
2366 2366 struct llchdr *llchdr;
2367 2367 int raw;
2368 2368
2369 2369 nmp = allocb(sizeof (dl_xid_ind_t) + 2 * (macinfo->llcp_addrlen + 1),
2370 2370 BPRI_MED);
2371 2371 if (nmp == NULL)
2372 2372 return (mp);
2373 2373
2374 2374 if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) {
2375 2375 hdr = (struct ether_header *)mp->b_rptr;
2376 2376 llchdr = (struct llchdr *)(hdr + 1);
2377 2377 } else {
2378 2378 if (mp->b_rptr == NULL)
2379 2379 return (mp);
2380 2380 llchdr = (struct llchdr *)mp->b_cont->b_rptr;
2381 2381 }
2382 2382
2383 2383 xid = (dl_xid_ind_t *)nmp->b_rptr;
2384 2384 xid->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0;
2385 2385 xid->dl_dest_addr_offset = sizeof (dl_xid_ind_t);
2386 2386 xid->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2387 2387
2388 2388 if (raw) {
2389 2389 bcopy(hdr->ether_dhost.ether_addr_octet,
2390 2390 (nmp->b_rptr + xid->dl_dest_addr_offset),
2391 2391 xid->dl_dest_addr_length);
2392 2392 } else {
2393 2393 dl_unitdata_ind_t *ind;
2394 2394 ind = (dl_unitdata_ind_t *)mp->b_rptr;
2395 2395 bcopy(LLCADDR(ind, ind->dl_dest_addr_offset),
2396 2396 (nmp->b_rptr + xid->dl_dest_addr_offset),
2397 2397 xid->dl_dest_addr_length);
2398 2398 }
2399 2399
2400 2400 LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap =
2401 2401 llchdr->llc_dsap;
2402 2402
2403 2403 xid->dl_src_addr_offset =
2404 2404 xid->dl_dest_addr_offset + xid->dl_dest_addr_length;
2405 2405 xid->dl_src_addr_length = xid->dl_dest_addr_length;
2406 2406
2407 2407 if (raw) {
2408 2408 bcopy(hdr->ether_shost.ether_addr_octet,
2409 2409 (nmp->b_rptr + xid->dl_src_addr_offset),
2410 2410 xid->dl_src_addr_length);
2411 2411 } else {
2412 2412 dl_unitdata_ind_t *ind;
2413 2413 ind = (dl_unitdata_ind_t *)mp->b_rptr;
2414 2414 bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset),
2415 2415 (nmp->b_rptr + xid->dl_src_addr_offset),
2416 2416 ind->dl_src_addr_length);
2417 2417 }
2418 2418 LLCADDR(nmp->b_rptr, xid->dl_src_addr_offset)->llca_sap =
2419 2419 llchdr->llc_ssap & ~LLC_RESPONSE;
2420 2420
2421 2421 nmp->b_wptr = nmp->b_rptr + sizeof (dl_xid_ind_t) +
2422 2422 2 * xid->dl_dest_addr_length;
2423 2423
2424 2424 if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
2425 2425 xid->dl_primitive = DL_XID_IND;
2426 2426 } else {
2427 2427 xid->dl_primitive = DL_XID_CON;
2428 2428 }
2429 2429
2430 2430 DB_TYPE(nmp) = M_PROTO;
2431 2431 if (raw) {
2432 2432 if (MBLKL(mp) >
2433 2433 (sizeof (struct ether_header) + sizeof (struct llchdr))) {
2434 2434 nmp->b_cont = dupmsg(mp);
2435 2435 if (nmp->b_cont) {
2436 2436 nmp->b_cont->b_rptr +=
2437 2437 sizeof (struct ether_header) +
2438 2438 sizeof (struct llchdr);
2439 2439 }
2440 2440 }
2441 2441 } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) >
2442 2442 sizeof (struct llchdr)) {
2443 2443 nmp->b_cont = dupmsg(mp->b_cont);
2444 2444 (void) adjmsg(nmp->b_cont, sizeof (struct llchdr));
2445 2445 }
2446 2446 putnext(RD(lld->llc_qptr), nmp);
2447 2447 return (mp);
2448 2448 }
2449 2449
2450 2450 /*
2451 2451 * llc1_xid_req_res(q, mp, req_or_res) the user wants to send an XID message
2452 2452 * or response construct a proper message and put on the net
2453 2453 */
2454 2454 static int
2455 2455 llc1_xid_req_res(queue_t *q, mblk_t *mp, int req_or_res)
2456 2456 {
2457 2457 dl_xid_req_t *xid = (dl_xid_req_t *)mp->b_rptr;
2458 2458 llc1_t *llc = (llc1_t *)q->q_ptr;
2459 2459 llc_mac_info_t *macinfo;
2460 2460 mblk_t *nmp, *rmp;
2461 2461 struct ether_header *hdr;
2462 2462 struct llchdr *llchdr;
2463 2463
2464 2464 if (llc == NULL || llc->llc_state == DL_UNATTACHED)
2465 2465 return (DL_OUTSTATE);
2466 2466
2467 2467 if (llc->llc_sap == LLC_NOVELL_SAP)
2468 2468 return (DL_NOTSUPPORTED);
2469 2469
2470 2470 if (llc->llc_flags & DL_AUTO_XID)
2471 2471 return (DL_XIDAUTO);
2472 2472
2473 2473 macinfo = llc->llc_mac_info;
2474 2474 if (MBLKL(mp) < sizeof (dl_xid_req_t) ||
2475 2475 !MBLKIN(mp, xid->dl_dest_addr_offset, xid->dl_dest_addr_length)) {
2476 2476 return (DL_BADPRIM);
2477 2477 }
2478 2478
2479 2479 nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr) +
2480 2480 sizeof (struct llchdr_xid), BPRI_MED);
2481 2481
2482 2482 if (nmp == NULL)
2483 2483 return (LLCE_NOBUFFER);
2484 2484
2485 2485 if (macinfo->llcp_flags & LLC1_USING_RAW) {
2486 2486 hdr = (struct ether_header *)nmp->b_rptr;
2487 2487 bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr,
2488 2488 hdr->ether_dhost.ether_addr_octet, ETHERADDRL);
2489 2489 bcopy(macinfo->llcp_macaddr,
2490 2490 hdr->ether_shost.ether_addr_octet, ETHERADDRL);
2491 2491 hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp));
2492 2492 nmp->b_wptr = nmp->b_rptr +
2493 2493 sizeof (struct ether_header) + sizeof (struct llchdr);
2494 2494 llchdr = (struct llchdr *)(hdr + 1);
2495 2495 rmp = nmp;
2496 2496 } else {
2497 2497 dl_unitdata_req_t *ud;
2498 2498 rmp = allocb(sizeof (dl_unitdata_req_t) +
2499 2499 (macinfo->llcp_addrlen + 2), BPRI_MED);
2500 2500 if (rmp == NULL) {
2501 2501 freemsg(nmp);
2502 2502 return (LLCE_NOBUFFER);
2503 2503 }
2504 2504 ud = (dl_unitdata_req_t *)rmp->b_rptr;
2505 2505 DB_TYPE(rmp) = M_PROTO;
2506 2506 ud->dl_primitive = DL_UNITDATA_REQ;
2507 2507 ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
2508 2508 ud->dl_dest_addr_length = xid->dl_dest_addr_length;
2509 2509 rmp->b_wptr += sizeof (dl_unitdata_req_t);
2510 2510 bcopy(LLCADDR(xid, xid->dl_dest_addr_offset)->llca_addr,
2511 2511 LLCADDR(ud, ud->dl_dest_addr_offset),
2512 2512 xid->dl_dest_addr_length);
2513 2513 LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap =
2514 2514 msgdsize(mp);
2515 2515 rmp->b_wptr += xid->dl_dest_addr_length;
2516 2516 rmp->b_cont = nmp;
2517 2517 llchdr = (struct llchdr *)nmp->b_rptr;
2518 2518 nmp->b_wptr += sizeof (struct llchdr);
2519 2519 }
2520 2520
2521 2521 llchdr->llc_dsap = LLCADDR(xid, xid->dl_dest_addr_offset)->llca_sap;
2522 2522 llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0);
2523 2523 llchdr->llc_ctl =
2524 2524 LLC_XID | ((xid->dl_flag & DL_POLL_FINAL) ? LLC_P : 0);
2525 2525
2526 2526 nmp->b_cont = mp->b_cont;
2527 2527 mp->b_cont = NULL;
2528 2528 freeb(mp);
2529 2529 macinfo->llcp_stats.llcs_xidxmt++;
2530 2530 putnext(WR(macinfo->llcp_queue), rmp);
2531 2531 return (LLCE_OK);
2532 2532 }
2533 2533
2534 2534 /*
2535 2535 * llc1_test_reply(macinfo, mp)
2536 2536 * automatic reply to a TEST message
2537 2537 */
2538 2538 static mblk_t *
2539 2539 llc1_test_reply(llc_mac_info_t *macinfo, mblk_t *mp, int sap)
2540 2540 {
2541 2541 mblk_t *nmp;
2542 2542 struct ether_header *hdr, *msgether;
2543 2543 struct llchdr *llchdr;
2544 2544 struct llchdr *msgllc;
2545 2545 int poll_final;
2546 2546
2547 2547 if (DB_TYPE(mp) == M_PROTO) {
2548 2548 if (mp->b_cont == NULL)
2549 2549 return (mp);
2550 2550 llchdr = (struct llchdr *)mp->b_cont->b_rptr;
2551 2551 hdr = NULL;
2552 2552 } else {
2553 2553 hdr = (struct ether_header *)mp->b_rptr;
2554 2554 llchdr = (struct llchdr *)(hdr + 1);
2555 2555 }
2556 2556
2557 2557 /* we only want to respond to commands to avoid response loops */
2558 2558 if (llchdr->llc_ssap & LLC_RESPONSE)
2559 2559 return (mp);
2560 2560
2561 2561 nmp = copymsg(mp); /* so info field is duplicated */
2562 2562 if (nmp == NULL) {
2563 2563 nmp = mp;
2564 2564 mp = NULL;
2565 2565 }
2566 2566 /*
2567 2567 * now construct the TEST reply frame
2568 2568 */
2569 2569
2570 2570
2571 2571 poll_final = llchdr->llc_ctl & LLC_P;
2572 2572
2573 2573 if (DB_TYPE(nmp) == M_PROTO) {
2574 2574 dl_unitdata_req_t *udr = (dl_unitdata_req_t *)nmp->b_rptr;
2575 2575 dl_unitdata_ind_t *udi = (dl_unitdata_ind_t *)nmp->b_rptr;
2576 2576
2577 2577 /* make into a request */
2578 2578 udr->dl_primitive = DL_UNITDATA_REQ;
2579 2579 udr->dl_dest_addr_offset = udi->dl_src_addr_offset;
2580 2580 udr->dl_dest_addr_length = udi->dl_src_addr_length;
2581 2581 udr->dl_priority.dl_min = udr->dl_priority.dl_max = 0;
2582 2582 msgllc = (struct llchdr *)nmp->b_cont->b_rptr;
2583 2583 } else {
2584 2584 msgether = (struct ether_header *)nmp->b_rptr;
2585 2585 bcopy(hdr->ether_shost.ether_addr_octet,
2586 2586 msgether->ether_dhost.ether_addr_octet,
2587 2587 macinfo->llcp_addrlen);
2588 2588 bcopy(macinfo->llcp_macaddr,
2589 2589 msgether->ether_shost.ether_addr_octet,
2590 2590 macinfo->llcp_addrlen);
2591 2591 msgllc = (struct llchdr *)(msgether+1);
2592 2592 }
2593 2593
2594 2594 msgllc->llc_dsap = llchdr->llc_ssap;
2595 2595
2596 2596 /* mark it as a response */
2597 2597 msgllc->llc_ssap = sap | LLC_RESPONSE;
2598 2598 msgllc->llc_ctl = LLC_TEST | poll_final;
2599 2599
2600 2600 macinfo->llcp_stats.llcs_testxmt++;
2601 2601 putnext(WR(macinfo->llcp_queue), nmp);
2602 2602 return (mp);
2603 2603 }
2604 2604
2605 2605 /*
2606 2606 * llc1_test_ind_con(lld, macinfo, mp) form a DL_TEST_IND or DL_TEST_CON
2607 2607 * message to send to the user since it was requested that the user process
2608 2608 * these messages
2609 2609 */
2610 2610 static mblk_t *
2611 2611 llc1_test_ind_con(llc1_t *lld, llc_mac_info_t *macinfo, mblk_t *mp)
2612 2612 {
2613 2613 mblk_t *nmp;
2614 2614 dl_test_ind_t *test;
2615 2615 struct ether_header *hdr;
2616 2616 struct llchdr *llchdr;
2617 2617 int raw;
2618 2618
2619 2619 nmp = allocb(sizeof (dl_test_ind_t) + 2 * (ETHERADDRL + 1), BPRI_MED);
2620 2620 if (nmp == NULL)
2621 2621 return (NULL);
2622 2622
2623 2623 if ((raw = (DB_TYPE(mp) == M_DATA)) != 0) {
2624 2624 hdr = (struct ether_header *)mp->b_rptr;
2625 2625 llchdr = (struct llchdr *)(hdr + 1);
2626 2626 } else {
2627 2627 if (mp->b_rptr == NULL)
2628 2628 return (mp);
2629 2629 llchdr = (struct llchdr *)mp->b_cont->b_rptr;
2630 2630 }
2631 2631
2632 2632 test = (dl_test_ind_t *)nmp->b_rptr;
2633 2633 test->dl_flag = (llchdr->llc_ctl & LLC_P) ? DL_POLL_FINAL : 0;
2634 2634 test->dl_dest_addr_offset = sizeof (dl_test_ind_t);
2635 2635 test->dl_dest_addr_length = macinfo->llcp_addrlen + 1;
2636 2636
2637 2637 if (raw) {
2638 2638 bcopy(hdr->ether_dhost.ether_addr_octet,
2639 2639 LLCADDR(nmp->b_rptr, test->dl_dest_addr_offset)->llca_addr,
2640 2640 test->dl_dest_addr_length);
2641 2641 } else {
2642 2642 dl_unitdata_ind_t *ind;
2643 2643 ind = (dl_unitdata_ind_t *)mp->b_rptr;
2644 2644 bcopy(LLCADDR(ind, ind->dl_dest_addr_offset),
2645 2645 (nmp->b_rptr + test->dl_dest_addr_offset),
2646 2646 test->dl_dest_addr_length);
2647 2647 }
2648 2648
2649 2649 LLCADDR(test, test->dl_dest_addr_offset)->llca_sap =
2650 2650 llchdr->llc_dsap;
2651 2651
2652 2652 test->dl_src_addr_offset = test->dl_dest_addr_offset +
2653 2653 test->dl_dest_addr_length;
2654 2654 test->dl_src_addr_length = test->dl_dest_addr_length;
2655 2655
2656 2656 if (raw) {
2657 2657 bcopy(hdr->ether_shost.ether_addr_octet,
2658 2658 LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_addr,
2659 2659 test->dl_src_addr_length);
2660 2660 } else {
2661 2661 dl_unitdata_ind_t *ind;
2662 2662 ind = (dl_unitdata_ind_t *)mp->b_rptr;
2663 2663 bcopy(LLCADDR(mp->b_rptr, ind->dl_src_addr_offset),
2664 2664 (nmp->b_rptr + test->dl_src_addr_offset),
2665 2665 ind->dl_src_addr_length);
2666 2666 }
2667 2667 LLCADDR(nmp->b_rptr, test->dl_src_addr_offset)->llca_sap =
2668 2668 llchdr->llc_ssap & ~LLC_RESPONSE;
2669 2669
2670 2670 nmp->b_wptr = nmp->b_rptr + sizeof (dl_test_ind_t) +
2671 2671 2 * test->dl_dest_addr_length;
2672 2672
2673 2673 if (!(llchdr->llc_ssap & LLC_RESPONSE)) {
2674 2674 test->dl_primitive = DL_TEST_IND;
2675 2675 } else {
2676 2676 test->dl_primitive = DL_TEST_CON;
2677 2677 }
2678 2678
2679 2679 DB_TYPE(nmp) = M_PROTO;
2680 2680 if (raw) {
2681 2681 if (MBLKL(mp) >
2682 2682 (sizeof (struct ether_header) + sizeof (struct llchdr))) {
2683 2683 nmp->b_cont = dupmsg(mp);
2684 2684 if (nmp->b_cont) {
2685 2685 nmp->b_cont->b_rptr +=
2686 2686 sizeof (struct ether_header) +
2687 2687 sizeof (struct llchdr);
2688 2688 }
2689 2689 }
2690 2690 } else if (mp->b_cont != NULL && MBLKL(mp->b_cont) >
2691 2691 sizeof (struct llchdr)) {
2692 2692 nmp->b_cont = dupmsg(mp->b_cont);
2693 2693 (void) adjmsg(nmp->b_cont, sizeof (struct llchdr));
2694 2694 }
2695 2695 putnext(RD(lld->llc_qptr), nmp);
2696 2696 return (mp);
2697 2697 }
2698 2698
2699 2699 /*
2700 2700 * llc1_test_req_res(q, mp, req_or_res) the user wants to send a TEST
2701 2701 * message or response construct a proper message and put on the net
2702 2702 */
2703 2703 static int
2704 2704 llc1_test_req_res(queue_t *q, mblk_t *mp, int req_or_res)
2705 2705 {
2706 2706 dl_test_req_t *test = (dl_test_req_t *)mp->b_rptr;
2707 2707 llc1_t *llc = (llc1_t *)q->q_ptr;
2708 2708 llc_mac_info_t *macinfo;
2709 2709 mblk_t *nmp, *rmp;
2710 2710 struct ether_header *hdr;
2711 2711 struct llchdr *llchdr;
2712 2712
2713 2713 if (llc == NULL || llc->llc_state == DL_UNATTACHED)
2714 2714 return (DL_OUTSTATE);
2715 2715
2716 2716 if (llc->llc_sap == LLC_NOVELL_SAP)
2717 2717 return (DL_NOTSUPPORTED);
2718 2718
2719 2719 if (llc->llc_flags & DL_AUTO_TEST)
2720 2720 return (DL_TESTAUTO);
2721 2721
2722 2722 macinfo = llc->llc_mac_info;
2723 2723 if (MBLKL(mp) < sizeof (dl_test_req_t) ||
2724 2724 !MBLKIN(mp, test->dl_dest_addr_offset,
2725 2725 test->dl_dest_addr_length)) {
2726 2726 return (DL_BADPRIM);
2727 2727 }
2728 2728
2729 2729 nmp = allocb(sizeof (struct ether_header) + sizeof (struct llchdr),
2730 2730 BPRI_MED);
2731 2731
2732 2732 if (nmp == NULL)
2733 2733 return (LLCE_NOBUFFER);
2734 2734
2735 2735 if (macinfo->llcp_flags & LLC1_USING_RAW) {
2736 2736 hdr = (struct ether_header *)nmp->b_rptr;
2737 2737 bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr,
2738 2738 hdr->ether_dhost.ether_addr_octet, ETHERADDRL);
2739 2739 bcopy(macinfo->llcp_macaddr,
2740 2740 hdr->ether_shost.ether_addr_octet, ETHERADDRL);
2741 2741 hdr->ether_type = htons(sizeof (struct llchdr) + msgdsize(mp));
2742 2742 nmp->b_wptr = nmp->b_rptr +
2743 2743 sizeof (struct ether_header) + sizeof (struct llchdr);
2744 2744 llchdr = (struct llchdr *)(hdr + 1);
2745 2745 rmp = nmp;
2746 2746 } else {
2747 2747 dl_unitdata_req_t *ud;
2748 2748
2749 2749 rmp = allocb(sizeof (dl_unitdata_req_t) +
2750 2750 (macinfo->llcp_addrlen + 2), BPRI_MED);
2751 2751 if (rmp == NULL) {
2752 2752 freemsg(nmp);
2753 2753 return (LLCE_NOBUFFER);
2754 2754
2755 2755 }
2756 2756 ud = (dl_unitdata_req_t *)rmp->b_rptr;
2757 2757 DB_TYPE(rmp) = M_PROTO;
2758 2758 ud->dl_primitive = DL_UNITDATA_REQ;
2759 2759 ud->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
2760 2760 ud->dl_dest_addr_length = test->dl_dest_addr_length;
2761 2761 rmp->b_wptr += sizeof (dl_unitdata_req_t);
2762 2762 bcopy(LLCADDR(test, test->dl_dest_addr_offset)->llca_addr,
2763 2763 LLCADDR(ud, ud->dl_dest_addr_offset),
2764 2764 test->dl_dest_addr_length);
2765 2765 LLCSADDR(ud, ud->dl_dest_addr_offset)->llca_ssap =
2766 2766 msgdsize(mp);
2767 2767 rmp->b_wptr += test->dl_dest_addr_length;
2768 2768 rmp->b_cont = nmp;
2769 2769 llchdr = (struct llchdr *)nmp->b_rptr;
2770 2770 nmp->b_wptr += sizeof (struct llchdr);
2771 2771 }
2772 2772
2773 2773 llchdr->llc_dsap = LLCADDR(test, test->dl_dest_addr_offset)->llca_sap;
2774 2774 llchdr->llc_ssap = llc->llc_sap | (req_or_res ? LLC_RESPONSE : 0);
2775 2775 llchdr->llc_ctl =
2776 2776 LLC_TEST | ((test->dl_flag & DL_POLL_FINAL) ? LLC_P : 0);
2777 2777
2778 2778 nmp->b_cont = mp->b_cont;
2779 2779 mp->b_cont = NULL;
2780 2780 freeb(mp);
2781 2781 macinfo->llcp_stats.llcs_testxmt++;
2782 2782 putnext(WR(macinfo->llcp_queue), rmp);
2783 2783 return (LLCE_OK);
2784 2784 }
2785 2785
2786 2786 /*
2787 2787 * llc1_find_waiting(macinfo, mp, prim) look for a stream waiting for a
2788 2788 * response to a message identified by prim and send it to the user.
2789 2789 */
2790 2790 static void
2791 2791 llc1_find_waiting(llc_mac_info_t *macinfo, mblk_t *mp, long prim)
2792 2792 {
2793 2793 llc1_t *llc;
2794 2794
2795 2795 for (llc = llc1_device_list.llc1_str_next;
2796 2796 llc != (llc1_t *)&llc1_device_list.llc1_str_next;
2797 2797 llc = llc->llc_next)
2798 2798 if (llc->llc_mac_info == macinfo &&
2799 2799 prim == llc->llc_waiting_for) {
2800 2800 putnext(RD(llc->llc_qptr), mp);
2801 2801 llc->llc_waiting_for = -1;
2802 2802 return;
2803 2803 }
2804 2804 freemsg(mp);
2805 2805 }
2806 2806
2807 2807 static void
2808 2808 llc1insque(void *elem, void *pred)
2809 2809 {
2810 2810 struct qelem *pelem = elem;
2811 2811 struct qelem *ppred = pred;
2812 2812 struct qelem *pnext = ppred->q_forw;
2813 2813
2814 2814 pelem->q_forw = pnext;
2815 2815 pelem->q_back = ppred;
2816 2816 ppred->q_forw = pelem;
2817 2817 pnext->q_back = pelem;
2818 2818 }
2819 2819
2820 2820 static void
2821 2821 llc1remque(void *arg)
2822 2822 {
2823 2823 struct qelem *pelem = arg;
2824 2824 struct qelem *elem = arg;
2825 2825
2826 2826 ASSERT(pelem->q_forw != NULL);
2827 2827 pelem->q_forw->q_back = pelem->q_back;
2828 2828 pelem->q_back->q_forw = pelem->q_forw;
2829 2829 elem->q_back = elem->q_forw = NULL;
2830 2830 }
2831 2831
2832 2832 /* VARARGS */
2833 2833 static void
2834 2834 llc1error(dip, fmt, a1, a2, a3, a4, a5, a6)
2835 2835 dev_info_t *dip;
2836 2836 char *fmt, *a1, *a2, *a3, *a4, *a5, *a6;
2837 2837 {
2838 2838 static long last;
2839 2839 static char *lastfmt;
2840 2840 time_t now;
2841 2841
2842 2842 /*
2843 2843 * Don't print same error message too often.
2844 2844 */
2845 2845 now = gethrestime_sec();
2846 2846 if ((last == (now & ~1)) && (lastfmt == fmt))
2847 2847 return;
2848 2848 last = now & ~1;
2849 2849 lastfmt = fmt;
2850 2850
2851 2851 cmn_err(CE_CONT, "%s%d: ",
2852 2852 ddi_get_name(dip), ddi_get_instance(dip));
2853 2853 cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5, a6);
2854 2854 cmn_err(CE_CONT, "\n");
2855 2855 }
2856 2856
2857 2857 /*ARGSUSED1*/
2858 2858 static int
2859 2859 llc1_update_kstat(kstat_t *ksp, int rw)
2860 2860 {
2861 2861 llc_mac_info_t *macinfo;
2862 2862 kstat_named_t *kstat;
2863 2863 struct llc_stats *stats;
2864 2864
2865 2865 if (ksp == NULL)
2866 2866 return (0);
2867 2867
2868 2868 kstat = (kstat_named_t *)(ksp->ks_data);
2869 2869 macinfo = (llc_mac_info_t *)(ksp->ks_private);
2870 2870 stats = &macinfo->llcp_stats;
2871 2871
2872 2872 kstat[LLCS_NOBUFFER].value.ul = stats->llcs_nobuffer;
2873 2873 kstat[LLCS_MULTIXMT].value.ul = stats->llcs_multixmt;
2874 2874 kstat[LLCS_MULTIRCV].value.ul = stats->llcs_multircv;
2875 2875 kstat[LLCS_BRDCSTXMT].value.ul = stats->llcs_brdcstxmt;
2876 2876 kstat[LLCS_BRDCSTRCV].value.ul = stats->llcs_brdcstrcv;
2877 2877 kstat[LLCS_BLOCKED].value.ul = stats->llcs_blocked;
2878 2878 kstat[LLCS_PKTXMT].value.ul = stats->llcs_pktxmt;
2879 2879 kstat[LLCS_PKTRCV].value.ul = stats->llcs_pktrcv;
2880 2880 kstat[LLCS_BYTEXMT].value.ul = stats->llcs_bytexmt;
2881 2881 kstat[LLCS_BYTERCV].value.ul = stats->llcs_bytercv;
2882 2882 kstat[LLCS_XIDXMT].value.ul = stats->llcs_xidxmt;
2883 2883 kstat[LLCS_XIDRCV].value.ul = stats->llcs_xidrcv;
2884 2884 kstat[LLCS_TESTXMT].value.ul = stats->llcs_testxmt;
2885 2885 kstat[LLCS_TESTRCV].value.ul = stats->llcs_testrcv;
2886 2886 kstat[LLCS_IERRORS].value.ul = stats->llcs_ierrors;
2887 2887 kstat[LLCS_OERRORS].value.ul = stats->llcs_oerrors;
2888 2888 return (0);
2889 2889 }
2890 2890
2891 2891 static void
2892 2892 llc1_init_kstat(llc_mac_info_t *macinfo)
2893 2893 {
2894 2894 kstat_named_t *ksp;
2895 2895
2896 2896 /*
2897 2897 * Note that the temporary macinfo->llcp_ppa number is negative.
2898 2898 */
2899 2899 macinfo->llcp_kstatp = kstat_create("llc", (-macinfo->llcp_ppa - 1),
2900 2900 NULL, "net", KSTAT_TYPE_NAMED,
2901 2901 sizeof (struct llc_stats) / sizeof (long), 0);
2902 2902 if (macinfo->llcp_kstatp == NULL)
2903 2903 return;
2904 2904
2905 2905 macinfo->llcp_kstatp->ks_update = llc1_update_kstat;
2906 2906 macinfo->llcp_kstatp->ks_private = (void *)macinfo;
2907 2907
2908 2908 ksp = (kstat_named_t *)(macinfo->llcp_kstatp->ks_data);
2909 2909
2910 2910 kstat_named_init(&ksp[LLCS_NOBUFFER], "nobuffer", KSTAT_DATA_ULONG);
2911 2911 kstat_named_init(&ksp[LLCS_MULTIXMT], "multixmt", KSTAT_DATA_ULONG);
2912 2912 kstat_named_init(&ksp[LLCS_MULTIRCV], "multircv", KSTAT_DATA_ULONG);
2913 2913 kstat_named_init(&ksp[LLCS_BRDCSTXMT], "brdcstxmt", KSTAT_DATA_ULONG);
2914 2914 kstat_named_init(&ksp[LLCS_BRDCSTRCV], "brdcstrcv", KSTAT_DATA_ULONG);
2915 2915 kstat_named_init(&ksp[LLCS_BLOCKED], "blocked", KSTAT_DATA_ULONG);
2916 2916 kstat_named_init(&ksp[LLCS_PKTXMT], "pktxmt", KSTAT_DATA_ULONG);
2917 2917 kstat_named_init(&ksp[LLCS_PKTRCV], "pktrcv", KSTAT_DATA_ULONG);
2918 2918 kstat_named_init(&ksp[LLCS_BYTEXMT], "bytexmt", KSTAT_DATA_ULONG);
2919 2919 kstat_named_init(&ksp[LLCS_BYTERCV], "bytercv", KSTAT_DATA_ULONG);
2920 2920 kstat_named_init(&ksp[LLCS_XIDXMT], "xidxmt", KSTAT_DATA_ULONG);
2921 2921 kstat_named_init(&ksp[LLCS_XIDRCV], "xidrcv", KSTAT_DATA_ULONG);
2922 2922 kstat_named_init(&ksp[LLCS_TESTXMT], "testxmt", KSTAT_DATA_ULONG);
2923 2923 kstat_named_init(&ksp[LLCS_TESTRCV], "testrcv", KSTAT_DATA_ULONG);
2924 2924 kstat_named_init(&ksp[LLCS_IERRORS], "ierrors", KSTAT_DATA_ULONG);
2925 2925 kstat_named_init(&ksp[LLCS_OERRORS], "oerrors", KSTAT_DATA_ULONG);
2926 2926 kstat_install(macinfo->llcp_kstatp);
2927 2927 }
2928 2928
2929 2929 static void
2930 2930 llc1_uninit_kstat(llc_mac_info_t *macinfo)
2931 2931 {
2932 2932 if (macinfo->llcp_kstatp) {
2933 2933 kstat_delete(macinfo->llcp_kstatp);
2934 2934 macinfo->llcp_kstatp = NULL;
2935 2935 }
2936 2936 }
2937 2937
2938 2938 /*
2939 2939 * llc1_subs_bind(q, mp)
2940 2940 * implements the DL_SUBS_BIND_REQ primitive
2941 2941 * this only works for a STREAM bound to LLC_SNAP_SAP
2942 2942 * or one bound to the automatic SNAP mode.
2943 2943 * If bound to LLC_SNAP_SAP, the subs bind can be:
2944 2944 * - 2 octets treated as a native byte order short (ethertype)
2945 2945 * - 3 octets treated as a network order byte string (OID part)
2946 2946 * - 5 octets treated as a network order byte string (full SNAP header)
2947 2947 * If bound to an automatic SNAP mode sap, then only the 3 octet
2948 2948 * form is allowed
2949 2949 */
2950 2950 static int
2951 2951 llc1_subs_bind(queue_t *q, mblk_t *mp)
2952 2952 {
2953 2953 llc1_t *lld = (llc1_t *)q->q_ptr;
2954 2954 dl_subs_bind_req_t *subs = (dl_subs_bind_req_t *)mp->b_rptr;
2955 2955 ushort_t subssap;
2956 2956 uchar_t *sapstr;
2957 2957 int result;
2958 2958
2959 2959
2960 2960 #if defined(LLC1_DEBUG)
2961 2961 if (llc1_debug & (LLCTRACE|LLCPROT)) {
2962 2962 printf("llc1_subs_bind (%x, %x)\n", q, mp);
2963 2963 }
2964 2964 #endif
2965 2965
2966 2966 if (lld == NULL || lld->llc_state != DL_IDLE) {
2967 2967 result = DL_OUTSTATE;
2968 2968 } else if (lld->llc_sap != LLC_SNAP_SAP ||
2969 2969 subs->dl_subs_bind_class != DL_HIERARCHICAL_BIND) {
2970 2970 /* we only want to support this for SNAP at present */
2971 2971 result = DL_UNSUPPORTED;
2972 2972 } else {
2973 2973
2974 2974 lld->llc_state = DL_SUBS_BIND_PND;
2975 2975
2976 2976 sapstr = (uchar_t *)(mp->b_rptr + subs->dl_subs_sap_offset);
2977 2977
2978 2978 result = LLCE_OK;
2979 2979 switch (subs->dl_subs_sap_length) {
2980 2980 case 2: /* just the ethertype part */
2981 2981 if (lld->llc_flags & LLC_SNAP) {
2982 2982 result = DL_BADADDR;
2983 2983 break;
2984 2984 }
2985 2985 ((uchar_t *)&subssap)[0] = sapstr[0];
2986 2986 ((uchar_t *)&subssap)[1] = sapstr[1];
2987 2987 subssap = htons(subssap);
2988 2988 lld->llc_snap[3] = ((uchar_t *)&subssap)[0];
2989 2989 lld->llc_snap[4] = ((uchar_t *)&subssap)[1];
2990 2990 lld->llc_flags |= LLC_SNAP;
2991 2991 break;
2992 2992
2993 2993 case 3: /* just the OID part */
2994 2994 if ((lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) ==
2995 2995 (LLC_SNAP|LLC_SNAP_OID)) {
2996 2996 result = DL_BADADDR;
2997 2997 break;
2998 2998 }
2999 2999 bcopy(sapstr, lld->llc_snap, 3);
3000 3000 lld->llc_flags |= LLC_SNAP_OID;
3001 3001 break;
3002 3002
3003 3003 case 5: /* full SNAP header */
3004 3004 if (lld->llc_flags & (LLC_SNAP|LLC_SNAP_OID)) {
3005 3005 result = DL_BADADDR;
3006 3006 break;
3007 3007 }
3008 3008 bcopy(sapstr, lld->llc_snap, 5);
3009 3009 lld->llc_flags |= LLC_SNAP|LLC_SNAP_OID;
3010 3010 break;
3011 3011 }
3012 3012 /* if successful, acknowledge and enter the proper state */
3013 3013 if (result == LLCE_OK) {
3014 3014 mblk_t *nmp = mp;
3015 3015 dl_subs_bind_ack_t *ack;
3016 3016
3017 3017 if (DB_REF(mp) != 1 ||
3018 3018 MBLKL(mp) < (sizeof (dl_subs_bind_ack_t) + 5)) {
3019 3019 freemsg(mp);
3020 3020 nmp = allocb(sizeof (dl_subs_bind_ack_t) + 5,
3021 3021 BPRI_MED);
3022 3022 }
3023 3023 ack = (dl_subs_bind_ack_t *)nmp->b_rptr;
3024 3024 nmp->b_wptr = nmp->b_rptr +
3025 3025 sizeof (dl_subs_bind_ack_t) + 5;
3026 3026 ack->dl_primitive = DL_SUBS_BIND_ACK;
3027 3027 ack->dl_subs_sap_offset = sizeof (dl_subs_bind_ack_t);
3028 3028 ack->dl_subs_sap_length = 5;
3029 3029 bcopy(lld->llc_snap,
3030 3030 (caddr_t)nmp->b_rptr + ack->dl_subs_sap_offset + 5,
3031 3031 5);
3032 3032 DB_TYPE(nmp) = M_PCPROTO;
3033 3033 qreply(q, nmp);
3034 3034
3035 3035 }
3036 3036 lld->llc_state = DL_IDLE;
3037 3037 }
3038 3038 return (result);
3039 3039 }
3040 3040
3041 3041 /*
3042 3042 *
3043 3043 */
3044 3044 static int
3045 3045 llc1_subs_unbind(void)
3046 3046 {
3047 3047 return (DL_UNSUPPORTED);
3048 3048 }
3049 3049
3050 3050 char *
3051 3051 snapdmp(uchar_t *bstr)
3052 3052 {
3053 3053 static char buff[32];
3054 3054
3055 3055 (void) sprintf(buff, "%x.%x.%x.%x.%x",
3056 3056 bstr[0],
3057 3057 bstr[1],
3058 3058 bstr[2],
3059 3059 bstr[3],
3060 3060 bstr[4]);
3061 3061 return (buff);
3062 3062 }
3063 3063
3064 3064 static int
3065 3065 llc1_snap_match(llc1_t *lld, struct snaphdr *snap)
3066 3066 {
3067 3067 return (bcmp(snap->snap_oid, lld->llc_snap, 5) == 0);
3068 3068 }
↓ open down ↓ |
2862 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX