1 /* Copyright (c) University of British Columbia, 1984 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/socket.h" 7 #include "../h/protosw.h" 8 #include "../h/socketvar.h" 9 #include "../h/errno.h" 10 11 #include "../net/if.h" 12 13 #include "../netccitt/x25.h" 14 #include "../netccitt/pk.h" 15 #include "../netccitt/pk_var.h" 16 17 struct pkcb * 18 pk_newlink (xcp) 19 struct x25config *xcp; 20 { 21 register struct pkcb *pkp; 22 register struct mbuf *m; 23 register struct pklcd *lcp; 24 register struct protosw *pp; 25 register unsigned size; 26 27 if (xcp -> xc_ntnlen <= 0 || xcp -> xc_ntnlen > sizeof (xcp -> xc_ntn) * 2) 28 return ((struct pkcb *)0); 29 #ifdef BSD4_3 30 pp = pffindproto (AF_CCITT, (int)xcp -> xc_lproto, 0); 31 #else 32 pp = pffindproto (AF_CCITT, (int)xcp -> xc_lproto); 33 #endif 34 if (pp == 0 || pp -> pr_output == 0) { 35 pk_message (0, xcp, "link level protosw error"); 36 return ((struct pkcb *)0); 37 } 38 39 /* 40 * Allocate a network control block structure 41 */ 42 43 size = sizeof (struct pkcb) + xcp->xc_maxlcn * sizeof (struct pklcd *); 44 #ifdef sun 45 if (xcp -> xc_maxlcn < 1 || size > mclbytes) { 46 #else 47 if (xcp -> xc_maxlcn < 1 || size > CLBYTES) { 48 #endif 49 pk_message (0, xcp, "invalid maxlcn"); 50 return ((struct pkcb *)0); 51 } 52 m = m_get (M_DONTWAIT, MT_PCB); 53 if (m == 0) 54 return ((struct pkcb *)0); 55 if (size > MLEN) { 56 #ifdef sun 57 if (mclget (m) == 0) { 58 m_freem (m); 59 return ((struct pkcb *)0); 60 } 61 #else 62 #ifdef BSD4_3 63 MCLGET (m); 64 if (m -> m_len != CLBYTES) { 65 (void) m_free (m); 66 return ((struct pkcb *)0); 67 } 68 #else 69 register struct mbuf *p; 70 71 MCLGET (p, 1); 72 if (p == 0) { 73 m_freem (m); 74 return ((struct pkcb *)0); 75 } 76 m -> m_off = (int)p - (int)m; 77 #endif 78 #endif 79 } 80 pkp = mtod (m, struct pkcb *); 81 bzero ((caddr_t)pkp, size); 82 83 /* 84 * Allocate a logical channel descriptor for lcn 0 85 */ 86 87 m = m_getclr (M_DONTWAIT, MT_PCB); 88 if (m == 0) { 89 m_freem (dtom (pkp)); 90 return ((struct pkcb *)0); 91 } 92 lcp = mtod (m, struct pklcd *); 93 lcp -> lcd_state = READY; 94 lcp -> lcd_pkp = pkp; 95 pkp -> pk_chan[0] = lcp; 96 97 pkp -> pk_output = pp -> pr_output; 98 pkp -> pk_xcp = xcp; 99 pkp -> pk_state = DTE_WAITING; 100 pkp -> pk_maxlcn = xcp -> xc_maxlcn; 101 pkp -> pk_next = pkcbhead; 102 pkcbhead = pkp; 103 104 /* 105 * set defaults 106 */ 107 108 if (xcp -> xc_pwsize == 0) 109 xcp -> xc_pwsize = DEFAULT_WINDOW_SIZE; 110 if (xcp -> xc_psize == 0) 111 xcp -> xc_psize = X25_PS128; 112 return (pkp); 113 } 114 115 /* 116 * This procedure is called by the link level whenever the link 117 * becomes operational, is reset, or when the link goes down. 118 */ 119 120 pk_ctlinput (code, xcp) 121 struct x25config *xcp; 122 { 123 register struct pkcb *pkp; 124 125 for (pkp = pkcbhead; pkp; pkp = pkp -> pk_next) 126 if (pkp -> pk_xcp == xcp) 127 break; 128 129 if (pkp == 0 && (pkp = pk_newlink (xcp)) == 0) 130 return (EINVAL); 131 132 switch (code) { 133 case PRC_LINKUP: 134 if (pkp -> pk_state == DTE_WAITING) 135 pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); 136 break; 137 138 case PRC_LINKDOWN: 139 pk_restart (pkp, -1); /* Clear all active circuits */ 140 pkp -> pk_state = DTE_WAITING; 141 break; 142 143 case PRC_LINKRESET: 144 pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); 145 break; 146 147 } 148 return (0); 149 } 150 151 /* 152 * X.25 PACKET INPUT 153 * 154 * This procedure is called by a link level procedure whenever 155 * an information frame is received. It decodes the packet and 156 * demultiplexes based on the logical channel number. 157 * 158 */ 159 160 pk_input (m, xcp) 161 register struct mbuf *m; 162 struct x25config *xcp; 163 { 164 register struct x25_packet *xp; 165 register struct pklcd *lcp; 166 register struct socket *so = 0; 167 register struct pkcb *pkp; 168 int ptype, lcn, lcdstate = LISTEN; 169 static struct x25config *lastxcp; 170 static struct pkcb *lastpkp; 171 172 if (xcp == lastxcp) 173 pkp = lastpkp; 174 else { 175 for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { 176 if (pkp == 0) { 177 pk_message (0, xcp, "pk_input: unknown network"); 178 m_freem (m); 179 return; 180 } 181 if (pkp -> pk_xcp == xcp) 182 break; 183 } 184 lastxcp = xcp; 185 lastpkp = pkp; 186 } 187 188 xp = mtod (m, struct x25_packet *); 189 ptype = pk_decode (xp); 190 lcn = xp -> logical_channel_number; 191 lcp = pkp -> pk_chan[lcn]; 192 193 /* 194 * If the DTE is in Restart state, then it will ignore data, 195 * interrupt, call setup and clearing, flow control and reset 196 * packets. 197 */ 198 if (lcn < 0 || lcn > pkp -> pk_maxlcn) { 199 pk_message (lcn, pkp -> pk_xcp, "illegal lcn"); 200 m_freem (m); 201 return; 202 } 203 204 pk_trace (pkp -> pk_xcp, xp, "P-In"); 205 206 if (pkp -> pk_state != DTE_READY && ptype != RESTART && ptype != RESTART_CONF) { 207 m_freem (m); 208 return; 209 } 210 if (lcp) { 211 so = lcp -> lcd_so; 212 lcdstate = lcp -> lcd_state; 213 } else { 214 if (ptype == CLEAR) { /* idle line probe (Datapac specific) */ 215 /* send response on lcd 0's output queue */ 216 lcp -> lcd_template = pk_template (lcn, X25_CLEAR_CONFIRM); 217 pk_output (lcp); 218 m_freem (m); 219 return; 220 } 221 if (ptype != CALL) 222 ptype = INVALID_PACKET; 223 } 224 225 if (lcn == 0 && ptype != RESTART && ptype != RESTART_CONF) { 226 pk_message (0, pkp -> pk_xcp, "illegal ptype (%s) on lcn 0", 227 pk_name[ptype / MAXSTATES]); 228 m_freem (m); 229 return; 230 } 231 232 switch (ptype + lcdstate) { 233 /* 234 * Incoming Call packet received. 235 */ 236 case CALL + LISTEN: 237 incoming_call (pkp, xp, m -> m_len); 238 break; 239 240 /* 241 * Call collision: Just throw this "incoming call" away since 242 * the DCE will ignore it anyway. 243 */ 244 case CALL + SENT_CALL: 245 pk_message ((int)xp -> logical_channel_number, pkp -> pk_xcp, 246 "incoming call collision"); 247 break; 248 249 /* 250 * Call confirmation packet received. This usually means our 251 * previous connect request is now complete. 252 */ 253 case CALL_ACCEPTED + SENT_CALL: 254 call_accepted (lcp, xp, m -> m_len); 255 break; 256 257 /* 258 * This condition can only happen if the previous state was 259 * SENT_CALL. Just ignore the packet, eventually a clear 260 * confirmation should arrive. 261 */ 262 case CALL_ACCEPTED + SENT_CLEAR: 263 break; 264 265 /* 266 * Clear packet received. This requires a complete tear down 267 * of the virtual circuit. Free buffers and control blocks. 268 * and send a clear confirmation. 269 */ 270 case CLEAR + READY: 271 case CLEAR + RECEIVED_CALL: 272 case CLEAR + SENT_CALL: 273 case CLEAR + DATA_TRANSFER: 274 lcp -> lcd_state = RECEIVED_CLEAR; 275 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR_CONFIRM); 276 pk_output (lcp); 277 pk_clearcause (pkp, xp); 278 pk_close (lcp); 279 break; 280 281 /* 282 * Clear collision: Treat this clear packet as a confirmation. 283 */ 284 case CLEAR + SENT_CLEAR: 285 pk_close (lcp); 286 break; 287 288 /* 289 * Clear confirmation received. This usually means the virtual 290 * circuit is now completely removed. 291 */ 292 case CLEAR_CONF + SENT_CLEAR: 293 pk_close (lcp); 294 break; 295 296 /* 297 * A clear confirmation on an unassigned logical channel - just 298 * ignore it. Note: All other packets on an unassigned channel 299 * results in a clear. 300 */ 301 case CLEAR_CONF + READY: 302 break; 303 304 /* 305 * Data packet received. Pass on to next level. Move the Q and M 306 * bits into the data portion for the next level. 307 */ 308 case DATA + DATA_TRANSFER: 309 if (lcp -> lcd_reset_condition) { 310 ptype = DELETE_PACKET; 311 break; 312 } 313 314 /* 315 * Process the P(S) flow control information in this Data packet. 316 * Check that the packets arrive in the correct sequence and that 317 * they are within the "lcd_input_window". Input window rotation is 318 * initiated by the receive interface. 319 */ 320 321 if (PS(xp) != ((lcp -> lcd_rsn + 1) % MODULUS) || 322 PS(xp) == ((lcp -> lcd_input_window + lcp->lcd_windowsize) % MODULUS)) { 323 m_freem (m); 324 pk_procerror (RESET, lcp, "p(s) flow control error"); 325 break; 326 } 327 lcp -> lcd_rsn = PS(xp); 328 329 if (pk_ack (lcp, PR(xp)) != PACKET_OK) { 330 m_freem (m); 331 break; 332 } 333 334 m -> m_off += PKHEADERLN; 335 m -> m_len -= PKHEADERLN; 336 if (lcp -> lcd_flags & X25_MQBIT) { 337 octet *t; 338 339 m -> m_off -= 1; 340 m -> m_len += 1; 341 t = mtod (m, octet *); 342 *t = 0x00; 343 if (xp -> q_bit) 344 *t |= 0x80; 345 if (MBIT(xp)) 346 *t |= 0x40; 347 } 348 349 /* 350 * Discard Q-BIT packets if the application 351 * doesn't want to be informed of M and Q bit status 352 */ 353 if (xp -> q_bit && (lcp -> lcd_flags & X25_MQBIT) == 0) { 354 m_freem (m); 355 lcp -> lcd_rxcnt++; 356 /* 357 * NB. This is dangerous: sending a RR here can 358 * cause sequence number errors if a previous data 359 * packet has not yet been passed up to the application 360 * (RR's are normally generated via PRU_RCVD). 361 */ 362 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR); 363 pk_output (lcp); 364 } else { 365 #ifdef BSD4_3 366 sbappendrecord (&so -> so_rcv, m); 367 #else 368 sbappend (&so -> so_rcv, m); 369 #endif 370 sorwakeup (so); 371 } 372 break; 373 374 /* 375 * Interrupt packet received. 376 */ 377 case INTERRUPT + DATA_TRANSFER: 378 if (lcp -> lcd_reset_condition) 379 break; 380 lcp -> lcd_intrdata = xp -> packet_data; 381 sohasoutofband (so); 382 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT_CONFIRM); 383 pk_output (lcp); 384 break; 385 386 /* 387 * Interrupt confirmation packet received. 388 */ 389 case INTERRUPT_CONF + DATA_TRANSFER: 390 if (lcp -> lcd_reset_condition) 391 break; 392 if (lcp -> lcd_intrconf_pending == TRUE) 393 lcp -> lcd_intrconf_pending = FALSE; 394 else 395 pk_procerror (RESET, lcp, "unexpected packet"); 396 break; 397 398 /* 399 * Receiver ready received. Rotate the output window and output 400 * any data packets waiting transmission. 401 */ 402 case RR + DATA_TRANSFER: 403 if (lcp -> lcd_reset_condition) 404 break; 405 if (pk_ack (lcp, PR(xp)) != PACKET_OK) 406 break; 407 if (lcp -> lcd_rnr_condition == TRUE) 408 lcp -> lcd_rnr_condition = FALSE; 409 pk_output (lcp); 410 break; 411 412 /* 413 * Receiver Not Ready received. Packets up to the P(R) can be 414 * be sent. Condition is cleared with a RR. 415 */ 416 case RNR + DATA_TRANSFER: 417 if (lcp -> lcd_reset_condition) 418 break; 419 if (pk_ack (lcp, PR(xp)) != PACKET_OK) 420 break; 421 lcp -> lcd_rnr_condition = TRUE; 422 break; 423 424 /* 425 * Reset packet received. Set state to FLOW_OPEN. The Input and 426 * Output window edges ar set to zero. Both the send and receive 427 * numbers are reset. A confirmation is returned. 428 */ 429 case RESET + DATA_TRANSFER: 430 if (lcp -> lcd_reset_condition) 431 /* Reset collision. Just ignore packet. */ 432 break; 433 434 pk_resetcause (pkp, xp); 435 sbflush (&so -> so_snd); 436 sbflush (&so -> so_rcv); 437 438 wakeup ((caddr_t) & so -> so_timeo); 439 sorwakeup (so); 440 sowwakeup (so); 441 442 lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = 443 lcp -> lcd_intrconf_pending = FALSE; 444 lcp -> lcd_output_window = lcp -> lcd_input_window = 445 lcp -> lcd_last_transmitted_pr = 0; 446 lcp -> lcd_ssn = 0; 447 lcp -> lcd_rsn = MODULUS - 1; 448 449 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET_CONFIRM); 450 pk_output (lcp); 451 break; 452 453 /* 454 * Reset confirmation received. 455 */ 456 case RESET_CONF + DATA_TRANSFER: 457 if (lcp -> lcd_reset_condition) { 458 lcp -> lcd_reset_condition = FALSE; 459 pk_output (lcp); 460 } 461 else 462 pk_procerror (RESET, lcp, "unexpected packet"); 463 break; 464 465 case DATA + SENT_CLEAR: 466 ptype = DELETE_PACKET; 467 case RR + SENT_CLEAR: 468 case RNR + SENT_CLEAR: 469 case INTERRUPT + SENT_CLEAR: 470 case INTERRUPT_CONF + SENT_CLEAR: 471 case RESET + SENT_CLEAR: 472 case RESET_CONF + SENT_CLEAR: 473 /* Just ignore packet if we have sent a CLEAR already. 474 */ 475 break; 476 477 /* 478 * Restart sets all the permanent virtual circuits to the "Data 479 * Transfer" stae and all the switched virtual circuits to the 480 * "Ready" state. 481 */ 482 case RESTART + READY: 483 switch (pkp -> pk_state) { 484 case DTE_SENT_RESTART: 485 /* Restart collision. */ 486 pkp -> pk_state = DTE_READY; 487 pk_message (0, pkp -> pk_xcp, 488 "Packet level operational"); 489 break; 490 491 default: 492 pk_restart (pkp, -1); 493 pk_restartcause (pkp, xp); 494 pkp -> pk_chan[0] -> lcd_template = pk_template (0, 495 X25_RESTART_CONFIRM); 496 pk_output (pkp -> pk_chan[0]); 497 } 498 break; 499 500 /* 501 * Restart confirmation received. All logical channels are set 502 * to READY. 503 */ 504 case RESTART_CONF + READY: 505 switch (pkp -> pk_state) { 506 case DTE_SENT_RESTART: 507 pkp -> pk_state = DTE_READY; 508 pk_message (0, pkp -> pk_xcp, 509 "Packet level operational"); 510 break; 511 512 default: 513 /* Restart local procedure error. */ 514 pk_restart (pkp, X25_RESTART_LOCAL_PROCEDURE_ERROR); 515 pkp -> pk_state = DTE_SENT_RESTART; 516 } 517 break; 518 519 default: 520 if (lcp) { 521 pk_procerror (CLEAR, lcp, "unknown packet error"); 522 pk_message (lcn, pkp -> pk_xcp, 523 "\"%s\" unexpected in \"%s\" state", 524 pk_name[ptype/MAXSTATES], pk_state[lcdstate]); 525 } 526 else /* Packets arrived on an unassigned channel. 527 */ 528 pk_message ((int)xp->logical_channel_number, pkp -> pk_xcp, 529 "packet arrived on unassigned lcn"); 530 break; 531 } 532 if (ptype != DATA) 533 m_freem (m); 534 } 535 536 537 /* 538 * This routine handles incoming call packets. It matches the protocol 539 * field on the Call User Data field (usually the first four bytes) with 540 * sockets awaiting connections. 541 */ 542 543 static 544 incoming_call (pkp, xp, len) 545 struct pkcb *pkp; 546 struct x25_packet *xp; 547 { 548 register struct pklcd *lcp, *l; 549 register struct sockaddr_x25 *sa; 550 register struct x25_calladdr *a; 551 register struct socket *so; 552 struct mbuf *m; 553 register int l1, l2; 554 char *e, *errstr = "server unavailable"; 555 octet *u; 556 int lcn = xp -> logical_channel_number; 557 558 /* First, copy the data from the incoming call packet to a X25_socket 559 descriptor. */ 560 561 a = (struct x25_calladdr *) &xp -> packet_data; 562 l1 = a -> calling_addrlen; 563 l2 = a -> called_addrlen; 564 if ((m = m_getclr (M_DONTWAIT, MT_HEADER)) == 0) 565 return; 566 sa = mtod (m, struct sockaddr_x25 *); 567 u = (octet *) (a -> address_field + l2 / 2); 568 e = sa -> x25_addr; 569 if (l2 & 0x01) { 570 *e++ = *u++ & 0x0f; 571 l1--; 572 } 573 from_bcd (e, &u, l1); 574 if (l1 & 0x01) 575 u++; 576 577 parse_facilities (u, sa); 578 u += *u + 1; 579 sa -> x25_udlen = min (16, ((octet *)xp) + len - u); 580 if (sa -> x25_udlen < 0) 581 sa -> x25_udlen = 0; 582 bcopy ((caddr_t)u, sa -> x25_udata, (unsigned)sa -> x25_udlen); 583 584 /* 585 * Now, loop through the listen sockets looking for a match on the 586 * PID. That is the first four octets of the user data field. This 587 * is the closest thing to a port number for X.25 packets. What it 588 * does provide is away of multiplexing services at the user level. 589 */ 590 591 for (l = pk_listenhead; l; l = l -> lcd_listen) { 592 struct sockaddr_x25 *sxp = l -> lcd_ceaddr; 593 594 if (bcmp (sxp -> x25_udata, sa -> x25_udata, sxp->x25_udlen)) 595 continue; 596 if (sxp -> x25_net && sxp -> x25_net != pkp->pk_xcp->xc_net) 597 continue; 598 /* 599 * don't accept incoming collect calls unless 600 * the server sets the reverse charging option. 601 */ 602 if ((sxp -> x25_opts.op_flags & (X25_OLDSOCKADDR|X25_REVERSE_CHARGE)) == 0 && 603 sa -> x25_opts.op_flags & X25_REVERSE_CHARGE) { 604 errstr = "incoming collect call refused"; 605 break; 606 } 607 so = sonewconn (l -> lcd_so); 608 if (so == NULL) { 609 /* 610 * Insufficient space or too many unaccepted 611 * connections. Just throw the call away. 612 */ 613 errstr = "server malfunction"; 614 break; 615 } 616 lcp = (struct pklcd *) so -> so_pcb; 617 lcp -> lcd_lcn = lcn; 618 lcp -> lcd_state = RECEIVED_CALL; 619 lcp -> lcd_craddr = sa; 620 sa -> x25_opts.op_flags |= sxp -> x25_opts.op_flags & 621 ~X25_REVERSE_CHARGE; 622 pk_assoc (pkp, lcp, sa); 623 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL_ACCEPTED); 624 pk_output (lcp); 625 soisconnected (so); 626 return; 627 } 628 629 /* 630 * If the call fails for whatever reason, we still need to build a 631 * skeleton LCD in order to be able to properly receive the CLEAR 632 * CONFIRMATION. 633 */ 634 #ifdef WATERLOO /* be explicit */ 635 if (l == 0 && bcmp(sa->x25_udata, "ean", 3) == 0) 636 pk_message (lcn, pkp -> pk_xcp, "host=%s ean%c: %s", 637 sa->x25_addr, sa->x25_udata[3] & 0xff, errstr); 638 else if (l == 0 && bcmp(sa->x25_udata, "\1\0\0\0", 4) == 0) 639 pk_message (lcn, pkp -> pk_xcp, "host=%s x29d: %s", 640 sa->x25_addr, errstr); 641 else 642 #endif 643 pk_message (lcn, pkp -> pk_xcp, "host=%s pid=%x %x %x %x: %s", 644 sa -> x25_addr, sa -> x25_udata[0] & 0xff, 645 sa -> x25_udata[1] & 0xff, sa -> x25_udata[2] & 0xff, 646 sa -> x25_udata[3] & 0xff, errstr); 647 if ((m = m_getclr (M_DONTWAIT, MT_HEADER)) == 0) { 648 (void) m_free (dtom (sa)); 649 return; 650 } 651 lcp = mtod (m, struct pklcd *); 652 lcp -> lcd_lcn = lcn; 653 lcp -> lcd_state = RECEIVED_CALL; 654 pk_assoc (pkp, lcp, sa); 655 (void) m_free (dtom (sa)); 656 pk_clear (lcp); 657 } 658 659 static 660 call_accepted (lcp, xp, len) 661 struct pklcd *lcp; 662 struct x25_packet *xp; 663 { 664 register struct x25_calladdr *ap; 665 register octet *fcp; 666 667 lcp -> lcd_state = DATA_TRANSFER; 668 soisconnected (lcp -> lcd_so); 669 if (len > 3) { 670 ap = (struct x25_calladdr *) &xp -> packet_data; 671 fcp = (octet *) ap -> address_field + (ap -> calling_addrlen + 672 ap -> called_addrlen + 1) / 2; 673 if (fcp + *fcp <= ((octet *)xp) + len) 674 parse_facilities (fcp, lcp -> lcd_ceaddr); 675 } 676 pk_assoc (lcp -> lcd_pkp, lcp, lcp -> lcd_ceaddr); 677 } 678 679 static 680 parse_facilities (fcp, sa) 681 register octet *fcp; 682 register struct sockaddr_x25 *sa; 683 { 684 register octet *maxfcp; 685 686 maxfcp = fcp + *fcp; 687 fcp++; 688 while (fcp < maxfcp) { 689 /* 690 * Ignore national DCE or DTE facilities 691 */ 692 if (*fcp == 0 || *fcp == 0xff) 693 break; 694 switch (*fcp) { 695 case FACILITIES_WINDOWSIZE: 696 sa -> x25_opts.op_wsize = fcp[1]; 697 fcp += 3; 698 break; 699 700 case FACILITIES_PACKETSIZE: 701 sa -> x25_opts.op_psize = fcp[1]; 702 fcp += 3; 703 break; 704 705 case FACILITIES_THROUGHPUT: 706 sa -> x25_opts.op_speed = fcp[1]; 707 fcp += 2; 708 break; 709 710 case FACILITIES_REVERSE_CHARGE: 711 if (fcp[1] & 01) 712 sa -> x25_opts.op_flags |= X25_REVERSE_CHARGE; 713 /* 714 * Datapac specific: for a X.25(1976) DTE, bit 2 715 * indicates a "hi priority" (eg. international) call. 716 */ 717 if (fcp[1] & 02 && sa -> x25_opts.op_psize == 0) 718 sa -> x25_opts.op_psize = X25_PS128; 719 fcp += 2; 720 break; 721 722 default: 723 /*printf("unknown facility %x, class=%d\n", *fcp, (*fcp & 0xc0) >> 6);*/ 724 switch ((*fcp & 0xc0) >> 6) { 725 case 0: /* class A */ 726 fcp += 2; 727 break; 728 729 case 1: 730 fcp += 3; 731 break; 732 733 case 2: 734 fcp += 4; 735 break; 736 737 case 3: 738 fcp++; 739 fcp += *fcp; 740 } 741 } 742 } 743 } 744 745 from_bcd (a, x, len) 746 register char *a; 747 register octet **x; 748 register int len; 749 { 750 register int posn = 0; 751 752 while (--len >= 0) { 753 if (posn++ & 0x01) 754 *a = *(*x)++ & 0x0f; 755 else 756 *a = (**x >> 4) & 0x0F; 757 *a++ |= 0x30; 758 } 759 } 760