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