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