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