|
|
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_subr.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/time.h> ! 76: #include <sys/kernel.h> ! 77: #include <sys/malloc.h> ! 78: ! 79: #include <net/if.h> ! 80: #include <net/route.h> ! 81: ! 82: #include <netccitt/dll.h> ! 83: #include <netccitt/x25.h> ! 84: #include <netccitt/x25err.h> ! 85: #include <netccitt/pk.h> ! 86: #include <netccitt/pk_var.h> ! 87: ! 88: int pk_sendspace = 1024 * 2 + 8; ! 89: int pk_recvspace = 1024 * 2 + 8; ! 90: ! 91: struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q}; ! 92: ! 93: struct x25bitslice x25_bitslice[] = { ! 94: /* mask, shift value */ ! 95: { 0xf0, 0x4 }, ! 96: { 0xf, 0x0 }, ! 97: { 0x80, 0x7 }, ! 98: { 0x40, 0x6 }, ! 99: { 0x30, 0x4 }, ! 100: { 0xe0, 0x5 }, ! 101: { 0x10, 0x4 }, ! 102: { 0xe, 0x1 }, ! 103: { 0x1, 0x0 } ! 104: }; ! 105: ! 106: ! 107: /* ! 108: * Attach X.25 protocol to socket, allocate logical channel descripter ! 109: * and buffer space, and enter LISTEN state if we are to accept ! 110: * IN-COMMING CALL packets. ! 111: * ! 112: */ ! 113: ! 114: struct pklcd * ! 115: pk_attach (so) ! 116: struct socket *so; ! 117: { ! 118: register struct pklcd *lcp; ! 119: register int error = ENOBUFS; ! 120: int pk_output (); ! 121: ! 122: MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT); ! 123: if (lcp) { ! 124: bzero ((caddr_t)lcp, sizeof (*lcp)); ! 125: insque (&lcp -> lcd_q, &pklcd_q); ! 126: lcp -> lcd_state = READY; ! 127: lcp -> lcd_send = pk_output; ! 128: if (so) { ! 129: error = soreserve (so, pk_sendspace, pk_recvspace); ! 130: lcp -> lcd_so = so; ! 131: if (so -> so_options & SO_ACCEPTCONN) ! 132: lcp -> lcd_state = LISTEN; ! 133: } else ! 134: sbreserve (&lcp -> lcd_sb, pk_sendspace); ! 135: } ! 136: if (so) { ! 137: so -> so_pcb = (caddr_t) lcp; ! 138: so -> so_error = error; ! 139: } ! 140: return (lcp); ! 141: } ! 142: ! 143: /* ! 144: * Disconnect X.25 protocol from socket. ! 145: */ ! 146: ! 147: pk_disconnect (lcp) ! 148: register struct pklcd *lcp; ! 149: { ! 150: register struct socket *so = lcp -> lcd_so; ! 151: register struct pklcd *l, *p; ! 152: ! 153: switch (lcp -> lcd_state) { ! 154: case LISTEN: ! 155: for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); ! 156: if (p == 0) { ! 157: if (l != 0) ! 158: pk_listenhead = l -> lcd_listen; ! 159: } ! 160: else ! 161: if (l != 0) ! 162: p -> lcd_listen = l -> lcd_listen; ! 163: pk_close (lcp); ! 164: break; ! 165: ! 166: case READY: ! 167: pk_acct (lcp); ! 168: pk_close (lcp); ! 169: break; ! 170: ! 171: case SENT_CLEAR: ! 172: case RECEIVED_CLEAR: ! 173: break; ! 174: ! 175: default: ! 176: pk_acct (lcp); ! 177: if (so) { ! 178: soisdisconnecting (so); ! 179: sbflush (&so -> so_rcv); ! 180: } ! 181: pk_clear (lcp, 241, 0); /* Normal Disconnect */ ! 182: ! 183: } ! 184: } ! 185: ! 186: /* ! 187: * Close an X.25 Logical Channel. Discard all space held by the ! 188: * connection and internal descriptors. Wake up any sleepers. ! 189: */ ! 190: ! 191: pk_close (lcp) ! 192: struct pklcd *lcp; ! 193: { ! 194: register struct socket *so = lcp -> lcd_so; ! 195: ! 196: /* ! 197: * If the X.25 connection is torn down due to link ! 198: * level failure (e.g. LLC2 FRMR) and at the same the user ! 199: * level is still filling up the socket send buffer that ! 200: * send buffer is locked. An attempt to sbflush () that send ! 201: * buffer will lead us into - no, not temptation but - panic! ! 202: * So - we'll just check wether the send buffer is locked ! 203: * and if that's the case we'll mark the lcp as zombie and ! 204: * have the pk_timer () do the cleaning ... ! 205: */ ! 206: ! 207: if (so && so -> so_snd.sb_flags & SB_LOCK) ! 208: lcp -> lcd_state = LCN_ZOMBIE; ! 209: else ! 210: pk_freelcd (lcp); ! 211: ! 212: if (so == NULL) ! 213: return; ! 214: ! 215: so -> so_pcb = 0; ! 216: soisdisconnected (so); ! 217: /* sofree (so); /* gak!!! you can't do that here */ ! 218: } ! 219: ! 220: /* ! 221: * Create a template to be used to send X.25 packets on a logical ! 222: * channel. It allocates an mbuf and fills in a skeletal packet ! 223: * depending on its type. This packet is passed to pk_output where ! 224: * the remainer of the packet is filled in. ! 225: */ ! 226: ! 227: struct mbuf * ! 228: pk_template (lcn, type) ! 229: int lcn, type; ! 230: { ! 231: register struct mbuf *m; ! 232: register struct x25_packet *xp; ! 233: ! 234: MGETHDR (m, M_DONTWAIT, MT_HEADER); ! 235: if (m == 0) ! 236: panic ("pk_template"); ! 237: m -> m_act = 0; ! 238: ! 239: /* ! 240: * Efficiency hack: leave a four byte gap at the beginning ! 241: * of the packet level header with the hope that this will ! 242: * be enough room for the link level to insert its header. ! 243: */ ! 244: m -> m_data += max_linkhdr; ! 245: m -> m_pkthdr.len = m -> m_len = PKHEADERLN; ! 246: ! 247: xp = mtod (m, struct x25_packet *); ! 248: *(long *)xp = 0; /* ugly, but fast */ ! 249: /* xp -> q_bit = 0;*/ ! 250: X25SBITS(xp -> bits, fmt_identifier, 1); ! 251: /* xp -> lc_group_number = 0;*/ ! 252: ! 253: SET_LCN(xp, lcn); ! 254: xp -> packet_type = type; ! 255: ! 256: return (m); ! 257: } ! 258: ! 259: /* ! 260: * This routine restarts all the virtual circuits. Actually, ! 261: * the virtual circuits are not "restarted" as such. Instead, ! 262: * any active switched circuit is simply returned to READY ! 263: * state. ! 264: */ ! 265: ! 266: pk_restart (pkp, restart_cause) ! 267: register struct pkcb *pkp; ! 268: int restart_cause; ! 269: { ! 270: register struct mbuf *m; ! 271: register struct pklcd *lcp; ! 272: register int i; ! 273: ! 274: /* Restart all logical channels. */ ! 275: if (pkp -> pk_chan == 0) ! 276: return; ! 277: ! 278: /* ! 279: * Don't do this if we're doing a restart issued from ! 280: * inside pk_connect () --- which is only done if and ! 281: * only if the X.25 link is down, i.e. a RESTART needs ! 282: * to be done to get it up. ! 283: */ ! 284: if (!(pkp -> pk_dxerole & DTE_CONNECTPENDING)) { ! 285: for (i = 1; i <= pkp -> pk_maxlcn; ++i) ! 286: if ((lcp = pkp -> pk_chan[i]) != NULL) { ! 287: if (lcp -> lcd_so) { ! 288: lcp -> lcd_so -> so_error = ENETRESET; ! 289: pk_close (lcp); ! 290: } else { ! 291: pk_flush (lcp); ! 292: lcp -> lcd_state = READY; ! 293: if (lcp -> lcd_upper) ! 294: lcp -> lcd_upper (lcp, 0); ! 295: } ! 296: } ! 297: } ! 298: ! 299: if (restart_cause < 0) ! 300: return; ! 301: ! 302: pkp -> pk_state = DTE_SENT_RESTART; ! 303: pkp -> pk_dxerole &= ~(DTE_PLAYDCE | DTE_PLAYDTE); ! 304: lcp = pkp -> pk_chan[0]; ! 305: m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); ! 306: m -> m_pkthdr.len = m -> m_len += 2; ! 307: mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */ ! 308: mtod (m, octet *)[4] = restart_cause; ! 309: pk_output (lcp); ! 310: } ! 311: ! 312: ! 313: /* ! 314: * This procedure frees up the Logical Channel Descripter. ! 315: */ ! 316: ! 317: pk_freelcd (lcp) ! 318: register struct pklcd *lcp; ! 319: { ! 320: if (lcp == NULL) ! 321: return; ! 322: ! 323: if (lcp -> lcd_lcn > 0) ! 324: lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; ! 325: ! 326: pk_flush (lcp); ! 327: remque (&lcp -> lcd_q); ! 328: free ((caddr_t)lcp, M_PCB); ! 329: } ! 330: ! 331: static struct x25_ifaddr * ! 332: pk_ifwithaddr (sx) ! 333: struct sockaddr_x25 *sx; ! 334: { ! 335: struct ifnet *ifp; ! 336: struct ifaddr *ifa; ! 337: register struct x25_ifaddr *ia; ! 338: char *addr = sx -> x25_addr; ! 339: ! 340: for (ifp = ifnet; ifp; ifp = ifp -> if_next) ! 341: for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next) ! 342: if (ifa -> ifa_addr -> sa_family == AF_CCITT) { ! 343: ia = (struct x25_ifaddr *)ifa; ! 344: if (bcmp (addr, ia -> ia_xc.xc_addr.x25_addr, ! 345: 16) == 0) ! 346: return (ia); ! 347: ! 348: } ! 349: return ((struct x25_ifaddr *)0); ! 350: } ! 351: ! 352: ! 353: /* ! 354: * Bind a address and protocol value to a socket. The important ! 355: * part is the protocol value - the first four characters of the ! 356: * Call User Data field. ! 357: */ ! 358: ! 359: #define XTRACTPKP(rt) ((rt) -> rt_flags & RTF_GATEWAY ? \ ! 360: ((rt) -> rt_llinfo ? \ ! 361: (struct pkcb *) ((struct rtentry *)((rt) -> rt_llinfo)) -> rt_llinfo : \ ! 362: (struct pkcb *) NULL) : \ ! 363: (struct pkcb *)((rt) -> rt_llinfo)) ! 364: ! 365: pk_bind (lcp, nam) ! 366: struct pklcd *lcp; ! 367: struct mbuf *nam; ! 368: { ! 369: register struct pklcd *pp; ! 370: register struct sockaddr_x25 *sa; ! 371: ! 372: if (nam == NULL) ! 373: return (EADDRNOTAVAIL); ! 374: if (lcp -> lcd_ceaddr) /* XXX */ ! 375: return (EADDRINUSE); ! 376: if (pk_checksockaddr (nam)) ! 377: return (EINVAL); ! 378: sa = mtod (nam, struct sockaddr_x25 *); ! 379: ! 380: /* ! 381: * If the user wishes to accept calls only from a particular ! 382: * net (net != 0), make sure the net is known ! 383: */ ! 384: ! 385: if (sa -> x25_addr[0]) { ! 386: if (!pk_ifwithaddr (sa)) ! 387: return (ENETUNREACH); ! 388: } else if (sa -> x25_net) { ! 389: if (!ifa_ifwithnet ((struct sockaddr *)sa)) ! 390: return (ENETUNREACH); ! 391: } ! 392: ! 393: /* ! 394: * For ISO's sake permit default listeners, but only one such . . . ! 395: */ ! 396: for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) { ! 397: register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr; ! 398: if ((sa2 -> x25_udlen == sa -> x25_udlen) && ! 399: (sa2 -> x25_udlen == 0 || ! 400: (bcmp (sa2 -> x25_udata, sa -> x25_udata, ! 401: min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0))) ! 402: return (EADDRINUSE); ! 403: } ! 404: lcp -> lcd_laddr = *sa; ! 405: lcp -> lcd_ceaddr = &lcp -> lcd_laddr; ! 406: return (0); ! 407: } ! 408: ! 409: /* ! 410: * Include a bound control block in the list of listeners. ! 411: */ ! 412: pk_listen (lcp) ! 413: register struct pklcd *lcp; ! 414: { ! 415: register struct pklcd **pp; ! 416: ! 417: if (lcp -> lcd_ceaddr == 0) ! 418: return (EDESTADDRREQ); ! 419: ! 420: lcp -> lcd_state = LISTEN; ! 421: /* ! 422: * Add default listener at end, any others at start. ! 423: */ ! 424: if (lcp -> lcd_ceaddr -> x25_udlen == 0) { ! 425: for (pp = &pk_listenhead; *pp; ) ! 426: pp = &((*pp) -> lcd_listen); ! 427: *pp = lcp; ! 428: } else { ! 429: lcp -> lcd_listen = pk_listenhead; ! 430: pk_listenhead = lcp; ! 431: } ! 432: return (0); ! 433: } ! 434: /* ! 435: * Include a listening control block for the benefit of other protocols. ! 436: */ ! 437: pk_protolisten (spi, spilen, callee) ! 438: int (*callee) (); ! 439: { ! 440: register struct pklcd *lcp = pk_attach ((struct socket *)0); ! 441: register struct mbuf *nam; ! 442: register struct sockaddr_x25 *sa; ! 443: int error = ENOBUFS; ! 444: ! 445: if (lcp) { ! 446: if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) { ! 447: sa = mtod (nam, struct sockaddr_x25 *); ! 448: sa -> x25_family = AF_CCITT; ! 449: sa -> x25_len = nam -> m_len = sizeof (*sa); ! 450: sa -> x25_udlen = spilen; ! 451: sa -> x25_udata[0] = spi; ! 452: lcp -> lcd_upper = callee; ! 453: lcp -> lcd_flags = X25_MBS_HOLD; ! 454: if ((error = pk_bind (lcp, nam)) == 0) ! 455: error = pk_listen (lcp); ! 456: (void) m_free (nam); ! 457: } ! 458: if (error) ! 459: pk_freelcd (lcp); ! 460: } ! 461: return error; /* Hopefully Zero !*/ ! 462: } ! 463: ! 464: /* ! 465: * Associate a logical channel descriptor with a network. ! 466: * Fill in the default network specific parameters and then ! 467: * set any parameters explicitly specified by the user or ! 468: * by the remote DTE. ! 469: */ ! 470: ! 471: pk_assoc (pkp, lcp, sa) ! 472: register struct pkcb *pkp; ! 473: register struct pklcd *lcp; ! 474: register struct sockaddr_x25 *sa; ! 475: { ! 476: ! 477: lcp -> lcd_pkp = pkp; ! 478: lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; ! 479: lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; ! 480: lcp -> lcd_rsn = MODULUS - 1; ! 481: pkp -> pk_chan[lcp -> lcd_lcn] = lcp; ! 482: ! 483: if (sa -> x25_opts.op_psize) ! 484: lcp -> lcd_packetsize = sa -> x25_opts.op_psize; ! 485: else ! 486: sa -> x25_opts.op_psize = lcp -> lcd_packetsize; ! 487: if (sa -> x25_opts.op_wsize) ! 488: lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; ! 489: else ! 490: sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; ! 491: sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; ! 492: lcp -> lcd_flags |= sa -> x25_opts.op_flags; ! 493: lcp -> lcd_stime = time.tv_sec; ! 494: } ! 495: ! 496: pk_connect (lcp, sa) ! 497: register struct pklcd *lcp; ! 498: register struct sockaddr_x25 *sa; ! 499: { ! 500: register struct pkcb *pkp; ! 501: register struct rtentry *rt; ! 502: register struct rtentry *nrt; ! 503: ! 504: struct rtentry *npaidb_enter (); ! 505: struct pkcb *pk_newlink (); ! 506: ! 507: if (sa -> x25_addr[0] == '\0') ! 508: return (EDESTADDRREQ); ! 509: ! 510: /* ! 511: * Is the destination address known? ! 512: */ ! 513: if (!(rt = rtalloc1 ((struct sockaddr *)sa, 1))) ! 514: return (ENETUNREACH); ! 515: ! 516: if (!(pkp = XTRACTPKP(rt))) ! 517: pkp = pk_newlink ((struct x25_ifaddr *) (rt -> rt_ifa), ! 518: (caddr_t) 0); ! 519: ! 520: /* ! 521: * Have we entered the LLC address? ! 522: */ ! 523: if (nrt = npaidb_enter (rt -> rt_gateway, rt_key (rt), rt, 0)) ! 524: pkp -> pk_llrt = nrt; ! 525: ! 526: /* ! 527: * Have we allocated an LLC2 link yet? ! 528: */ ! 529: if (pkp -> pk_llnext == (caddr_t)0 && pkp -> pk_llctlinput) { ! 530: struct dll_ctlinfo ctlinfo; ! 531: ! 532: ctlinfo.dlcti_rt = rt; ! 533: ctlinfo.dlcti_pcb = (caddr_t) pkp; ! 534: ctlinfo.dlcti_conf = ! 535: (struct dllconfig *) (&((struct x25_ifaddr *)(rt -> rt_ifa)) -> ia_xc); ! 536: pkp -> pk_llnext = ! 537: (pkp -> pk_llctlinput) (PRC_CONNECT_REQUEST, 0, &ctlinfo); ! 538: } ! 539: ! 540: if (pkp -> pk_state != DTE_READY && pkp -> pk_state != DTE_WAITING) ! 541: return (ENETDOWN); ! 542: if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) ! 543: return (EMFILE); ! 544: ! 545: lcp -> lcd_faddr = *sa; ! 546: lcp -> lcd_ceaddr = & lcp -> lcd_faddr; ! 547: pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); ! 548: ! 549: /* ! 550: * If the link is not up yet, initiate an X.25 RESTART ! 551: */ ! 552: if (pkp -> pk_state == DTE_WAITING) { ! 553: pkp -> pk_dxerole |= DTE_CONNECTPENDING; ! 554: pk_ctlinput (PRC_LINKUP, (struct sockaddr *)0, pkp); ! 555: if (lcp -> lcd_so) ! 556: soisconnecting (lcp -> lcd_so); ! 557: return 0; ! 558: } ! 559: ! 560: if (lcp -> lcd_so) ! 561: soisconnecting (lcp -> lcd_so); ! 562: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); ! 563: pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); ! 564: return (*pkp -> pk_ia -> ia_start) (lcp); ! 565: } ! 566: ! 567: /* ! 568: * Complete all pending X.25 call requests --- this gets called after ! 569: * the X.25 link has been restarted. ! 570: */ ! 571: #define RESHUFFLELCN(maxlcn, lcn) ((maxlcn) - (lcn) + 1) ! 572: ! 573: pk_callcomplete (pkp) ! 574: register struct pkcb *pkp; ! 575: { ! 576: register struct pklcd *lcp; ! 577: register int i; ! 578: register int ni; ! 579: ! 580: ! 581: if (pkp -> pk_dxerole & DTE_CONNECTPENDING) ! 582: pkp -> pk_dxerole &= ~DTE_CONNECTPENDING; ! 583: else return; ! 584: ! 585: if (pkp -> pk_chan == 0) ! 586: return; ! 587: ! 588: /* ! 589: * We pretended to be a DTE for allocating lcns, if ! 590: * it turns out that we are in reality performing as a ! 591: * DCE we need to reshuffle the lcps. ! 592: * ! 593: * /+---------------+-------- - ! 594: * / | a (maxlcn-1) | \ ! 595: * / +---------------+ \ ! 596: * +--- * | b (maxlcn-2) | \ ! 597: * | \ +---------------+ \ ! 598: * r | \ | c (maxlcn-3) | \ ! 599: * e | \+---------------+ | ! 600: * s | | . | ! 601: * h | | . | m ! 602: * u | | . | a ! 603: * f | | . | x ! 604: * f | | . | l ! 605: * l | /+---------------+ | c ! 606: * e | / | c' ( 3 ) | | n ! 607: * | / +---------------+ | ! 608: * +--> * | b' ( 2 ) | / ! 609: * \ +---------------+ / ! 610: * \ | a' ( 1 ) | / ! 611: * \+---------------+ / ! 612: * | 0 | / ! 613: * +---------------+-------- - ! 614: * ! 615: */ ! 616: if (pkp -> pk_dxerole & DTE_PLAYDCE) { ! 617: /* Sigh, reshuffle it */ ! 618: for (i = pkp -> pk_maxlcn; i > 0; --i) ! 619: if (pkp -> pk_chan[i]) { ! 620: ni = RESHUFFLELCN(pkp -> pk_maxlcn, i); ! 621: pkp -> pk_chan[ni] = pkp -> pk_chan[i]; ! 622: pkp -> pk_chan[i] = NULL; ! 623: pkp -> pk_chan[ni] -> lcd_lcn = ni; ! 624: } ! 625: } ! 626: ! 627: for (i = 1; i <= pkp -> pk_maxlcn; ++i) ! 628: if ((lcp = pkp -> pk_chan[i]) != NULL) { ! 629: /* if (lcp -> lcd_so) ! 630: soisconnecting (lcp -> lcd_so); */ ! 631: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); ! 632: pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); ! 633: (*pkp -> pk_ia -> ia_start) (lcp); ! 634: } ! 635: } ! 636: ! 637: struct bcdinfo { ! 638: octet *cp; ! 639: unsigned posn; ! 640: }; ! 641: /* ! 642: * Build the rest of the CALL REQUEST packet. Fill in calling ! 643: * address, facilities fields and the user data field. ! 644: */ ! 645: ! 646: pk_callrequest (lcp, sa, xcp) ! 647: struct pklcd *lcp; ! 648: register struct sockaddr_x25 *sa; ! 649: register struct x25config *xcp; ! 650: { ! 651: register struct x25_calladdr *a; ! 652: register struct mbuf *m = lcp -> lcd_template; ! 653: register struct x25_packet *xp = mtod (m, struct x25_packet *); ! 654: struct bcdinfo b; ! 655: ! 656: if (lcp -> lcd_flags & X25_DBIT) ! 657: X25SBITS(xp -> bits, d_bit, 1); ! 658: a = (struct x25_calladdr *) &xp -> packet_data; ! 659: b.cp = (octet *) a -> address_field; ! 660: b.posn = 0; ! 661: X25SBITS(a -> addrlens, called_addrlen, to_bcd (&b, sa, xcp)); ! 662: X25SBITS(a -> addrlens, calling_addrlen, to_bcd (&b, &xcp -> xc_addr, xcp)); ! 663: if (b.posn & 0x01) ! 664: *b.cp++ &= 0xf0; ! 665: m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a; ! 666: ! 667: if (lcp -> lcd_facilities) { ! 668: m -> m_pkthdr.len += ! 669: (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len; ! 670: lcp -> lcd_facilities = 0; ! 671: } else ! 672: pk_build_facilities (m, sa, (int)xcp -> xc_type); ! 673: ! 674: m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata); ! 675: } ! 676: ! 677: pk_build_facilities (m, sa, type) ! 678: register struct mbuf *m; ! 679: struct sockaddr_x25 *sa; ! 680: { ! 681: register octet *cp; ! 682: register octet *fcp; ! 683: register int revcharge; ! 684: ! 685: cp = mtod (m, octet *) + m -> m_len; ! 686: fcp = cp + 1; ! 687: revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; ! 688: /* ! 689: * This is specific to Datapac X.25(1976) DTEs. International ! 690: * calls must have the "hi priority" bit on. ! 691: */ ! 692: if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) ! 693: revcharge |= 02; ! 694: if (revcharge) { ! 695: *fcp++ = FACILITIES_REVERSE_CHARGE; ! 696: *fcp++ = revcharge; ! 697: } ! 698: switch (type) { ! 699: case X25_1980: ! 700: case X25_1984: ! 701: *fcp++ = FACILITIES_PACKETSIZE; ! 702: *fcp++ = sa -> x25_opts.op_psize; ! 703: *fcp++ = sa -> x25_opts.op_psize; ! 704: ! 705: *fcp++ = FACILITIES_WINDOWSIZE; ! 706: *fcp++ = sa -> x25_opts.op_wsize; ! 707: *fcp++ = sa -> x25_opts.op_wsize; ! 708: } ! 709: *cp = fcp - cp - 1; ! 710: m -> m_pkthdr.len = (m -> m_len += *cp + 1); ! 711: } ! 712: ! 713: to_bcd (b, sa, xcp) ! 714: register struct bcdinfo *b; ! 715: struct sockaddr_x25 *sa; ! 716: register struct x25config *xcp; ! 717: { ! 718: register char *x = sa -> x25_addr; ! 719: unsigned start = b -> posn; ! 720: /* ! 721: * The nodnic and prepnd0 stuff looks tedious, ! 722: * but it does allow full X.121 addresses to be used, ! 723: * which is handy for routing info (& OSI type 37 addresses). ! 724: */ ! 725: if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { ! 726: char dnicname[sizeof (long) * NBBY/3 + 2]; ! 727: register char *p = dnicname; ! 728: ! 729: sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff); ! 730: for (; *p; p++) /* *p == 0 means dnic matched */ ! 731: if ((*p ^ *x++) & 0x0f) ! 732: break; ! 733: if (*p || xcp -> xc_nodnic == 0) ! 734: x = sa -> x25_addr; ! 735: if (*p && xcp -> xc_prepnd0) { ! 736: if ((b -> posn)++ & 0x01) ! 737: *(b -> cp)++; ! 738: else ! 739: *(b -> cp) = 0; ! 740: } ! 741: } ! 742: while (*x) ! 743: if ((b -> posn)++ & 0x01) ! 744: *(b -> cp)++ |= *x++ & 0x0F; ! 745: else ! 746: *(b -> cp) = *x++ << 4; ! 747: return ((b -> posn) - start); ! 748: } ! 749: ! 750: /* ! 751: * This routine gets the first available logical channel number. The ! 752: * search is ! 753: * - from the highest number to lowest number if playing DTE, and ! 754: * - from lowest to highest number if playing DCE. ! 755: */ ! 756: ! 757: pk_getlcn (pkp) ! 758: register struct pkcb *pkp; ! 759: { ! 760: register int i; ! 761: ! 762: if (pkp -> pk_chan == 0) ! 763: return (0); ! 764: if ( pkp -> pk_dxerole & DTE_PLAYDCE ) { ! 765: for (i = 1; i <= pkp -> pk_maxlcn; ++i) ! 766: if (pkp -> pk_chan[i] == NULL) ! 767: break; ! 768: } else { ! 769: for (i = pkp -> pk_maxlcn; i > 0; --i) ! 770: if (pkp -> pk_chan[i] == NULL) ! 771: break; ! 772: } ! 773: i = ( i > pkp -> pk_maxlcn ? 0 : i ); ! 774: return (i); ! 775: } ! 776: ! 777: /* ! 778: * This procedure sends a CLEAR request packet. The lc state is ! 779: * set to "SENT_CLEAR". ! 780: */ ! 781: ! 782: pk_clear (lcp, diagnostic, abortive) ! 783: register struct pklcd *lcp; ! 784: { ! 785: register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); ! 786: ! 787: m -> m_len += 2; ! 788: m -> m_pkthdr.len += 2; ! 789: mtod (m, struct x25_packet *) -> packet_data = 0; ! 790: mtod (m, octet *)[4] = diagnostic; ! 791: if (lcp -> lcd_facilities) { ! 792: m -> m_next = lcp -> lcd_facilities; ! 793: m -> m_pkthdr.len += m -> m_next -> m_len; ! 794: lcp -> lcd_facilities = 0; ! 795: } ! 796: if (abortive) ! 797: lcp -> lcd_template = m; ! 798: else { ! 799: struct socket *so = lcp -> lcd_so; ! 800: struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; ! 801: sbappendrecord (sb, m); ! 802: } ! 803: pk_output (lcp); ! 804: ! 805: } ! 806: ! 807: /* ! 808: * This procedure generates RNR's or RR's to inhibit or enable ! 809: * inward data flow, if the current state changes (blocked ==> open or ! 810: * vice versa), or if forced to generate one. One forces RNR's to ack data. ! 811: */ ! 812: pk_flowcontrol (lcp, inhibit, forced) ! 813: register struct pklcd *lcp; ! 814: { ! 815: inhibit = (inhibit != 0); ! 816: if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || ! 817: (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) ! 818: return; ! 819: lcp -> lcd_rxrnr_condition = inhibit; ! 820: lcp -> lcd_template = ! 821: pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR); ! 822: pk_output (lcp); ! 823: } ! 824: ! 825: /* ! 826: * This procedure sends a RESET request packet. It re-intializes ! 827: * virtual circuit. ! 828: */ ! 829: ! 830: static ! 831: pk_reset (lcp, diagnostic) ! 832: register struct pklcd *lcp; ! 833: { ! 834: register struct mbuf *m; ! 835: register struct socket *so = lcp -> lcd_so; ! 836: ! 837: if (lcp -> lcd_state != DATA_TRANSFER) ! 838: return; ! 839: ! 840: if (so) ! 841: so -> so_error = ECONNRESET; ! 842: lcp -> lcd_reset_condition = TRUE; ! 843: ! 844: /* Reset all the control variables for the channel. */ ! 845: pk_flush (lcp); ! 846: lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = ! 847: lcp -> lcd_intrconf_pending = FALSE; ! 848: lcp -> lcd_rsn = MODULUS - 1; ! 849: lcp -> lcd_ssn = 0; ! 850: lcp -> lcd_output_window = lcp -> lcd_input_window = ! 851: lcp -> lcd_last_transmitted_pr = 0; ! 852: m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); ! 853: m -> m_pkthdr.len = m -> m_len += 2; ! 854: mtod (m, struct x25_packet *) -> packet_data = 0; ! 855: mtod (m, octet *)[4] = diagnostic; ! 856: pk_output (lcp); ! 857: ! 858: } ! 859: ! 860: /* ! 861: * This procedure frees all data queued for output or delivery on a ! 862: * virtual circuit. ! 863: */ ! 864: ! 865: pk_flush (lcp) ! 866: register struct pklcd *lcp; ! 867: { ! 868: register struct socket *so; ! 869: ! 870: if (lcp -> lcd_template) ! 871: m_freem (lcp -> lcd_template); ! 872: ! 873: if (lcp -> lcd_cps) { ! 874: m_freem (lcp -> lcd_cps); ! 875: lcp -> lcd_cps = 0; ! 876: } ! 877: if (lcp -> lcd_facilities) { ! 878: m_freem (lcp -> lcd_facilities); ! 879: lcp -> lcd_facilities = 0; ! 880: } ! 881: if (so = lcp -> lcd_so) ! 882: sbflush (&so -> so_snd); ! 883: else ! 884: sbflush (&lcp -> lcd_sb); ! 885: } ! 886: ! 887: /* ! 888: * This procedure handles all local protocol procedure errors. ! 889: */ ! 890: ! 891: pk_procerror (error, lcp, errstr, diagnostic) ! 892: register struct pklcd *lcp; ! 893: char *errstr; ! 894: { ! 895: ! 896: pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); ! 897: ! 898: switch (error) { ! 899: case CLEAR: ! 900: if (lcp -> lcd_so) { ! 901: lcp -> lcd_so -> so_error = ECONNABORTED; ! 902: soisdisconnecting (lcp -> lcd_so); ! 903: } ! 904: pk_clear (lcp, diagnostic, 1); ! 905: break; ! 906: ! 907: case RESET: ! 908: pk_reset (lcp, diagnostic); ! 909: } ! 910: } ! 911: ! 912: /* ! 913: * This procedure is called during the DATA TRANSFER state to check ! 914: * and process the P(R) values received in the DATA, RR OR RNR ! 915: * packets. ! 916: */ ! 917: ! 918: pk_ack (lcp, pr) ! 919: struct pklcd *lcp; ! 920: unsigned pr; ! 921: { ! 922: register struct socket *so = lcp -> lcd_so; ! 923: ! 924: if (lcp -> lcd_output_window == pr) ! 925: return (PACKET_OK); ! 926: if (lcp -> lcd_output_window < lcp -> lcd_ssn) { ! 927: if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { ! 928: pk_procerror (RESET, lcp, ! 929: "p(r) flow control error", 2); ! 930: return (ERROR_PACKET); ! 931: } ! 932: } ! 933: else { ! 934: if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { ! 935: pk_procerror (RESET, lcp, ! 936: "p(r) flow control error #2", 2); ! 937: return (ERROR_PACKET); ! 938: } ! 939: } ! 940: ! 941: lcp -> lcd_output_window = pr; /* Rotate window. */ ! 942: if (lcp -> lcd_window_condition == TRUE) ! 943: lcp -> lcd_window_condition = FALSE; ! 944: ! 945: if (so && ((so -> so_snd.sb_flags & SB_WAIT) || ! 946: (so -> so_snd.sb_flags & SB_NOTIFY))) ! 947: sowwakeup (so); ! 948: ! 949: return (PACKET_OK); ! 950: } ! 951: ! 952: /* ! 953: * This procedure decodes the X.25 level 3 packet returning a ! 954: * code to be used in switchs or arrays. ! 955: */ ! 956: ! 957: pk_decode (xp) ! 958: register struct x25_packet *xp; ! 959: { ! 960: register int type; ! 961: ! 962: if (X25GBITS(xp -> bits, fmt_identifier) != 1) ! 963: return (INVALID_PACKET); ! 964: #ifdef ancient_history ! 965: /* ! 966: * Make sure that the logical channel group number is 0. ! 967: * This restriction may be removed at some later date. ! 968: */ ! 969: if (xp -> lc_group_number != 0) ! 970: return (INVALID_PACKET); ! 971: #endif ! 972: /* ! 973: * Test for data packet first. ! 974: */ ! 975: if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) ! 976: return (DATA); ! 977: ! 978: /* ! 979: * Test if flow control packet (RR or RNR). ! 980: */ ! 981: if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) ! 982: switch (xp -> packet_type & 0x1f) { ! 983: case X25_RR: ! 984: return (RR); ! 985: case X25_RNR: ! 986: return (RNR); ! 987: case X25_REJECT: ! 988: return (REJECT); ! 989: } ! 990: ! 991: /* ! 992: * Determine the rest of the packet types. ! 993: */ ! 994: switch (xp -> packet_type) { ! 995: case X25_CALL: ! 996: type = CALL; ! 997: break; ! 998: ! 999: case X25_CALL_ACCEPTED: ! 1000: type = CALL_ACCEPTED; ! 1001: break; ! 1002: ! 1003: case X25_CLEAR: ! 1004: type = CLEAR; ! 1005: break; ! 1006: ! 1007: case X25_CLEAR_CONFIRM: ! 1008: type = CLEAR_CONF; ! 1009: break; ! 1010: ! 1011: case X25_INTERRUPT: ! 1012: type = INTERRUPT; ! 1013: break; ! 1014: ! 1015: case X25_INTERRUPT_CONFIRM: ! 1016: type = INTERRUPT_CONF; ! 1017: break; ! 1018: ! 1019: case X25_RESET: ! 1020: type = RESET; ! 1021: break; ! 1022: ! 1023: case X25_RESET_CONFIRM: ! 1024: type = RESET_CONF; ! 1025: break; ! 1026: ! 1027: case X25_RESTART: ! 1028: type = RESTART; ! 1029: break; ! 1030: ! 1031: case X25_RESTART_CONFIRM: ! 1032: type = RESTART_CONF; ! 1033: break; ! 1034: ! 1035: case X25_DIAGNOSTIC: ! 1036: type = DIAG_TYPE; ! 1037: break; ! 1038: ! 1039: default: ! 1040: type = INVALID_PACKET; ! 1041: } ! 1042: return (type); ! 1043: } ! 1044: ! 1045: /* ! 1046: * A restart packet has been received. Print out the reason ! 1047: * for the restart. ! 1048: */ ! 1049: ! 1050: pk_restartcause (pkp, xp) ! 1051: struct pkcb *pkp; ! 1052: register struct x25_packet *xp; ! 1053: { ! 1054: register struct x25config *xcp = pkp -> pk_xcp; ! 1055: register int lcn = LCN(xp); ! 1056: ! 1057: switch (xp -> packet_data) { ! 1058: case X25_RESTART_LOCAL_PROCEDURE_ERROR: ! 1059: pk_message (lcn, xcp, "restart: local procedure error"); ! 1060: break; ! 1061: ! 1062: case X25_RESTART_NETWORK_CONGESTION: ! 1063: pk_message (lcn, xcp, "restart: network congestion"); ! 1064: break; ! 1065: ! 1066: case X25_RESTART_NETWORK_OPERATIONAL: ! 1067: pk_message (lcn, xcp, "restart: network operational"); ! 1068: break; ! 1069: ! 1070: default: ! 1071: pk_message (lcn, xcp, "restart: unknown cause"); ! 1072: } ! 1073: } ! 1074: ! 1075: #define MAXRESETCAUSE 7 ! 1076: ! 1077: int Reset_cause[] = { ! 1078: EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG ! 1079: }; ! 1080: ! 1081: /* ! 1082: * A reset packet has arrived. Return the cause to the user. ! 1083: */ ! 1084: ! 1085: pk_resetcause (pkp, xp) ! 1086: struct pkcb *pkp; ! 1087: register struct x25_packet *xp; ! 1088: { ! 1089: register struct pklcd *lcp = ! 1090: pkp -> pk_chan[LCN(xp)]; ! 1091: register int code = xp -> packet_data; ! 1092: ! 1093: if (code > MAXRESETCAUSE) ! 1094: code = 7; /* EXRNCG */ ! 1095: ! 1096: pk_message (LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x", ! 1097: xp -> packet_data, 4[(u_char *)xp]); ! 1098: ! 1099: if (lcp -> lcd_so) ! 1100: lcp -> lcd_so -> so_error = Reset_cause[code]; ! 1101: } ! 1102: ! 1103: #define MAXCLEARCAUSE 25 ! 1104: ! 1105: int Clear_cause[] = { ! 1106: EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, ! 1107: 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, ! 1108: 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC ! 1109: }; ! 1110: ! 1111: /* ! 1112: * A clear packet has arrived. Return the cause to the user. ! 1113: */ ! 1114: ! 1115: pk_clearcause (pkp, xp) ! 1116: struct pkcb *pkp; ! 1117: register struct x25_packet *xp; ! 1118: { ! 1119: register struct pklcd *lcp = ! 1120: pkp -> pk_chan[LCN(xp)]; ! 1121: register int code = xp -> packet_data; ! 1122: ! 1123: if (code > MAXCLEARCAUSE) ! 1124: code = 5; /* EXRNCG */ ! 1125: if (lcp -> lcd_so) ! 1126: lcp -> lcd_so -> so_error = Clear_cause[code]; ! 1127: } ! 1128: ! 1129: char * ! 1130: format_ntn (xcp) ! 1131: register struct x25config *xcp; ! 1132: { ! 1133: ! 1134: return (xcp -> xc_addr.x25_addr); ! 1135: } ! 1136: ! 1137: /* VARARGS1 */ ! 1138: pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) ! 1139: struct x25config *xcp; ! 1140: char *fmt; ! 1141: { ! 1142: ! 1143: if (lcn) ! 1144: if (!PQEMPTY) ! 1145: printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); ! 1146: else ! 1147: printf ("X.25: lcn %d: ", lcn); ! 1148: else ! 1149: if (!PQEMPTY) ! 1150: printf ("X.25(%s): ", format_ntn (xcp)); ! 1151: else ! 1152: printf ("X.25: "); ! 1153: ! 1154: printf (fmt, a1, a2, a3, a4, a5, a6); ! 1155: printf ("\n"); ! 1156: } ! 1157: ! 1158: pk_fragment (lcp, m0, qbit, mbit, wait) ! 1159: struct mbuf *m0; ! 1160: register struct pklcd *lcp; ! 1161: { ! 1162: register struct mbuf *m = m0; ! 1163: register struct x25_packet *xp; ! 1164: register struct sockbuf *sb; ! 1165: struct mbuf *head = 0, *next, **mp = &head, *m_split (); ! 1166: int totlen, psize = 1 << (lcp -> lcd_packetsize); ! 1167: ! 1168: if (m == 0) ! 1169: return 0; ! 1170: if (m -> m_flags & M_PKTHDR == 0) ! 1171: panic ("pk_fragment"); ! 1172: totlen = m -> m_pkthdr.len; ! 1173: m -> m_act = 0; ! 1174: sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; ! 1175: do { ! 1176: if (totlen > psize) { ! 1177: if ((next = m_split (m, psize, wait)) == 0) ! 1178: goto abort; ! 1179: totlen -= psize; ! 1180: } else ! 1181: next = 0; ! 1182: M_PREPEND(m, PKHEADERLN, wait); ! 1183: if (m == 0) ! 1184: goto abort; ! 1185: *mp = m; ! 1186: mp = & m -> m_act; ! 1187: *mp = 0; ! 1188: xp = mtod (m, struct x25_packet *); ! 1189: 0[(char *)xp] = 0; ! 1190: if (qbit) ! 1191: X25SBITS(xp -> bits, q_bit, 1); ! 1192: if (lcp -> lcd_flags & X25_DBIT) ! 1193: X25SBITS(xp -> bits, d_bit, 1); ! 1194: X25SBITS(xp -> bits, fmt_identifier, 1); ! 1195: xp -> packet_type = X25_DATA; ! 1196: SET_LCN(xp, lcp -> lcd_lcn); ! 1197: if (next || (mbit && (totlen == psize || ! 1198: (lcp -> lcd_flags & X25_DBIT)))) ! 1199: SMBIT(xp, 1); ! 1200: } while (m = next); ! 1201: for (m = head; m; m = next) { ! 1202: next = m -> m_act; ! 1203: m -> m_act = 0; ! 1204: sbappendrecord (sb, m); ! 1205: } ! 1206: return 0; ! 1207: abort: ! 1208: if (wait) ! 1209: panic ("pk_fragment null mbuf after wait"); ! 1210: if (next) ! 1211: m_freem (next); ! 1212: for (m = head; m; m = next) { ! 1213: next = m -> m_act; ! 1214: m_freem (m); ! 1215: } ! 1216: return ENOBUFS; ! 1217: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.