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