|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) University of British Columbia, 1984 ! 24: * Copyright (C) Computer Science Department IV, ! 25: * University of Erlangen-Nuremberg, Germany, 1992 ! 26: * Copyright (c) 1991, 1992, 1993 ! 27: * The Regents of the University of California. All rights reserved. ! 28: * ! 29: * This code is derived from software contributed to Berkeley by the ! 30: * Laboratory for Computation Vision and the Computer Science Department ! 31: * of the the University of British Columbia and the Computer Science ! 32: * Department (IV) of the University of Erlangen-Nuremberg, Germany. ! 33: * ! 34: * Redistribution and use in source and binary forms, with or without ! 35: * modification, are permitted provided that the following conditions ! 36: * are met: ! 37: * 1. Redistributions of source code must retain the above copyright ! 38: * notice, this list of conditions and the following disclaimer. ! 39: * 2. Redistributions in binary form must reproduce the above copyright ! 40: * notice, this list of conditions and the following disclaimer in the ! 41: * documentation and/or other materials provided with the distribution. ! 42: * 3. All advertising materials mentioning features or use of this software ! 43: * must display the following acknowledgement: ! 44: * This product includes software developed by the University of ! 45: * California, Berkeley and its contributors. ! 46: * 4. Neither the name of the University nor the names of its contributors ! 47: * may be used to endorse or promote products derived from this software ! 48: * without specific prior written permission. ! 49: * ! 50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 60: * SUCH DAMAGE. ! 61: * ! 62: * @(#)pk_input.c 8.1 (Berkeley) 6/10/93 ! 63: */ ! 64: ! 65: #include <sys/param.h> ! 66: #include <sys/systm.h> ! 67: #include <sys/mbuf.h> ! 68: #include <sys/socket.h> ! 69: #include <sys/protosw.h> ! 70: #include <sys/socketvar.h> ! 71: #include <sys/errno.h> ! 72: #include <sys/malloc.h> ! 73: ! 74: #include <net/if.h> ! 75: #include <net/if_dl.h> ! 76: #include <net/if_llc.h> ! 77: #include <net/route.h> ! 78: ! 79: #include <netccitt/dll.h> ! 80: #include <netccitt/x25.h> ! 81: #include <netccitt/pk.h> ! 82: #include <netccitt/pk_var.h> ! 83: #include <netccitt/llc_var.h> ! 84: ! 85: struct pkcb_q pkcb_q = {&pkcb_q, &pkcb_q}; ! 86: ! 87: /* ! 88: * ccittintr() is the generic interrupt handler for HDLC, LLC2, and X.25. This ! 89: * allows to have kernel running X.25 but no HDLC or LLC2 or both (in case we ! 90: * employ boards that do all the stuff themselves, e.g. ADAX X.25 or TPS ISDN.) ! 91: */ ! 92: void ! 93: ccittintr () ! 94: { ! 95: extern struct ifqueue pkintrq; ! 96: extern struct ifqueue hdintrq; ! 97: extern struct ifqueue llcintrq; ! 98: ! 99: #if HDLC ! 100: if (hdintrq.ifq_len) ! 101: hdintr (); ! 102: #endif ! 103: #if LLC ! 104: if (llcintrq.ifq_len) ! 105: llcintr (); ! 106: #endif ! 107: if (pkintrq.ifq_len) ! 108: pkintr (); ! 109: } ! 110: ! 111: struct pkcb * ! 112: pk_newlink (ia, llnext) ! 113: struct x25_ifaddr *ia; ! 114: caddr_t llnext; ! 115: { ! 116: register struct x25config *xcp = &ia -> ia_xc; ! 117: register struct pkcb *pkp; ! 118: register struct pklcd *lcp; ! 119: register struct protosw *pp; ! 120: unsigned size; ! 121: ! 122: pp = pffindproto (AF_CCITT, (int) xcp -> xc_lproto, 0); ! 123: if (pp == 0 || pp -> pr_output == 0) { ! 124: pk_message (0, xcp, "link level protosw error"); ! 125: return ((struct pkcb *)0); ! 126: } ! 127: /* ! 128: * Allocate a network control block structure ! 129: */ ! 130: size = sizeof (struct pkcb); ! 131: // pkp = (struct pkcb *) malloc (size, M_PCB, M_WAITOK); ! 132: MALLOC(pkp, struct pkcb *, size, M_PCB, M_WAITOK); ! 133: if (pkp == 0) ! 134: return ((struct pkcb *)0); ! 135: bzero ((caddr_t) pkp, size); ! 136: pkp -> pk_lloutput = pp -> pr_output; ! 137: pkp -> pk_llctlinput = (caddr_t (*)()) pp -> pr_ctlinput; ! 138: pkp -> pk_xcp = xcp; ! 139: pkp -> pk_ia = ia; ! 140: pkp -> pk_state = DTE_WAITING; ! 141: pkp -> pk_llnext = llnext; ! 142: insque (pkp, &pkcb_q); ! 143: ! 144: /* ! 145: * set defaults ! 146: */ ! 147: ! 148: if (xcp -> xc_pwsize == 0) ! 149: xcp -> xc_pwsize = DEFAULT_WINDOW_SIZE; ! 150: if (xcp -> xc_psize == 0) ! 151: xcp -> xc_psize = X25_PS128; ! 152: /* ! 153: * Allocate logical channel descriptor vector ! 154: */ ! 155: ! 156: (void) pk_resize (pkp); ! 157: return (pkp); ! 158: } ! 159: ! 160: ! 161: pk_dellink (pkp) ! 162: register struct pkcb *pkp; ! 163: { ! 164: register int i; ! 165: register struct protosw *pp; ! 166: ! 167: /* ! 168: * Essentially we have the choice to ! 169: * (a) go ahead and let the route be deleted and ! 170: * leave the pkcb associated with that route ! 171: * as it is, i.e. the connections stay open ! 172: * (b) do a pk_disconnect() on all channels associated ! 173: * with the route via the pkcb and then proceed. ! 174: * ! 175: * For the time being we stick with (b) ! 176: */ ! 177: ! 178: for (i = 1; i < pkp -> pk_maxlcn; ++i) ! 179: if (pkp -> pk_chan[i]) ! 180: pk_disconnect (pkp -> pk_chan[i]); ! 181: ! 182: /* ! 183: * Free the pkcb ! 184: */ ! 185: ! 186: /* ! 187: * First find the protoswitch to get hold of the link level ! 188: * protocol to be notified that the packet level entity is ! 189: * dissolving ... ! 190: */ ! 191: pp = pffindproto (AF_CCITT, (int) pkp -> pk_xcp -> xc_lproto, 0); ! 192: if (pp == 0 || pp -> pr_output == 0) { ! 193: pk_message (0, pkp -> pk_xcp, "link level protosw error"); ! 194: return (EPROTONOSUPPORT); ! 195: } ! 196: ! 197: pkp -> pk_refcount--; ! 198: if (!pkp -> pk_refcount) { ! 199: struct dll_ctlinfo ctlinfo; ! 200: ! 201: remque (pkp); ! 202: if (pkp -> pk_rt -> rt_llinfo == (caddr_t) pkp) ! 203: pkp -> pk_rt -> rt_llinfo = (caddr_t) NULL; ! 204: ! 205: /* ! 206: * Tell the link level that the pkcb is dissolving ! 207: */ ! 208: if (pp -> pr_ctlinput && pkp -> pk_llnext) { ! 209: ctlinfo.dlcti_pcb = pkp -> pk_llnext; ! 210: ctlinfo.dlcti_rt = pkp -> pk_rt; ! 211: (pp -> pr_ctlinput)(PRC_DISCONNECT_REQUEST, ! 212: pkp -> pk_xcp, &ctlinfo); ! 213: } ! 214: FREE((caddr_t) pkp -> pk_chan, M_IFADDR); ! 215: FREE((caddr_t) pkp, M_PCB); ! 216: } ! 217: ! 218: return (0); ! 219: } ! 220: ! 221: ! 222: pk_resize (pkp) ! 223: register struct pkcb *pkp; ! 224: { ! 225: struct pklcd *dev_lcp = 0; ! 226: struct x25config *xcp = pkp -> pk_xcp; ! 227: if (pkp -> pk_chan && ! 228: (pkp -> pk_maxlcn != xcp -> xc_maxlcn)) { ! 229: pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); ! 230: dev_lcp = pkp -> pk_chan[0]; ! 231: FREE((caddr_t) pkp -> pk_chan, M_IFADDR); ! 232: pkp -> pk_chan = 0; ! 233: } ! 234: if (pkp -> pk_chan == 0) { ! 235: unsigned size; ! 236: pkp -> pk_maxlcn = xcp -> xc_maxlcn; ! 237: size = (pkp -> pk_maxlcn + 1) * sizeof (struct pklcd *); ! 238: // pkp -> pk_chan = ! 239: // (struct pklcd **) malloc (size, M_IFADDR, M_WAITOK); ! 240: MALLOC(pkp->pk_chan, struct pklcd **, size, M_IFADDR, M_WAITOK); ! 241: if (pkp -> pk_chan) { ! 242: bzero ((caddr_t) pkp -> pk_chan, size); ! 243: /* ! 244: * Allocate a logical channel descriptor for lcn 0 ! 245: */ ! 246: if (dev_lcp == 0 && ! 247: (dev_lcp = pk_attach ((struct socket *)0)) == 0) ! 248: return (ENOBUFS); ! 249: dev_lcp -> lcd_state = READY; ! 250: dev_lcp -> lcd_pkp = pkp; ! 251: pkp -> pk_chan[0] = dev_lcp; ! 252: } else { ! 253: if (dev_lcp) ! 254: pk_close (dev_lcp); ! 255: return (ENOBUFS); ! 256: } ! 257: } ! 258: return 0; ! 259: } ! 260: ! 261: /* ! 262: * This procedure is called by the link level whenever the link ! 263: * becomes operational, is reset, or when the link goes down. ! 264: */ ! 265: /*VARARGS*/ ! 266: caddr_t ! 267: pk_ctlinput (code, src, addr) ! 268: int code; ! 269: struct sockaddr *src; ! 270: caddr_t addr; ! 271: { ! 272: register struct pkcb *pkp = (struct pkcb *) addr; ! 273: ! 274: switch (code) { ! 275: case PRC_LINKUP: ! 276: if (pkp -> pk_state == DTE_WAITING) ! 277: pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); ! 278: break; ! 279: ! 280: case PRC_LINKDOWN: ! 281: pk_restart (pkp, -1); /* Clear all active circuits */ ! 282: pkp -> pk_state = DTE_WAITING; ! 283: break; ! 284: ! 285: case PRC_LINKRESET: ! 286: pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); ! 287: break; ! 288: ! 289: case PRC_CONNECT_INDICATION: { ! 290: struct rtentry *llrt; ! 291: ! 292: if ((llrt = rtalloc1(src, 0)) == 0) ! 293: return 0; ! 294: else llrt -> rt_refcnt--; ! 295: ! 296: pkp = (((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt) ? ! 297: (struct pkcb *)(((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt -> rt_llinfo) : (struct pkcb *) 0; ! 298: if (pkp == (struct pkcb *) 0) ! 299: return 0; ! 300: pkp -> pk_llnext = addr; ! 301: ! 302: return ((caddr_t) pkp); ! 303: } ! 304: case PRC_DISCONNECT_INDICATION: ! 305: pk_restart (pkp, -1) ; /* Clear all active circuits */ ! 306: pkp -> pk_state = DTE_WAITING; ! 307: pkp -> pk_llnext = (caddr_t) 0; ! 308: } ! 309: return (0); ! 310: } ! 311: struct ifqueue pkintrq; ! 312: /* ! 313: * This routine is called if there are semi-smart devices that do HDLC ! 314: * in hardware and want to queue the packet and call level 3 directly ! 315: */ ! 316: pkintr () ! 317: { ! 318: register struct mbuf *m; ! 319: register struct ifaddr *ifa; ! 320: register struct ifnet *ifp; ! 321: register int s; ! 322: ! 323: for (;;) { ! 324: s = splimp (); ! 325: IF_DEQUEUE (&pkintrq, m); ! 326: splx (s); ! 327: if (m == 0) ! 328: break; ! 329: if (m -> m_len < PKHEADERLN) { ! 330: printf ("pkintr: packet too short (len=%d)\n", ! 331: m -> m_len); ! 332: m_freem (m); ! 333: continue; ! 334: } ! 335: pk_input (m); ! 336: } ! 337: } ! 338: struct mbuf *pk_bad_packet; ! 339: struct mbuf_cache pk_input_cache = {0 }; ! 340: /* ! 341: * X.25 PACKET INPUT ! 342: * ! 343: * This procedure is called by a link level procedure whenever ! 344: * an information frame is received. It decodes the packet and ! 345: * demultiplexes based on the logical channel number. ! 346: * ! 347: * We change the original conventions of the UBC code here -- ! 348: * since there may be multiple pkcb's for a given interface ! 349: * of type 802.2 class 2, we retrieve which one it is from ! 350: * m_pkthdr.rcvif (which has been overwritten by lower layers); ! 351: * That field is then restored for the benefit of upper layers which ! 352: * may make use of it, such as CLNP. ! 353: * ! 354: */ ! 355: ! 356: #define RESTART_DTE_ORIGINATED(xp) (((xp) -> packet_cause == X25_RESTART_DTE_ORIGINATED) || \ ! 357: ((xp) -> packet_cause >= X25_RESTART_DTE_ORIGINATED2)) ! 358: ! 359: pk_input (m) ! 360: register struct mbuf *m; ! 361: { ! 362: register struct x25_packet *xp; ! 363: register struct pklcd *lcp; ! 364: register struct socket *so = 0; ! 365: register struct pkcb *pkp; ! 366: int ptype, lcn, lcdstate = LISTEN; ! 367: ! 368: if (pk_input_cache.mbc_size || pk_input_cache.mbc_oldsize) ! 369: mbuf_cache (&pk_input_cache, m); ! 370: if ((m -> m_flags & M_PKTHDR) == 0) ! 371: panic ("pkintr"); ! 372: ! 373: if ((pkp = (struct pkcb *) m -> m_pkthdr.rcvif) == 0) ! 374: return; ! 375: xp = mtod (m, struct x25_packet *); ! 376: ptype = pk_decode (xp); ! 377: lcn = LCN(xp); ! 378: lcp = pkp -> pk_chan[lcn]; ! 379: ! 380: /* ! 381: * If the DTE is in Restart state, then it will ignore data, ! 382: * interrupt, call setup and clearing, flow control and reset ! 383: * packets. ! 384: */ ! 385: if (lcn < 0 || lcn > pkp -> pk_maxlcn) { ! 386: pk_message (lcn, pkp -> pk_xcp, "illegal lcn"); ! 387: m_freem (m); ! 388: return; ! 389: } ! 390: ! 391: pk_trace (pkp -> pk_xcp, m, "P-In"); ! 392: ! 393: if (pkp -> pk_state != DTE_READY && ptype != RESTART && ptype != RESTART_CONF) { ! 394: m_freem (m); ! 395: return; ! 396: } ! 397: if (lcp) { ! 398: so = lcp -> lcd_so; ! 399: lcdstate = lcp -> lcd_state; ! 400: } else { ! 401: if (ptype == CLEAR) { /* idle line probe (Datapac specific) */ ! 402: /* send response on lcd 0's output queue */ ! 403: lcp = pkp -> pk_chan[0]; ! 404: lcp -> lcd_template = pk_template (lcn, X25_CLEAR_CONFIRM); ! 405: pk_output (lcp); ! 406: m_freem (m); ! 407: return; ! 408: } ! 409: if (ptype != CALL) ! 410: ptype = INVALID_PACKET; ! 411: } ! 412: ! 413: if (lcn == 0 && ptype != RESTART && ptype != RESTART_CONF) { ! 414: pk_message (0, pkp -> pk_xcp, "illegal ptype (%d, %s) on lcn 0", ! 415: ptype, pk_name[ptype / MAXSTATES]); ! 416: if (pk_bad_packet) ! 417: m_freem (pk_bad_packet); ! 418: pk_bad_packet = m; ! 419: return; ! 420: } ! 421: ! 422: m -> m_pkthdr.rcvif = pkp -> pk_ia -> ia_ifp; ! 423: ! 424: switch (ptype + lcdstate) { ! 425: /* ! 426: * Incoming Call packet received. ! 427: */ ! 428: case CALL + LISTEN: ! 429: pk_incoming_call (pkp, m); ! 430: break; ! 431: ! 432: /* ! 433: * Call collision: Just throw this "incoming call" away since ! 434: * the DCE will ignore it anyway. ! 435: */ ! 436: case CALL + SENT_CALL: ! 437: pk_message ((int) lcn, pkp -> pk_xcp, ! 438: "incoming call collision"); ! 439: break; ! 440: ! 441: /* ! 442: * Call confirmation packet received. This usually means our ! 443: * previous connect request is now complete. ! 444: */ ! 445: case CALL_ACCEPTED + SENT_CALL: ! 446: MCHTYPE(m, MT_CONTROL); ! 447: pk_call_accepted (lcp, m); ! 448: break; ! 449: ! 450: /* ! 451: * This condition can only happen if the previous state was ! 452: * SENT_CALL. Just ignore the packet, eventually a clear ! 453: * confirmation should arrive. ! 454: */ ! 455: case CALL_ACCEPTED + SENT_CLEAR: ! 456: break; ! 457: ! 458: /* ! 459: * Clear packet received. This requires a complete tear down ! 460: * of the virtual circuit. Free buffers and control blocks. ! 461: * and send a clear confirmation. ! 462: */ ! 463: case CLEAR + READY: ! 464: case CLEAR + RECEIVED_CALL: ! 465: case CLEAR + SENT_CALL: ! 466: case CLEAR + DATA_TRANSFER: ! 467: lcp -> lcd_state = RECEIVED_CLEAR; ! 468: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR_CONFIRM); ! 469: pk_output (lcp); ! 470: pk_clearcause (pkp, xp); ! 471: if (lcp -> lcd_upper) { ! 472: MCHTYPE(m, MT_CONTROL); ! 473: lcp -> lcd_upper (lcp, m); ! 474: } ! 475: pk_close (lcp); ! 476: lcp = 0; ! 477: break; ! 478: ! 479: /* ! 480: * Clear collision: Treat this clear packet as a confirmation. ! 481: */ ! 482: case CLEAR + SENT_CLEAR: ! 483: pk_close (lcp); ! 484: break; ! 485: ! 486: /* ! 487: * Clear confirmation received. This usually means the virtual ! 488: * circuit is now completely removed. ! 489: */ ! 490: case CLEAR_CONF + SENT_CLEAR: ! 491: pk_close (lcp); ! 492: break; ! 493: ! 494: /* ! 495: * A clear confirmation on an unassigned logical channel - just ! 496: * ignore it. Note: All other packets on an unassigned channel ! 497: * results in a clear. ! 498: */ ! 499: case CLEAR_CONF + READY: ! 500: case CLEAR_CONF + LISTEN: ! 501: break; ! 502: ! 503: /* ! 504: * Data packet received. Pass on to next level. Move the Q and M ! 505: * bits into the data portion for the next level. ! 506: */ ! 507: case DATA + DATA_TRANSFER: ! 508: if (lcp -> lcd_reset_condition) { ! 509: ptype = DELETE_PACKET; ! 510: break; ! 511: } ! 512: ! 513: /* ! 514: * Process the P(S) flow control information in this Data packet. ! 515: * Check that the packets arrive in the correct sequence and that ! 516: * they are within the "lcd_input_window". Input window rotation is ! 517: * initiated by the receive interface. ! 518: */ ! 519: ! 520: if (PS(xp) != ((lcp -> lcd_rsn + 1) % MODULUS) || ! 521: PS(xp) == ((lcp -> lcd_input_window + lcp -> lcd_windowsize) % MODULUS)) { ! 522: m_freem (m); ! 523: pk_procerror (RESET, lcp, "p(s) flow control error", 1); ! 524: break; ! 525: } ! 526: lcp -> lcd_rsn = PS(xp); ! 527: ! 528: if (pk_ack (lcp, PR(xp)) != PACKET_OK) { ! 529: m_freem (m); ! 530: break; ! 531: } ! 532: m -> m_data += PKHEADERLN; ! 533: m -> m_len -= PKHEADERLN; ! 534: m -> m_pkthdr.len -= PKHEADERLN; ! 535: ! 536: lcp -> lcd_rxcnt++; ! 537: if (lcp -> lcd_flags & X25_MBS_HOLD) { ! 538: register struct mbuf *n = lcp -> lcd_cps; ! 539: int mbit = MBIT(xp); ! 540: octet q_and_d_bits; ! 541: ! 542: if (n) { ! 543: n -> m_pkthdr.len += m -> m_pkthdr.len; ! 544: while (n -> m_next) ! 545: n = n -> m_next; ! 546: n -> m_next = m; ! 547: m = lcp -> lcd_cps; ! 548: ! 549: if (lcp -> lcd_cpsmax && ! 550: n -> m_pkthdr.len > lcp -> lcd_cpsmax) { ! 551: pk_procerror (RESET, lcp, ! 552: "C.P.S. overflow", 128); ! 553: return; ! 554: } ! 555: q_and_d_bits = 0xc0 & *(octet *) xp; ! 556: xp = (struct x25_packet *) ! 557: (mtod (m, octet *) - PKHEADERLN); ! 558: *(octet *) xp |= q_and_d_bits; ! 559: } ! 560: if (mbit) { ! 561: lcp -> lcd_cps = m; ! 562: pk_flowcontrol (lcp, 0, 1); ! 563: return; ! 564: } ! 565: lcp -> lcd_cps = 0; ! 566: } ! 567: if (so == 0) ! 568: break; ! 569: if (lcp -> lcd_flags & X25_MQBIT) { ! 570: octet t = (X25GBITS(xp -> bits, q_bit)) ? t = 0x80 : 0; ! 571: ! 572: if (MBIT(xp)) ! 573: t |= 0x40; ! 574: m -> m_data -= 1; ! 575: m -> m_len += 1; ! 576: m -> m_pkthdr.len += 1; ! 577: *mtod (m, octet *) = t; ! 578: } ! 579: ! 580: /* ! 581: * Discard Q-BIT packets if the application ! 582: * doesn't want to be informed of M and Q bit status ! 583: */ ! 584: if (X25GBITS(xp -> bits, q_bit) ! 585: && (lcp -> lcd_flags & X25_MQBIT) == 0) { ! 586: m_freem (m); ! 587: /* ! 588: * NB. This is dangerous: sending a RR here can ! 589: * cause sequence number errors if a previous data ! 590: * packet has not yet been passed up to the application ! 591: * (RR's are normally generated via PRU_RCVD). ! 592: */ ! 593: pk_flowcontrol (lcp, 0, 1); ! 594: } else { ! 595: sbappendrecord (&so -> so_rcv, m); ! 596: sorwakeup (so); ! 597: } ! 598: break; ! 599: ! 600: /* ! 601: * Interrupt packet received. ! 602: */ ! 603: case INTERRUPT + DATA_TRANSFER: ! 604: if (lcp -> lcd_reset_condition) ! 605: break; ! 606: lcp -> lcd_intrdata = xp -> packet_data; ! 607: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT_CONFIRM); ! 608: pk_output (lcp); ! 609: m -> m_data += PKHEADERLN; ! 610: m -> m_len -= PKHEADERLN; ! 611: m -> m_pkthdr.len -= PKHEADERLN; ! 612: MCHTYPE(m, MT_OOBDATA); ! 613: if (so) { ! 614: if (so -> so_options & SO_OOBINLINE) ! 615: sbinsertoob (&so -> so_rcv, m); ! 616: else ! 617: m_freem (m); ! 618: sohasoutofband (so); ! 619: } ! 620: break; ! 621: ! 622: /* ! 623: * Interrupt confirmation packet received. ! 624: */ ! 625: case INTERRUPT_CONF + DATA_TRANSFER: ! 626: if (lcp -> lcd_reset_condition) ! 627: break; ! 628: if (lcp -> lcd_intrconf_pending == TRUE) ! 629: lcp -> lcd_intrconf_pending = FALSE; ! 630: else ! 631: pk_procerror (RESET, lcp, "unexpected packet", 43); ! 632: break; ! 633: ! 634: /* ! 635: * Receiver ready received. Rotate the output window and output ! 636: * any data packets waiting transmission. ! 637: */ ! 638: case RR + DATA_TRANSFER: ! 639: if (lcp -> lcd_reset_condition || ! 640: pk_ack (lcp, PR(xp)) != PACKET_OK) { ! 641: ptype = DELETE_PACKET; ! 642: break; ! 643: } ! 644: if (lcp -> lcd_rnr_condition == TRUE) ! 645: lcp -> lcd_rnr_condition = FALSE; ! 646: pk_output (lcp); ! 647: break; ! 648: ! 649: /* ! 650: * Receiver Not Ready received. Packets up to the P(R) can be ! 651: * be sent. Condition is cleared with a RR. ! 652: */ ! 653: case RNR + DATA_TRANSFER: ! 654: if (lcp -> lcd_reset_condition || ! 655: pk_ack (lcp, PR(xp)) != PACKET_OK) { ! 656: ptype = DELETE_PACKET; ! 657: break; ! 658: } ! 659: lcp -> lcd_rnr_condition = TRUE; ! 660: break; ! 661: ! 662: /* ! 663: * Reset packet received. Set state to FLOW_OPEN. The Input and ! 664: * Output window edges ar set to zero. Both the send and receive ! 665: * numbers are reset. A confirmation is returned. ! 666: */ ! 667: case RESET + DATA_TRANSFER: ! 668: if (lcp -> lcd_reset_condition) ! 669: /* Reset collision. Just ignore packet. */ ! 670: break; ! 671: ! 672: pk_resetcause (pkp, xp); ! 673: lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = ! 674: lcp -> lcd_intrconf_pending = FALSE; ! 675: lcp -> lcd_output_window = lcp -> lcd_input_window = ! 676: lcp -> lcd_last_transmitted_pr = 0; ! 677: lcp -> lcd_ssn = 0; ! 678: lcp -> lcd_rsn = MODULUS - 1; ! 679: ! 680: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET_CONFIRM); ! 681: pk_output (lcp); ! 682: ! 683: pk_flush (lcp); ! 684: if (so == 0) ! 685: break; ! 686: wakeup ((caddr_t) & so -> so_timeo); ! 687: sorwakeup (so); ! 688: sowwakeup (so); ! 689: break; ! 690: ! 691: /* ! 692: * Reset confirmation received. ! 693: */ ! 694: case RESET_CONF + DATA_TRANSFER: ! 695: if (lcp -> lcd_reset_condition) { ! 696: lcp -> lcd_reset_condition = FALSE; ! 697: pk_output (lcp); ! 698: } ! 699: else ! 700: pk_procerror (RESET, lcp, "unexpected packet", 32); ! 701: break; ! 702: ! 703: case DATA + SENT_CLEAR: ! 704: ptype = DELETE_PACKET; ! 705: case RR + SENT_CLEAR: ! 706: case RNR + SENT_CLEAR: ! 707: case INTERRUPT + SENT_CLEAR: ! 708: case INTERRUPT_CONF + SENT_CLEAR: ! 709: case RESET + SENT_CLEAR: ! 710: case RESET_CONF + SENT_CLEAR: ! 711: /* Just ignore p if we have sent a CLEAR already. ! 712: */ ! 713: break; ! 714: ! 715: /* ! 716: * Restart sets all the permanent virtual circuits to the "Data ! 717: * Transfer" stae and all the switched virtual circuits to the ! 718: * "Ready" state. ! 719: */ ! 720: case RESTART + READY: ! 721: switch (pkp -> pk_state) { ! 722: case DTE_SENT_RESTART: ! 723: /* ! 724: * Restart collision. ! 725: * If case the restart cause is "DTE originated" we ! 726: * have a DTE-DTE situation and are trying to resolve ! 727: * who is going to play DTE/DCE [ISO 8208:4.2-4.5] ! 728: */ ! 729: if (RESTART_DTE_ORIGINATED(xp)) { ! 730: pk_restart (pkp, X25_RESTART_DTE_ORIGINATED); ! 731: pk_message (0, pkp -> pk_xcp, ! 732: "RESTART collision"); ! 733: if ((pkp -> pk_restartcolls++) > MAXRESTARTCOLLISIONS) { ! 734: pk_message (0, pkp -> pk_xcp, ! 735: "excessive RESTART collisions"); ! 736: pkp -> pk_restartcolls = 0; ! 737: } ! 738: break; ! 739: } ! 740: pkp -> pk_state = DTE_READY; ! 741: pkp -> pk_dxerole |= DTE_PLAYDTE; ! 742: pkp -> pk_dxerole &= ~DTE_PLAYDCE; ! 743: pk_message (0, pkp -> pk_xcp, ! 744: "Packet level operational"); ! 745: pk_message (0, pkp -> pk_xcp, ! 746: "Assuming DTE role"); ! 747: if (pkp -> pk_dxerole & DTE_CONNECTPENDING) ! 748: pk_callcomplete (pkp); ! 749: break; ! 750: ! 751: default: ! 752: pk_restart (pkp, -1); ! 753: pk_restartcause (pkp, xp); ! 754: pkp -> pk_chan[0] -> lcd_template = pk_template (0, ! 755: X25_RESTART_CONFIRM); ! 756: pk_output (pkp -> pk_chan[0]); ! 757: pkp -> pk_state = DTE_READY; ! 758: pkp -> pk_dxerole |= RESTART_DTE_ORIGINATED(xp) ? DTE_PLAYDCE : ! 759: DTE_PLAYDTE; ! 760: if (pkp -> pk_dxerole & DTE_PLAYDTE) { ! 761: pkp -> pk_dxerole &= ~DTE_PLAYDCE; ! 762: pk_message (0, pkp -> pk_xcp, ! 763: "Assuming DTE role"); ! 764: } else { ! 765: pkp -> pk_dxerole &= ~DTE_PLAYDTE; ! 766: pk_message (0, pkp -> pk_xcp, ! 767: "Assuming DCE role"); ! 768: } ! 769: if (pkp -> pk_dxerole & DTE_CONNECTPENDING) ! 770: pk_callcomplete (pkp); ! 771: } ! 772: break; ! 773: ! 774: /* ! 775: * Restart confirmation received. All logical channels are set ! 776: * to READY. ! 777: */ ! 778: case RESTART_CONF + READY: ! 779: switch (pkp -> pk_state) { ! 780: case DTE_SENT_RESTART: ! 781: pkp -> pk_state = DTE_READY; ! 782: pkp -> pk_dxerole |= DTE_PLAYDTE; ! 783: pkp -> pk_dxerole &= ~DTE_PLAYDCE; ! 784: pk_message (0, pkp -> pk_xcp, ! 785: "Packet level operational"); ! 786: pk_message (0, pkp -> pk_xcp, ! 787: "Assuming DTE role"); ! 788: if (pkp -> pk_dxerole & DTE_CONNECTPENDING) ! 789: pk_callcomplete (pkp); ! 790: break; ! 791: ! 792: default: ! 793: /* Restart local procedure error. */ ! 794: pk_restart (pkp, X25_RESTART_LOCAL_PROCEDURE_ERROR); ! 795: pkp -> pk_state = DTE_SENT_RESTART; ! 796: pkp -> pk_dxerole &= ~(DTE_PLAYDTE | DTE_PLAYDCE); ! 797: } ! 798: break; ! 799: ! 800: default: ! 801: if (lcp) { ! 802: pk_procerror (CLEAR, lcp, "unknown packet error", 33); ! 803: pk_message (lcn, pkp -> pk_xcp, ! 804: "\"%s\" unexpected in \"%s\" state", ! 805: pk_name[ptype/MAXSTATES], pk_state[lcdstate]); ! 806: } else ! 807: pk_message (lcn, pkp -> pk_xcp, ! 808: "packet arrived on unassigned lcn"); ! 809: break; ! 810: } ! 811: if (so == 0 && lcp && lcp -> lcd_upper && lcdstate == DATA_TRANSFER) { ! 812: if (ptype != DATA && ptype != INTERRUPT) ! 813: MCHTYPE(m, MT_CONTROL); ! 814: lcp -> lcd_upper (lcp, m); ! 815: } else if (ptype != DATA && ptype != INTERRUPT) ! 816: m_freem (m); ! 817: } ! 818: ! 819: static ! 820: prune_dnic (from, to, dnicname, xcp) ! 821: char *from, *to, *dnicname; ! 822: register struct x25config *xcp; ! 823: { ! 824: register char *cp1 = from, *cp2 = from; ! 825: if (xcp -> xc_prepnd0 && *cp1 == '0') { ! 826: from = ++cp1; ! 827: goto copyrest; ! 828: } ! 829: if (xcp -> xc_nodnic) { ! 830: for (cp1 = dnicname; *cp2 = *cp1++;) ! 831: cp2++; ! 832: cp1 = from; ! 833: } ! 834: copyrest: ! 835: for (cp1 = dnicname; *cp2 = *cp1++;) ! 836: cp2++; ! 837: } ! 838: /* static */ ! 839: pk_simple_bsd (from, to, lower, len) ! 840: register octet *from, *to; ! 841: register len, lower; ! 842: { ! 843: register int c; ! 844: while (--len >= 0) { ! 845: c = *from; ! 846: if (lower & 0x01) ! 847: *from++; ! 848: else ! 849: c >>= 4; ! 850: c &= 0x0f; c |= 0x30; *to++ = c; lower++; ! 851: } ! 852: *to = 0; ! 853: } ! 854: ! 855: /*static octet * */ ! 856: pk_from_bcd (a, iscalling, sa, xcp) ! 857: register struct x25_calladdr *a; ! 858: int iscalling; ! 859: register struct sockaddr_x25 *sa; ! 860: register struct x25config *xcp; ! 861: { ! 862: octet buf[MAXADDRLN+1]; ! 863: octet *cp; ! 864: unsigned count; ! 865: ! 866: bzero ((caddr_t) sa, sizeof (*sa)); ! 867: sa -> x25_len = sizeof (*sa); ! 868: sa -> x25_family = AF_CCITT; ! 869: if (iscalling) { ! 870: cp = a -> address_field + (X25GBITS(a -> addrlens, called_addrlen) / 2); ! 871: count = X25GBITS(a -> addrlens, calling_addrlen); ! 872: pk_simple_bsd (cp, buf, X25GBITS(a -> addrlens, called_addrlen), count); ! 873: } else { ! 874: count = X25GBITS(a -> addrlens, called_addrlen); ! 875: pk_simple_bsd (a -> address_field, buf, 0, count); ! 876: } ! 877: if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { ! 878: octet dnicname[sizeof (long) * NBBY/3 + 2]; ! 879: ! 880: sprintf ((char *) dnicname, "%d", xcp -> xc_addr.x25_net); ! 881: prune_dnic ((char *) buf, sa -> x25_addr, dnicname, xcp); ! 882: } else ! 883: bcopy ((caddr_t) buf, (caddr_t) sa -> x25_addr, count + 1); ! 884: } ! 885: ! 886: static ! 887: save_extra (m0, fp, so) ! 888: struct mbuf *m0; ! 889: octet *fp; ! 890: struct socket *so; ! 891: { ! 892: register struct mbuf *m; ! 893: struct cmsghdr cmsghdr; ! 894: if (m = m_copy (m, 0, (int)M_COPYALL)) { ! 895: int off = fp - mtod (m0, octet *); ! 896: int len = m -> m_pkthdr.len - off + sizeof (cmsghdr); ! 897: cmsghdr.cmsg_len = len; ! 898: cmsghdr.cmsg_level = AF_CCITT; ! 899: cmsghdr.cmsg_type = PK_FACILITIES; ! 900: m_adj (m, off); ! 901: M_PREPEND (m, sizeof (cmsghdr), M_DONTWAIT); ! 902: if (m == 0) ! 903: return; ! 904: bcopy ((caddr_t)&cmsghdr, mtod (m, caddr_t), sizeof (cmsghdr)); ! 905: MCHTYPE(m, MT_CONTROL); ! 906: sbappendrecord (&so -> so_rcv, m); ! 907: } ! 908: } ! 909: ! 910: /* ! 911: * This routine handles incoming call packets. It matches the protocol ! 912: * field on the Call User Data field (usually the first four bytes) with ! 913: * sockets awaiting connections. ! 914: */ ! 915: ! 916: pk_incoming_call (pkp, m0) ! 917: struct mbuf *m0; ! 918: struct pkcb *pkp; ! 919: { ! 920: register struct pklcd *lcp = 0, *l; ! 921: register struct sockaddr_x25 *sa; ! 922: register struct x25_calladdr *a; ! 923: register struct socket *so = 0; ! 924: struct x25_packet *xp = mtod (m0, struct x25_packet *); ! 925: struct mbuf *m; ! 926: struct x25config *xcp = pkp -> pk_xcp; ! 927: int len = m0 -> m_pkthdr.len; ! 928: int udlen; ! 929: char *errstr = "server unavailable"; ! 930: octet *u, *facp; ! 931: int lcn = LCN(xp); ! 932: ! 933: /* First, copy the data from the incoming call packet to a X25 address ! 934: descriptor. It is to be regretted that you have ! 935: to parse the facilities into a sockaddr to determine ! 936: if reverse charging is being requested */ ! 937: if ((m = m_get (M_DONTWAIT, MT_SONAME)) == 0) ! 938: return; ! 939: sa = mtod (m, struct sockaddr_x25 *); ! 940: a = (struct x25_calladdr *) &xp -> packet_data; ! 941: facp = u = (octet *) (a -> address_field + ! 942: ((X25GBITS(a -> addrlens, called_addrlen) + X25GBITS(a -> addrlens, calling_addrlen) + 1) / 2)); ! 943: u += *u + 1; ! 944: udlen = min (16, ((octet *) xp) + len - u); ! 945: if (udlen < 0) ! 946: udlen = 0; ! 947: pk_from_bcd (a, 1, sa, pkp -> pk_xcp); /* get calling address */ ! 948: pk_parse_facilities (facp, sa); ! 949: bcopy ((caddr_t) u, sa -> x25_udata, udlen); ! 950: sa -> x25_udlen = udlen; ! 951: ! 952: /* ! 953: * Now, loop through the listen sockets looking for a match on the ! 954: * PID. That is the first few octets of the user data field. ! 955: * This is the closest thing to a port number for X.25 packets. ! 956: * It does provide a way of multiplexing services at the user level. ! 957: */ ! 958: ! 959: for (l = pk_listenhead; l; l = l -> lcd_listen) { ! 960: struct sockaddr_x25 *sxp = l -> lcd_ceaddr; ! 961: ! 962: if (bcmp (sxp -> x25_udata, u, sxp -> x25_udlen)) ! 963: continue; ! 964: if (sxp -> x25_net && ! 965: sxp -> x25_net != xcp -> xc_addr.x25_net) ! 966: continue; ! 967: /* ! 968: * don't accept incoming calls with the D-Bit on ! 969: * unless the server agrees ! 970: */ ! 971: if (X25GBITS(xp -> bits, d_bit) && !(sxp -> x25_opts.op_flags & X25_DBIT)) { ! 972: errstr = "incoming D-Bit mismatch"; ! 973: break; ! 974: } ! 975: /* ! 976: * don't accept incoming collect calls unless ! 977: * the server sets the reverse charging option. ! 978: */ ! 979: if ((sxp -> x25_opts.op_flags & (X25_OLDSOCKADDR|X25_REVERSE_CHARGE)) == 0 && ! 980: sa -> x25_opts.op_flags & X25_REVERSE_CHARGE) { ! 981: errstr = "incoming collect call refused"; ! 982: break; ! 983: } ! 984: if (l -> lcd_so) { ! 985: if (so = sonewconn (l -> lcd_so, SS_ISCONNECTED)) ! 986: lcp = (struct pklcd *) so -> so_pcb; ! 987: } else ! 988: lcp = pk_attach ((struct socket *) 0); ! 989: if (lcp == 0) { ! 990: /* ! 991: * Insufficient space or too many unaccepted ! 992: * connections. Just throw the call away. ! 993: */ ! 994: errstr = "server malfunction"; ! 995: break; ! 996: } ! 997: lcp -> lcd_upper = l -> lcd_upper; ! 998: lcp -> lcd_upnext = l -> lcd_upnext; ! 999: lcp -> lcd_lcn = lcn; ! 1000: lcp -> lcd_state = RECEIVED_CALL; ! 1001: sa -> x25_opts.op_flags |= (sxp -> x25_opts.op_flags & ! 1002: ~X25_REVERSE_CHARGE) | l -> lcd_flags; ! 1003: pk_assoc (pkp, lcp, sa); ! 1004: lcp -> lcd_faddr = *sa; ! 1005: lcp -> lcd_laddr.x25_udlen = sxp -> x25_udlen; ! 1006: lcp -> lcd_craddr = &lcp -> lcd_faddr; ! 1007: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL_ACCEPTED); ! 1008: if (lcp -> lcd_flags & X25_DBIT) { ! 1009: if (X25GBITS(xp -> bits, d_bit)) ! 1010: X25SBITS(mtod (lcp -> lcd_template, ! 1011: struct x25_packet *) -> bits, d_bit, 1); ! 1012: else ! 1013: lcp -> lcd_flags &= ~X25_DBIT; ! 1014: } ! 1015: if (so) { ! 1016: pk_output (lcp); ! 1017: soisconnected (so); ! 1018: if (so -> so_options & SO_OOBINLINE) ! 1019: save_extra (m0, facp, so); ! 1020: } else if (lcp -> lcd_upper) { ! 1021: (*lcp -> lcd_upper) (lcp, m0); ! 1022: } ! 1023: (void) m_free (m); ! 1024: return; ! 1025: } ! 1026: ! 1027: /* ! 1028: * If the call fails for whatever reason, we still need to build a ! 1029: * skeleton LCD in order to be able to properly receive the CLEAR ! 1030: * CONFIRMATION. ! 1031: */ ! 1032: #ifdef WATERLOO /* be explicit */ ! 1033: if (l == 0 && bcmp (sa -> x25_udata, "ean", 3) == 0) ! 1034: pk_message (lcn, pkp -> pk_xcp, "host=%s ean%c: %s", ! 1035: sa -> x25_addr, sa -> x25_udata[3] & 0xff, errstr); ! 1036: else if (l == 0 && bcmp (sa -> x25_udata, "\1\0\0\0", 4) == 0) ! 1037: pk_message (lcn, pkp -> pk_xcp, "host=%s x29d: %s", ! 1038: sa -> x25_addr, errstr); ! 1039: else ! 1040: #endif ! 1041: pk_message (lcn, pkp -> pk_xcp, "host=%s pid=%x %x %x %x: %s", ! 1042: sa -> x25_addr, sa -> x25_udata[0] & 0xff, ! 1043: sa -> x25_udata[1] & 0xff, sa -> x25_udata[2] & 0xff, ! 1044: sa -> x25_udata[3] & 0xff, errstr); ! 1045: if ((lcp = pk_attach ((struct socket *)0)) == 0) { ! 1046: (void) m_free (m); ! 1047: return; ! 1048: } ! 1049: lcp -> lcd_lcn = lcn; ! 1050: lcp -> lcd_state = RECEIVED_CALL; ! 1051: pk_assoc (pkp, lcp, sa); ! 1052: (void) m_free (m); ! 1053: pk_clear (lcp, 0, 1); ! 1054: } ! 1055: ! 1056: pk_call_accepted (lcp, m) ! 1057: struct pklcd *lcp; ! 1058: struct mbuf *m; ! 1059: { ! 1060: register struct x25_calladdr *ap; ! 1061: register octet *fcp; ! 1062: struct x25_packet *xp = mtod (m, struct x25_packet *); ! 1063: int len = m -> m_len; ! 1064: ! 1065: lcp -> lcd_state = DATA_TRANSFER; ! 1066: if (lcp -> lcd_so) ! 1067: soisconnected (lcp -> lcd_so); ! 1068: if ((lcp -> lcd_flags & X25_DBIT) && (X25GBITS(xp -> bits, d_bit) == 0)) ! 1069: lcp -> lcd_flags &= ~X25_DBIT; ! 1070: if (len > 3) { ! 1071: ap = (struct x25_calladdr *) &xp -> packet_data; ! 1072: fcp = (octet *) ap -> address_field + (X25GBITS(ap -> addrlens, calling_addrlen) + ! 1073: X25GBITS(ap -> addrlens, called_addrlen) + 1) / 2; ! 1074: if (fcp + *fcp <= ((octet *) xp) + len) ! 1075: pk_parse_facilities (fcp, lcp -> lcd_ceaddr); ! 1076: } ! 1077: pk_assoc (lcp -> lcd_pkp, lcp, lcp -> lcd_ceaddr); ! 1078: if (lcp -> lcd_so == 0 && lcp -> lcd_upper) ! 1079: lcp -> lcd_upper (lcp, m); ! 1080: } ! 1081: ! 1082: pk_parse_facilities (fcp, sa) ! 1083: register octet *fcp; ! 1084: register struct sockaddr_x25 *sa; ! 1085: { ! 1086: register octet *maxfcp; ! 1087: ! 1088: maxfcp = fcp + *fcp; ! 1089: fcp++; ! 1090: while (fcp < maxfcp) { ! 1091: /* ! 1092: * Ignore national DCE or DTE facilities ! 1093: */ ! 1094: if (*fcp == 0 || *fcp == 0xff) ! 1095: break; ! 1096: switch (*fcp) { ! 1097: case FACILITIES_WINDOWSIZE: ! 1098: sa -> x25_opts.op_wsize = fcp[1]; ! 1099: fcp += 3; ! 1100: break; ! 1101: ! 1102: case FACILITIES_PACKETSIZE: ! 1103: sa -> x25_opts.op_psize = fcp[1]; ! 1104: fcp += 3; ! 1105: break; ! 1106: ! 1107: case FACILITIES_THROUGHPUT: ! 1108: sa -> x25_opts.op_speed = fcp[1]; ! 1109: fcp += 2; ! 1110: break; ! 1111: ! 1112: case FACILITIES_REVERSE_CHARGE: ! 1113: if (fcp[1] & 01) ! 1114: sa -> x25_opts.op_flags |= X25_REVERSE_CHARGE; ! 1115: /* ! 1116: * Datapac specific: for a X.25(1976) DTE, bit 2 ! 1117: * indicates a "hi priority" (eg. international) call. ! 1118: */ ! 1119: if (fcp[1] & 02 && sa -> x25_opts.op_psize == 0) ! 1120: sa -> x25_opts.op_psize = X25_PS128; ! 1121: fcp += 2; ! 1122: break; ! 1123: ! 1124: default: ! 1125: /*printf("unknown facility %x, class=%d\n", *fcp, (*fcp & 0xc0) >> 6);*/ ! 1126: switch ((*fcp & 0xc0) >> 6) { ! 1127: case 0: /* class A */ ! 1128: fcp += 2; ! 1129: break; ! 1130: ! 1131: case 1: ! 1132: fcp += 3; ! 1133: break; ! 1134: ! 1135: case 2: ! 1136: fcp += 4; ! 1137: break; ! 1138: ! 1139: case 3: ! 1140: fcp++; ! 1141: fcp += *fcp; ! 1142: } ! 1143: } ! 1144: } ! 1145: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.