1 /* 2 * Copyright (c) University of British Columbia, 1984 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Laboratory for Computation Vision and the Computer Science Department 8 * of the University of British Columbia. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)pk_subr.c 7.8 (Berkeley) 11/13/90 13 */ 14 15 #include "param.h" 16 #include "systm.h" 17 #include "mbuf.h" 18 #include "socket.h" 19 #include "protosw.h" 20 #include "socketvar.h" 21 #include "errno.h" 22 #include "time.h" 23 #include "kernel.h" 24 25 #include "../net/if.h" 26 27 #include "x25.h" 28 #include "pk.h" 29 #include "pk_var.h" 30 #include "x25err.h" 31 32 int pk_sendspace = 1024 * 2 + 8; 33 int pk_recvspace = 1024 * 2 + 8; 34 35 struct x25_packet *pk_template (); 36 37 /* 38 * Attach X.25 protocol to socket, allocate logical channel descripter 39 * and buffer space, and enter LISTEN state if we are to accept 40 * IN-COMMING CALL packets. 41 * 42 */ 43 44 struct pklcd * 45 pk_attach (so) 46 struct socket *so; 47 { 48 register struct pklcd *lcp; 49 register int error = ENOBUFS; 50 51 MALLOC(lcp, struct pklcd *, sizeof(*lcp), M_PCB, M_NOWAIT); 52 if (lcp) { 53 bzero((caddr_t)lcp, sizeof(*lcp)); 54 if (so) { 55 error = soreserve (so, pk_sendspace, pk_recvspace); 56 lcp -> lcd_so = so; 57 if (so -> so_options & SO_ACCEPTCONN) 58 lcp -> lcd_state = LISTEN; 59 else 60 lcp -> lcd_state = READY; 61 } else 62 sbreserve (&lcp -> lcd_sb, pk_sendspace); 63 } 64 if (so) { 65 so -> so_pcb = (caddr_t) lcp; 66 so -> so_error = error; 67 } 68 return (lcp); 69 } 70 71 /* 72 * Disconnect X.25 protocol from socket. 73 */ 74 75 pk_disconnect (lcp) 76 register struct pklcd *lcp; 77 { 78 register struct socket *so = lcp -> lcd_so; 79 register struct pklcd *l, *p; 80 81 switch (lcp -> lcd_state) { 82 case LISTEN: 83 for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); 84 if (p == 0) { 85 if (l != 0) 86 pk_listenhead = l -> lcd_listen; 87 } 88 else 89 if (l != 0) 90 p -> lcd_listen = l -> lcd_listen; 91 pk_close (lcp); 92 break; 93 94 case READY: 95 pk_acct (lcp); 96 pk_close (lcp); 97 break; 98 99 case SENT_CLEAR: 100 case RECEIVED_CLEAR: 101 break; 102 103 default: 104 pk_acct (lcp); 105 if (so) { 106 soisdisconnecting (so); 107 sbflush (&so -> so_rcv); 108 } 109 pk_clear (lcp); 110 111 } 112 } 113 114 /* 115 * Close an X.25 Logical Channel. Discard all space held by the 116 * connection and internal descriptors. Wake up any sleepers. 117 */ 118 119 pk_close (lcp) 120 struct pklcd *lcp; 121 { 122 register struct socket *so = lcp -> lcd_so; 123 124 pk_freelcd (lcp); 125 126 if (so == NULL) 127 return; 128 129 so -> so_pcb = 0; 130 sbflush (&so -> so_snd); 131 sbflush (&so -> so_rcv); 132 soisdisconnected (so); 133 sofree (so); /* gak!!! you can't do that here */ 134 } 135 136 /* 137 * Create a template to be used to send X.25 packets on a logical 138 * channel. It allocates an mbuf and fills in a skeletal packet 139 * depending on its type. This packet is passed to pk_output where 140 * the remainer of the packet is filled in. 141 */ 142 143 struct x25_packet * 144 pk_template (lcn, type) 145 int lcn, type; 146 { 147 register struct mbuf *m; 148 register struct x25_packet *xp; 149 150 MGETHDR (m, M_DONTWAIT, MT_HEADER); 151 if (m == 0) 152 panic ("pk_template"); 153 m -> m_act = 0; 154 155 /* 156 * Efficiency hack: leave a four byte gap at the beginning 157 * of the packet level header with the hope that this will 158 * be enough room for the link level to insert its header. 159 */ 160 m -> m_data += max_linkhdr; 161 m -> m_len = PKHEADERLN; 162 163 xp = mtod (m, struct x25_packet *); 164 *(long *)xp = 0; /* ugly, but fast */ 165 /* xp -> q_bit = 0;*/ 166 xp -> fmt_identifier = 1; 167 /* xp -> lc_group_number = 0;*/ 168 169 SET_LCN(xp, lcn); 170 xp -> packet_type = type; 171 172 return (xp); 173 } 174 175 /* 176 * This routine restarts all the virtual circuits. Actually, 177 * the virtual circuits are not "restarted" as such. Instead, 178 * any active switched circuit is simply returned to READY 179 * state. 180 */ 181 182 pk_restart (pkp, restart_cause) 183 register struct pkcb *pkp; 184 int restart_cause; 185 { 186 register struct x25_packet *xp; 187 register struct pklcd *lcp; 188 register int i; 189 190 /* Restart all logical channels. */ 191 if (pkp -> pk_chan == 0) 192 return; 193 for (i = 1; i <= pkp -> pk_maxlcn; ++i) 194 if ((lcp = pkp -> pk_chan[i]) != NULL) { 195 if (lcp -> lcd_so) 196 lcp -> lcd_so -> so_error = ENETRESET; 197 pk_close (lcp); 198 } 199 200 if (restart_cause < 0) 201 return; 202 203 pkp -> pk_state = DTE_SENT_RESTART; 204 lcp = pkp -> pk_chan[0]; 205 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); 206 (dtom (xp)) -> m_len++; 207 xp -> packet_data = 0; /* DTE only */ 208 pk_output (lcp); 209 } 210 211 212 /* 213 * This procedure frees up the Logical Channel Descripter. 214 */ 215 216 pk_freelcd (lcp) 217 register struct pklcd *lcp; 218 { 219 if (lcp == NULL) 220 return; 221 222 if (lcp -> lcd_template) 223 m_freem (dtom (lcp -> lcd_template)); 224 225 if (lcp -> lcd_lcn > 0) 226 lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; 227 228 free((caddr_t)lcp, M_PCB); 229 } 230 231 232 /* 233 * Bind a address and protocol value to a socket. The important 234 * part is the protocol value - the first four characters of the 235 * Call User Data field. 236 */ 237 238 pk_bind (lcp, nam) 239 struct pklcd *lcp; 240 struct mbuf *nam; 241 { 242 register struct pkcb *pkp; 243 register struct mbuf *m; 244 register struct pklcd *pp; 245 register struct sockaddr_x25 *sa; 246 247 if (nam == NULL) 248 return (EADDRNOTAVAIL); 249 if (lcp -> lcd_ceaddr) /* XXX */ 250 return (EADDRINUSE); 251 if (checksockaddr (nam)) 252 return (EINVAL); 253 sa = mtod (nam, struct sockaddr_x25 *); 254 255 /* 256 * If the user wishes to accept calls only from a particular 257 * net (net != 0), make sure the net is known 258 */ 259 260 if (sa -> x25_net) 261 for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { 262 if (pkp == 0) 263 return (ENETUNREACH); 264 if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net) 265 break; 266 } 267 268 for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) 269 if (bcmp (pp -> lcd_ceaddr -> x25_udata, sa -> x25_udata, 270 min (pp -> lcd_ceaddr -> x25_udlen, sa -> x25_udlen)) == 0) 271 return (EADDRINUSE); 272 273 lcp -> lcd_laddr = *sa; 274 lcp -> lcd_ceaddr = &lcp -> lcd_laddr; 275 return (0); 276 } 277 278 /* 279 * Associate a logical channel descriptor with a network. 280 * Fill in the default network specific parameters and then 281 * set any parameters explicitly specified by the user or 282 * by the remote DTE. 283 */ 284 285 pk_assoc (pkp, lcp, sa) 286 register struct pkcb *pkp; 287 register struct pklcd *lcp; 288 register struct sockaddr_x25 *sa; 289 { 290 291 lcp -> lcd_pkp = pkp; 292 lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; 293 lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; 294 lcp -> lcd_rsn = MODULUS - 1; 295 pkp -> pk_chan[lcp -> lcd_lcn] = lcp; 296 297 if (sa -> x25_opts.op_psize) 298 lcp -> lcd_packetsize = sa -> x25_opts.op_psize; 299 else 300 sa -> x25_opts.op_psize = lcp -> lcd_packetsize; 301 if (sa -> x25_opts.op_wsize) 302 lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; 303 else 304 sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; 305 sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; 306 lcp -> lcd_flags = sa -> x25_opts.op_flags; 307 lcp -> lcd_stime = time.tv_sec; 308 } 309 310 pk_connect (lcp, nam, sa) 311 register struct pklcd *lcp; 312 register struct sockaddr_x25 *sa; 313 struct mbuf *nam; 314 { 315 register struct pkcb *pkp; 316 register struct mbuf *m; 317 register struct ifnet *ifp; 318 319 if (sa == 0) { 320 if (checksockaddr (nam)) 321 return (EINVAL); 322 sa = mtod (nam, struct sockaddr_x25 *); 323 } 324 if (sa -> x25_addr[0] == '\0') 325 return (EDESTADDRREQ); 326 if (lcp -> lcd_pkp == 0) 327 for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { 328 if (pkp == 0) 329 return (ENETUNREACH); 330 /* 331 * use first net configured (last in list 332 * headed by pkcbhead) if net is zero 333 */ 334 if (sa -> x25_net == 0 && pkp -> pk_next == 0) 335 break; 336 if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net) 337 break; 338 } 339 340 if (pkp -> pk_state != DTE_READY) 341 return (ENETDOWN); 342 if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) 343 return (EMFILE); 344 lcp -> lcd_faddr = *sa; 345 lcp -> lcd_ceaddr = & lcp -> lcd_faddr; 346 pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); 347 if (lcp -> lcd_so) 348 soisconnecting (lcp -> lcd_so); 349 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); 350 pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); 351 return (*pkp -> pk_start)(lcp); 352 } 353 354 /* 355 * Build the rest of the CALL REQUEST packet. Fill in calling 356 * address, facilities fields and the user data field. 357 */ 358 359 pk_callrequest (lcp, sa, xcp) 360 struct pklcd *lcp; 361 register struct sockaddr_x25 *sa; 362 register struct x25config *xcp; 363 { 364 register struct x25_calladdr *a; 365 register struct mbuf *m = dtom (lcp -> lcd_template); 366 unsigned posn = 0; 367 octet *cp; 368 369 if (lcp -> lcd_flags & X25_DBIT) 370 lcp -> lcd_template -> d_bit = 1; 371 a = (struct x25_calladdr *) &lcp -> lcd_template -> packet_data; 372 a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr); 373 a -> called_addrlen = strlen (sa -> x25_addr); 374 cp = (octet *) a -> address_field; 375 to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn); 376 to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn); 377 if (posn & 0x01) 378 *cp++ &= 0xf0; 379 380 build_facilities (&cp, sa, (int)xcp -> xc_type); 381 382 bcopy (sa -> x25_udata, (caddr_t)cp, (unsigned)sa -> x25_udlen); 383 cp += sa -> x25_udlen; 384 385 m -> m_len += cp - (octet *) a; 386 387 #ifdef ANDREW 388 printf ("call: "); 389 for (cp = mtod (m, octet *), posn = 0; posn < m -> m_len; ++posn) 390 printf ("%x ", *cp++); 391 printf ("\n"); 392 #endif 393 } 394 395 build_facilities (cp, sa, type) 396 register octet **cp; 397 struct sockaddr_x25 *sa; 398 { 399 register octet *fcp; 400 register int revcharge; 401 402 fcp = *cp + 1; 403 revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; 404 /* 405 * This is specific to Datapac X.25(1976) DTEs. International 406 * calls must have the "hi priority" bit on. 407 */ 408 if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) 409 revcharge |= 02; 410 if (revcharge) { 411 *fcp++ = FACILITIES_REVERSE_CHARGE; 412 *fcp++ = revcharge; 413 } 414 switch (type) { 415 case X25_1980: 416 case X25_1984: 417 *fcp++ = FACILITIES_PACKETSIZE; 418 *fcp++ = sa -> x25_opts.op_psize; 419 *fcp++ = sa -> x25_opts.op_psize; 420 421 *fcp++ = FACILITIES_WINDOWSIZE; 422 *fcp++ = sa -> x25_opts.op_wsize; 423 *fcp++ = sa -> x25_opts.op_wsize; 424 } 425 **cp = fcp - *cp - 1; 426 *cp = fcp; 427 } 428 429 to_bcd (a, len, x, posn) 430 register octet **a; 431 register char *x; 432 register int len; 433 register unsigned *posn; 434 { 435 while (--len >= 0) 436 if ((*posn)++ & 0x01) 437 *(*a)++ |= *x++ & 0x0F; 438 else 439 **a = *x++ << 4; 440 } 441 442 /* 443 * This routine gets the first available logical channel number. The 444 * search is from the highest number to lowest number (DTE). 445 */ 446 447 pk_getlcn (pkp) 448 register struct pkcb *pkp; 449 { 450 register int i; 451 452 if (pkp -> pk_chan == 0) 453 return (0); 454 for (i = pkp -> pk_maxlcn; i > 0; --i) 455 if (pkp -> pk_chan[i] == NULL) 456 break; 457 return (i); 458 459 } 460 461 static 462 checksockaddr (m) 463 struct mbuf *m; 464 { 465 register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *); 466 register char *cp; 467 468 if (m -> m_len != sizeof (struct sockaddr_x25)) 469 return (1); 470 if (sa -> x25_family != AF_CCITT || sa -> x25_udlen == 0 || 471 sa -> x25_udlen > sizeof (sa -> x25_udata)) 472 return (1); 473 for (cp = sa -> x25_addr; *cp; cp++) { 474 if (*cp < '0' || *cp > '9' || 475 cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1]) 476 return (1); 477 } 478 return (0); 479 } 480 481 /* 482 * This procedure sends a CLEAR request packet. The lc state is 483 * set to "SENT_CLEAR". 484 */ 485 486 pk_clear (lcp) 487 struct pklcd *lcp; 488 { 489 register struct x25_packet *xp; 490 491 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR); 492 (dtom (xp)) -> m_len++; 493 xp -> packet_data = 0; 494 495 pk_output (lcp); 496 497 } 498 499 /* 500 * This procedure sends a RESET request packet. It re-intializes 501 * virtual circuit. 502 */ 503 504 static 505 pk_reset (lcp) 506 register struct pklcd *lcp; 507 { 508 register struct x25_packet *xp; 509 register struct socket *so; 510 511 if (lcp -> lcd_state != DATA_TRANSFER) 512 return; 513 514 lcp -> lcd_reset_condition = TRUE; 515 516 /* Reset all the control variables for the channel. */ 517 lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = 518 lcp -> lcd_intrconf_pending = FALSE; 519 lcp -> lcd_rsn = MODULUS - 1; 520 lcp -> lcd_ssn = 0; 521 lcp -> lcd_output_window = lcp -> lcd_input_window = 522 lcp -> lcd_last_transmitted_pr = 0; 523 if (so = lcp -> lcd_so) { 524 so -> so_error = ECONNRESET; 525 sbflush (&so -> so_rcv); 526 sbflush (&so -> so_snd); 527 } 528 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); 529 (dtom (xp)) -> m_len += 2; 530 xp -> packet_data = 0; 531 pk_output (lcp); 532 533 } 534 535 536 /* 537 * This procedure handles all local protocol procedure errors. 538 */ 539 540 pk_procerror (error, lcp, errstr) 541 register struct pklcd *lcp; 542 char *errstr; 543 { 544 545 pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); 546 547 switch (error) { 548 case CLEAR: 549 if (lcp -> lcd_so) { 550 lcp -> lcd_so -> so_error = ECONNABORTED; 551 soisdisconnecting (lcp -> lcd_so); 552 } 553 pk_clear (lcp); 554 break; 555 556 case RESET: 557 pk_reset (lcp); 558 } 559 } 560 561 /* 562 * This procedure is called during the DATA TRANSFER state to check 563 * and process the P(R) values received in the DATA, RR OR RNR 564 * packets. 565 */ 566 567 pk_ack (lcp, pr) 568 struct pklcd *lcp; 569 unsigned pr; 570 { 571 register struct socket *so = lcp -> lcd_so; 572 573 if (lcp -> lcd_output_window == pr) 574 return (PACKET_OK); 575 if (lcp -> lcd_output_window < lcp -> lcd_ssn) { 576 if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { 577 pk_procerror (RESET, lcp, "p(r) flow control error"); 578 return (ERROR_PACKET); 579 } 580 } 581 else { 582 if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { 583 pk_procerror (RESET, lcp, "p(r) flow control error"); 584 return (ERROR_PACKET); 585 } 586 } 587 588 lcp -> lcd_output_window = pr; /* Rotate window. */ 589 if (lcp -> lcd_window_condition == TRUE) 590 lcp -> lcd_window_condition = FALSE; 591 592 if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel)) 593 sowwakeup (so); 594 if (lcp -> lcd_upper) 595 (*lcp -> lcd_upper)(lcp, 0); 596 597 return (PACKET_OK); 598 } 599 600 /* 601 * This procedure decodes the X.25 level 3 packet returning a 602 * code to be used in switchs or arrays. 603 */ 604 605 pk_decode (xp) 606 register struct x25_packet *xp; 607 { 608 register int type; 609 610 if (xp -> fmt_identifier != 1) 611 return (INVALID_PACKET); 612 613 /* 614 * Make sure that the logical channel group number is 0. 615 * This restriction may be removed at some later date. 616 */ 617 if (xp -> lc_group_number != 0) 618 return (INVALID_PACKET); 619 620 /* 621 * Test for data packet first. 622 */ 623 if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) 624 return (DATA); 625 626 /* 627 * Test if flow control packet (RR or RNR). 628 */ 629 if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) 630 if (!(xp -> packet_type & RR_PACKET_DESIGNATOR)) 631 return (RR); 632 else 633 return (RNR); 634 635 /* 636 * Determine the rest of the packet types. 637 */ 638 switch (xp -> packet_type) { 639 case X25_CALL: 640 type = CALL; 641 break; 642 643 case X25_CALL_ACCEPTED: 644 type = CALL_ACCEPTED; 645 break; 646 647 case X25_CLEAR: 648 type = CLEAR; 649 break; 650 651 case X25_CLEAR_CONFIRM: 652 type = CLEAR_CONF; 653 break; 654 655 case X25_INTERRUPT: 656 type = INTERRUPT; 657 break; 658 659 case X25_INTERRUPT_CONFIRM: 660 type = INTERRUPT_CONF; 661 break; 662 663 case X25_RESET: 664 type = RESET; 665 break; 666 667 case X25_RESET_CONFIRM: 668 type = RESET_CONF; 669 break; 670 671 case X25_RESTART: 672 type = RESTART; 673 break; 674 675 case X25_RESTART_CONFIRM: 676 type = RESTART_CONF; 677 break; 678 679 default: 680 type = INVALID_PACKET; 681 } 682 return (type); 683 } 684 685 /* 686 * A restart packet has been received. Print out the reason 687 * for the restart. 688 */ 689 690 pk_restartcause (pkp, xp) 691 struct pkcb *pkp; 692 register struct x25_packet *xp; 693 { 694 register struct x25config *xcp = pkp -> pk_xcp; 695 register int lcn = LCN(xp); 696 697 switch (xp -> packet_data) { 698 case X25_RESTART_LOCAL_PROCEDURE_ERROR: 699 pk_message (lcn, xcp, "restart: local procedure error"); 700 break; 701 702 case X25_RESTART_NETWORK_CONGESTION: 703 pk_message (lcn, xcp, "restart: network congestion"); 704 break; 705 706 case X25_RESTART_NETWORK_OPERATIONAL: 707 pk_message (lcn, xcp, "restart: network operational"); 708 break; 709 710 default: 711 pk_message (lcn, xcp, "restart: unknown cause"); 712 } 713 } 714 715 #define MAXRESETCAUSE 7 716 717 int Reset_cause[] = { 718 EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG 719 }; 720 721 /* 722 * A reset packet has arrived. Return the cause to the user. 723 */ 724 725 pk_resetcause (pkp, xp) 726 struct pkcb *pkp; 727 register struct x25_packet *xp; 728 { 729 register struct pklcd *lcp = 730 pkp -> pk_chan[LCN(xp)]; 731 register int code = xp -> packet_data; 732 733 if (code > MAXRESETCAUSE) 734 code = 7; /* EXRNCG */ 735 736 lcp -> lcd_so -> so_error = Reset_cause[code]; 737 } 738 739 #define MAXCLEARCAUSE 25 740 741 int Clear_cause[] = { 742 EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, 743 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, 744 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC 745 }; 746 747 /* 748 * A clear packet has arrived. Return the cause to the user. 749 */ 750 751 pk_clearcause (pkp, xp) 752 struct pkcb *pkp; 753 register struct x25_packet *xp; 754 { 755 register struct pklcd *lcp = 756 pkp -> pk_chan[LCN(xp)]; 757 register int code = xp -> packet_data; 758 759 if (code > MAXCLEARCAUSE) 760 code = 5; /* EXRNCG */ 761 lcp -> lcd_so -> so_error = Clear_cause[code]; 762 } 763 764 char * 765 format_ntn (xcp) 766 register struct x25config *xcp; 767 { 768 769 return (xcp -> xc_addr.x25_addr); 770 } 771 772 /* VARARGS1 */ 773 pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) 774 struct x25config *xcp; 775 char *fmt; 776 { 777 778 if (lcn) 779 if (pkcbhead -> pk_next) 780 printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); 781 else 782 printf ("X.25: lcn %d: ", lcn); 783 else 784 if (pkcbhead -> pk_next) 785 printf ("X.25(%s): ", format_ntn (xcp)); 786 else 787 printf ("X.25: "); 788 789 printf (fmt, a1, a2, a3, a4, a5, a6); 790 printf ("\n"); 791 } 792 793 pk_ifattach(ia, lloutput, llnext) 794 register struct x25_ifaddr *ia; 795 int (*lloutput)(); 796 caddr_t llnext; 797 { 798 /* this is here because you can't include both pk_var and hd_var */ 799 /* this will probably be replace by a streams gluing mechanism */ 800 ia -> ia_pkcb.pk_lloutput = lloutput; 801 ia -> ia_pkcb.pk_llnext = llnext; 802 } 803 804 pk_fragment(lcp, m0, qbit, mbit, wait) 805 struct mbuf *m0; 806 register struct pklcd *lcp; 807 { 808 register struct mbuf *m = m0; 809 register struct x25_packet *xp; 810 register struct sockbuf *sb; 811 struct mbuf *head = 0, *next, **mp = &head; 812 int totlen, psize = 1 << (lcp -> lcd_packetsize); 813 814 if (m == 0) 815 return; 816 if (m->m_flags & M_PKTHDR == 0) 817 panic("pk_fragment"); 818 totlen = m -> m_pkthdr.len; 819 m -> m_act = 0; 820 sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; 821 do { 822 if (totlen > psize) { 823 next = m; 824 m = m_copym(m, 0, psize, wait); 825 if (m == 0) 826 goto abort; 827 m_adj(next, psize); 828 totlen -= psize; 829 } else 830 next = 0; 831 M_PREPEND(m, PKHEADERLN, wait); 832 if (m == 0) 833 goto abort; 834 *mp = m; 835 mp = & m -> m_act; 836 *mp = 0; 837 xp = mtod(m, struct x25_packet *); 838 0[(char *)xp] = 0; 839 if (qbit) 840 xp -> q_bit = 1; 841 if (lcp -> lcd_flags & X25_DBIT) 842 xp -> d_bit = 1; 843 xp -> fmt_identifier = 1; 844 xp -> packet_type = X25_DATA; 845 SET_LCN(xp, lcp -> lcd_lcn); 846 if (next || (mbit && (totlen == psize || 847 (lcp -> lcd_flags & X25_DBIT)))) 848 MBIT(xp) = 1; 849 } while (m = next); 850 for (m = head; m; m = next) { 851 next = m -> m_act; 852 m -> m_act = 0; 853 sbappendrecord(sb, m); 854 } 855 return 0; 856 abort: 857 if (wait) 858 panic("pk_fragment null mbuf after wait"); 859 if (next) 860 m_freem(next); 861 for (m = head; m; m = next) { 862 next = m -> m_act; 863 m_freem(m); 864 } 865 return ENOBUFS; 866 } 867 868 struct mbuf * 869 m_split(m0, len0, wait) 870 register struct mbuf *m0; 871 int len0; 872 { 873 register struct mbuf *m, *n; 874 unsigned len = len0; 875 876 for (m = m0; m && len > m -> m_len; m = m -> m_next) 877 len -= m -> m_len; 878 if (m == 0) 879 return (0); 880 if (m0 -> m_flags & M_PKTHDR) { 881 MGETHDR(n, wait, m0 -> m_type); 882 if (n == 0) 883 return (0); 884 n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif; 885 n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0; 886 m0 -> m_pkthdr.len = len0; 887 if (m -> m_flags & M_EXT) 888 goto extpacket; 889 if (len > MHLEN) { 890 /* m can't be the lead packet */ 891 MH_ALIGN(n, 0); 892 n -> m_next = m_split(m, len, wait); 893 if (n -> m_next == 0) { 894 (void) m_free(n); 895 return (0); 896 } else 897 return (n); 898 } else 899 MH_ALIGN(n, len); 900 } else if (len == m -> m_len) { 901 n = m -> m_next; 902 m -> m_next = 0; 903 return (n); 904 } 905 extpacket: 906 len = m -> m_len - len; /* remainder to be copied */ 907 m -> m_len -= len; /* now equals original len */ 908 if (m -> m>flags & M_EXT) { 909 n -> m_flags |= M_EXT; 910 n -> m_ext = m -> m_ext; 911 mclrefcnt[mtocl(m -> m_ext.ext_buf)]++; 912 n -> m_data = m -> m_data + m -> m_len; 913 } else { 914 MGET(n, wait, m -> m_type); 915 if (n == 0) { 916 m -> m_len += len; 917 return (0); 918 } 919 M_ALIGN(n, len); 920 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), len); 921 } 922 n -> m_len = len; 923 n -> m_next = m -> m_next; 924 m -> m_next = 0; 925 return (n); 926 } 927