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.6 (Berkeley) 08/30/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 MGET (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 += 4; 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 xp -> logical_channel_number = 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 a = (struct x25_calladdr *) &lcp -> lcd_template -> packet_data; 370 a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr); 371 a -> called_addrlen = strlen (sa -> x25_addr); 372 cp = (octet *) a -> address_field; 373 to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn); 374 to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn); 375 if (posn & 0x01) 376 *cp++ &= 0xf0; 377 378 build_facilities (&cp, sa, (int)xcp -> xc_type); 379 380 bcopy (sa -> x25_udata, (caddr_t)cp, (unsigned)sa -> x25_udlen); 381 cp += sa -> x25_udlen; 382 383 m -> m_len += cp - (octet *) a; 384 385 #ifdef ANDREW 386 printf ("call: "); 387 for (cp = mtod (m, octet *), posn = 0; posn < m->m_len; ++posn) 388 printf ("%x ", *cp++); 389 printf ("\n"); 390 #endif 391 } 392 393 build_facilities (cp, sa, type) 394 register octet **cp; 395 struct sockaddr_x25 *sa; 396 { 397 register octet *fcp; 398 register int revcharge; 399 400 fcp = *cp + 1; 401 revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; 402 /* 403 * This is specific to Datapac X.25(1976) DTEs. International 404 * calls must have the "hi priority" bit on. 405 */ 406 if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) 407 revcharge |= 02; 408 if (revcharge) { 409 *fcp++ = FACILITIES_REVERSE_CHARGE; 410 *fcp++ = revcharge; 411 } 412 switch (type) { 413 case X25_1980: 414 case X25_1984: 415 *fcp++ = FACILITIES_PACKETSIZE; 416 *fcp++ = sa -> x25_opts.op_psize; 417 *fcp++ = sa -> x25_opts.op_psize; 418 419 *fcp++ = FACILITIES_WINDOWSIZE; 420 *fcp++ = sa -> x25_opts.op_wsize; 421 *fcp++ = sa -> x25_opts.op_wsize; 422 } 423 **cp = fcp - *cp - 1; 424 *cp = fcp; 425 } 426 427 to_bcd (a, len, x, posn) 428 register octet **a; 429 register char *x; 430 register int len; 431 register unsigned *posn; 432 { 433 while (--len >= 0) 434 if ((*posn)++ & 0x01) 435 *(*a)++ |= *x++ & 0x0F; 436 else 437 **a = *x++ << 4; 438 } 439 440 /* 441 * This routine gets the first available logical channel number. The 442 * search is from the highest number to lowest number (DTE). 443 */ 444 445 pk_getlcn (pkp) 446 register struct pkcb *pkp; 447 { 448 register int i; 449 450 if (pkp->pk_chan == 0) 451 return (0); 452 for (i = pkp -> pk_maxlcn; i > 0; --i) 453 if (pkp -> pk_chan[i] == NULL) 454 break; 455 return (i); 456 457 } 458 459 static 460 checksockaddr (m) 461 struct mbuf *m; 462 { 463 register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *); 464 register char *cp; 465 466 if (m -> m_len != sizeof (struct sockaddr_x25)) 467 return (1); 468 if (sa -> x25_family != AF_CCITT || sa -> x25_udlen == 0 || 469 sa -> x25_udlen > sizeof (sa -> x25_udata)) 470 return (1); 471 for (cp = sa -> x25_addr; *cp; cp++) { 472 if (*cp < '0' || *cp > '9' || 473 cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1]) 474 return (1); 475 } 476 return (0); 477 } 478 479 /* 480 * This procedure sends a CLEAR request packet. The lc state is 481 * set to "SENT_CLEAR". 482 */ 483 484 pk_clear (lcp) 485 struct pklcd *lcp; 486 { 487 register struct x25_packet *xp; 488 489 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR); 490 (dtom (xp)) -> m_len++; 491 xp -> packet_data = 0; 492 493 pk_output (lcp); 494 495 } 496 497 /* 498 * This procedure sends a RESET request packet. It re-intializes 499 * virtual circuit. 500 */ 501 502 static 503 pk_reset (lcp) 504 register struct pklcd *lcp; 505 { 506 register struct x25_packet *xp; 507 register struct socket *so; 508 509 if (lcp -> lcd_state != DATA_TRANSFER) 510 return; 511 512 lcp -> lcd_reset_condition = TRUE; 513 514 /* Reset all the control variables for the channel. */ 515 lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = 516 lcp -> lcd_intrconf_pending = FALSE; 517 lcp -> lcd_rsn = MODULUS - 1; 518 lcp -> lcd_ssn = 0; 519 lcp -> lcd_output_window = lcp -> lcd_input_window = 520 lcp -> lcd_last_transmitted_pr = 0; 521 if (so = lcp -> lcd_so) { 522 so -> so_error = ECONNRESET; 523 sbflush (&so -> so_rcv); 524 sbflush (&so -> so_snd); 525 } 526 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); 527 (dtom (xp)) -> m_len += 2; 528 xp -> packet_data = 0; 529 pk_output (lcp); 530 531 } 532 533 534 /* 535 * This procedure handles all local protocol procedure errors. 536 */ 537 538 pk_procerror (error, lcp, errstr) 539 register struct pklcd *lcp; 540 char *errstr; 541 { 542 543 pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); 544 545 switch (error) { 546 case CLEAR: 547 if (lcp->lcd_so) { 548 lcp->lcd_so -> so_error = ECONNABORTED; 549 soisdisconnecting (lcp->lcd_so); 550 } 551 pk_clear (lcp); 552 break; 553 554 case RESET: 555 pk_reset (lcp); 556 } 557 } 558 559 /* 560 * This procedure is called during the DATA TRANSFER state to check 561 * and process the P(R) values received in the DATA, RR OR RNR 562 * packets. 563 */ 564 565 pk_ack (lcp, pr) 566 struct pklcd *lcp; 567 unsigned pr; 568 { 569 register struct socket *so = lcp -> lcd_so; 570 571 if (lcp -> lcd_output_window == pr) 572 return (PACKET_OK); 573 if (lcp -> lcd_output_window < lcp -> lcd_ssn) { 574 if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { 575 pk_procerror (RESET, lcp, "p(r) flow control error"); 576 return (ERROR_PACKET); 577 } 578 } 579 else { 580 if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { 581 pk_procerror (RESET, lcp, "p(r) flow control error"); 582 return (ERROR_PACKET); 583 } 584 } 585 586 lcp -> lcd_output_window = pr; /* Rotate window. */ 587 if (lcp -> lcd_window_condition == TRUE) 588 lcp -> lcd_window_condition = FALSE; 589 590 if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel)) 591 sowwakeup (so); 592 if (lcp -> lcd_upper) 593 (*lcp -> lcd_upper)(lcp, 0); 594 595 return (PACKET_OK); 596 } 597 598 /* 599 * This procedure decodes the X.25 level 3 packet returning a 600 * code to be used in switchs or arrays. 601 */ 602 603 pk_decode (xp) 604 register struct x25_packet *xp; 605 { 606 register int type; 607 608 if (xp -> fmt_identifier != 1) 609 return (INVALID_PACKET); 610 611 /* 612 * Make sure that the logical channel group number is 0. 613 * This restriction may be removed at some later date. 614 */ 615 if (xp -> lc_group_number != 0) 616 return (INVALID_PACKET); 617 618 /* 619 * Test for data packet first. 620 */ 621 if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) 622 return (DATA); 623 624 /* 625 * Test if flow control packet (RR or RNR). 626 */ 627 if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) 628 if (!(xp -> packet_type & RR_PACKET_DESIGNATOR)) 629 return (RR); 630 else 631 return (RNR); 632 633 /* 634 * Determine the rest of the packet types. 635 */ 636 switch (xp -> packet_type) { 637 case X25_CALL: 638 type = CALL; 639 break; 640 641 case X25_CALL_ACCEPTED: 642 type = CALL_ACCEPTED; 643 break; 644 645 case X25_CLEAR: 646 type = CLEAR; 647 break; 648 649 case X25_CLEAR_CONFIRM: 650 type = CLEAR_CONF; 651 break; 652 653 case X25_INTERRUPT: 654 type = INTERRUPT; 655 break; 656 657 case X25_INTERRUPT_CONFIRM: 658 type = INTERRUPT_CONF; 659 break; 660 661 case X25_RESET: 662 type = RESET; 663 break; 664 665 case X25_RESET_CONFIRM: 666 type = RESET_CONF; 667 break; 668 669 case X25_RESTART: 670 type = RESTART; 671 break; 672 673 case X25_RESTART_CONFIRM: 674 type = RESTART_CONF; 675 break; 676 677 default: 678 type = INVALID_PACKET; 679 } 680 return (type); 681 } 682 683 /* 684 * A restart packet has been received. Print out the reason 685 * for the restart. 686 */ 687 688 pk_restartcause (pkp, xp) 689 struct pkcb *pkp; 690 register struct x25_packet *xp; 691 { 692 register struct x25config *xcp = pkp -> pk_xcp; 693 register int lcn = xp -> logical_channel_number; 694 695 switch (xp -> packet_data) { 696 case X25_RESTART_LOCAL_PROCEDURE_ERROR: 697 pk_message (lcn, xcp, "restart: local procedure error"); 698 break; 699 700 case X25_RESTART_NETWORK_CONGESTION: 701 pk_message (lcn, xcp, "restart: network congestion"); 702 break; 703 704 case X25_RESTART_NETWORK_OPERATIONAL: 705 pk_message (lcn, xcp, "restart: network operational"); 706 break; 707 708 default: 709 pk_message (lcn, xcp, "restart: unknown cause"); 710 } 711 } 712 713 #define MAXRESETCAUSE 7 714 715 int Reset_cause[] = { 716 EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG 717 }; 718 719 /* 720 * A reset packet has arrived. Return the cause to the user. 721 */ 722 723 pk_resetcause (pkp, xp) 724 struct pkcb *pkp; 725 register struct x25_packet *xp; 726 { 727 register struct pklcd *lcp = pkp->pk_chan[xp -> logical_channel_number]; 728 register int code = xp -> packet_data; 729 730 if (code > MAXRESETCAUSE) 731 code = 7; /* EXRNCG */ 732 733 lcp->lcd_so -> so_error = Reset_cause[code]; 734 } 735 736 #define MAXCLEARCAUSE 25 737 738 int Clear_cause[] = { 739 EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, 740 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, 741 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC 742 }; 743 744 /* 745 * A clear packet has arrived. Return the cause to the user. 746 */ 747 748 pk_clearcause (pkp, xp) 749 struct pkcb *pkp; 750 register struct x25_packet *xp; 751 { 752 register struct pklcd *lcp = pkp->pk_chan[xp -> logical_channel_number]; 753 register int code = xp -> packet_data; 754 755 if (code > MAXCLEARCAUSE) 756 code = 5; /* EXRNCG */ 757 lcp->lcd_so -> so_error = Clear_cause[code]; 758 } 759 760 char * 761 format_ntn (xcp) 762 register struct x25config *xcp; 763 { 764 765 return (xcp -> xc_addr.x25_addr); 766 } 767 768 /* VARARGS1 */ 769 pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) 770 struct x25config *xcp; 771 char *fmt; 772 { 773 774 if (lcn) 775 if (pkcbhead -> pk_next) 776 printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); 777 else 778 printf ("X.25: lcn %d: ", lcn); 779 else 780 if (pkcbhead -> pk_next) 781 printf ("X.25(%s): ", format_ntn (xcp)); 782 else 783 printf ("X.25: "); 784 785 printf (fmt, a1, a2, a3, a4, a5, a6); 786 printf ("\n"); 787 } 788