|
|
1.1 ! root 1: /* ! 2: * Copyright (c) University of British Columbia, 1984 ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Laboratory for Computation Vision and the Computer Science Department ! 8: * of the University of British Columbia. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * @(#)pk_subr.c 7.16 (Berkeley) 6/6/91 ! 39: */ ! 40: ! 41: #include "param.h" ! 42: #include "systm.h" ! 43: #include "mbuf.h" ! 44: #include "socket.h" ! 45: #include "protosw.h" ! 46: #include "socketvar.h" ! 47: #include "errno.h" ! 48: #include "time.h" ! 49: #include "kernel.h" ! 50: ! 51: #include "../net/if.h" ! 52: ! 53: #include "x25.h" ! 54: #include "pk.h" ! 55: #include "pk_var.h" ! 56: #include "x25err.h" ! 57: ! 58: int pk_sendspace = 1024 * 2 + 8; ! 59: int pk_recvspace = 1024 * 2 + 8; ! 60: ! 61: struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q}; ! 62: ! 63: /* ! 64: * Attach X.25 protocol to socket, allocate logical channel descripter ! 65: * and buffer space, and enter LISTEN state if we are to accept ! 66: * IN-COMMING CALL packets. ! 67: * ! 68: */ ! 69: ! 70: struct pklcd * ! 71: pk_attach (so) ! 72: struct socket *so; ! 73: { ! 74: register struct pklcd *lcp; ! 75: register int error = ENOBUFS; ! 76: int pk_output(); ! 77: ! 78: MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT); ! 79: if (lcp) { ! 80: bzero ((caddr_t)lcp, sizeof (*lcp)); ! 81: insque (&lcp -> lcd_q, &pklcd_q); ! 82: lcp -> lcd_state = READY; ! 83: lcp -> lcd_send = pk_output; ! 84: if (so) { ! 85: error = soreserve (so, pk_sendspace, pk_recvspace); ! 86: lcp -> lcd_so = so; ! 87: if (so -> so_options & SO_ACCEPTCONN) ! 88: lcp -> lcd_state = LISTEN; ! 89: } else ! 90: sbreserve (&lcp -> lcd_sb, pk_sendspace); ! 91: } ! 92: if (so) { ! 93: so -> so_pcb = (caddr_t) lcp; ! 94: so -> so_error = error; ! 95: } ! 96: return (lcp); ! 97: } ! 98: ! 99: /* ! 100: * Disconnect X.25 protocol from socket. ! 101: */ ! 102: ! 103: pk_disconnect (lcp) ! 104: register struct pklcd *lcp; ! 105: { ! 106: register struct socket *so = lcp -> lcd_so; ! 107: register struct pklcd *l, *p; ! 108: ! 109: switch (lcp -> lcd_state) { ! 110: case LISTEN: ! 111: for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); ! 112: if (p == 0) { ! 113: if (l != 0) ! 114: pk_listenhead = l -> lcd_listen; ! 115: } ! 116: else ! 117: if (l != 0) ! 118: p -> lcd_listen = l -> lcd_listen; ! 119: pk_close (lcp); ! 120: break; ! 121: ! 122: case READY: ! 123: pk_acct (lcp); ! 124: pk_close (lcp); ! 125: break; ! 126: ! 127: case SENT_CLEAR: ! 128: case RECEIVED_CLEAR: ! 129: break; ! 130: ! 131: default: ! 132: pk_acct (lcp); ! 133: if (so) { ! 134: soisdisconnecting (so); ! 135: sbflush (&so -> so_rcv); ! 136: } ! 137: pk_clear (lcp, 241, 0); /* Normal Disconnect */ ! 138: ! 139: } ! 140: } ! 141: ! 142: /* ! 143: * Close an X.25 Logical Channel. Discard all space held by the ! 144: * connection and internal descriptors. Wake up any sleepers. ! 145: */ ! 146: ! 147: pk_close (lcp) ! 148: struct pklcd *lcp; ! 149: { ! 150: register struct socket *so = lcp -> lcd_so; ! 151: ! 152: pk_freelcd (lcp); ! 153: ! 154: if (so == NULL) ! 155: return; ! 156: ! 157: so -> so_pcb = 0; ! 158: soisdisconnected (so); ! 159: /* sofree (so); /* gak!!! you can't do that here */ ! 160: } ! 161: ! 162: /* ! 163: * Create a template to be used to send X.25 packets on a logical ! 164: * channel. It allocates an mbuf and fills in a skeletal packet ! 165: * depending on its type. This packet is passed to pk_output where ! 166: * the remainer of the packet is filled in. ! 167: */ ! 168: ! 169: struct mbuf * ! 170: pk_template (lcn, type) ! 171: int lcn, type; ! 172: { ! 173: register struct mbuf *m; ! 174: register struct x25_packet *xp; ! 175: ! 176: MGETHDR (m, M_DONTWAIT, MT_HEADER); ! 177: if (m == 0) ! 178: panic ("pk_template"); ! 179: m -> m_act = 0; ! 180: ! 181: /* ! 182: * Efficiency hack: leave a four byte gap at the beginning ! 183: * of the packet level header with the hope that this will ! 184: * be enough room for the link level to insert its header. ! 185: */ ! 186: m -> m_data += max_linkhdr; ! 187: m -> m_pkthdr.len = m -> m_len = PKHEADERLN; ! 188: ! 189: xp = mtod (m, struct x25_packet *); ! 190: *(long *)xp = 0; /* ugly, but fast */ ! 191: /* xp -> q_bit = 0;*/ ! 192: xp -> fmt_identifier = 1; ! 193: /* xp -> lc_group_number = 0;*/ ! 194: ! 195: SET_LCN(xp, lcn); ! 196: xp -> packet_type = type; ! 197: ! 198: return (m); ! 199: } ! 200: ! 201: /* ! 202: * This routine restarts all the virtual circuits. Actually, ! 203: * the virtual circuits are not "restarted" as such. Instead, ! 204: * any active switched circuit is simply returned to READY ! 205: * state. ! 206: */ ! 207: ! 208: pk_restart (pkp, restart_cause) ! 209: register struct pkcb *pkp; ! 210: int restart_cause; ! 211: { ! 212: register struct mbuf *m; ! 213: register struct pklcd *lcp; ! 214: register int i; ! 215: ! 216: /* Restart all logical channels. */ ! 217: if (pkp -> pk_chan == 0) ! 218: return; ! 219: for (i = 1; i <= pkp -> pk_maxlcn; ++i) ! 220: if ((lcp = pkp -> pk_chan[i]) != NULL) { ! 221: if (lcp -> lcd_so) { ! 222: lcp -> lcd_so -> so_error = ENETRESET; ! 223: pk_close (lcp); ! 224: } else { ! 225: pk_flush (lcp); ! 226: lcp -> lcd_state = READY; ! 227: if (lcp -> lcd_upper) ! 228: lcp -> lcd_upper (lcp, 0); ! 229: } ! 230: } ! 231: ! 232: if (restart_cause < 0) ! 233: return; ! 234: ! 235: pkp -> pk_state = DTE_SENT_RESTART; ! 236: lcp = pkp -> pk_chan[0]; ! 237: m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); ! 238: m -> m_pkthdr.len = m -> m_len += 2; ! 239: mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */ ! 240: mtod (m, octet *)[4] = restart_cause; ! 241: pk_output (lcp); ! 242: } ! 243: ! 244: ! 245: /* ! 246: * This procedure frees up the Logical Channel Descripter. ! 247: */ ! 248: ! 249: pk_freelcd (lcp) ! 250: register struct pklcd *lcp; ! 251: { ! 252: if (lcp == NULL) ! 253: return; ! 254: ! 255: if (lcp -> lcd_lcn > 0) ! 256: lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; ! 257: ! 258: pk_flush (lcp); ! 259: remque (&lcp -> lcd_q); ! 260: free ((caddr_t)lcp, M_PCB); ! 261: } ! 262: ! 263: ! 264: /* ! 265: * Bind a address and protocol value to a socket. The important ! 266: * part is the protocol value - the first four characters of the ! 267: * Call User Data field. ! 268: */ ! 269: ! 270: pk_bind (lcp, nam) ! 271: struct pklcd *lcp; ! 272: struct mbuf *nam; ! 273: { ! 274: register struct pkcb *pkp; ! 275: register struct pklcd *pp; ! 276: register struct sockaddr_x25 *sa; ! 277: ! 278: if (nam == NULL) ! 279: return (EADDRNOTAVAIL); ! 280: if (lcp -> lcd_ceaddr) /* XXX */ ! 281: return (EADDRINUSE); ! 282: if (pk_checksockaddr (nam)) ! 283: return (EINVAL); ! 284: sa = mtod (nam, struct sockaddr_x25 *); ! 285: ! 286: /* ! 287: * If the user wishes to accept calls only from a particular ! 288: * net (net != 0), make sure the net is known ! 289: */ ! 290: ! 291: if (sa -> x25_net) ! 292: for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { ! 293: if (pkp == 0) ! 294: return (ENETUNREACH); ! 295: if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net) ! 296: break; ! 297: } ! 298: ! 299: /* ! 300: * For ISO's sake permit default listeners, but only one such . . . ! 301: */ ! 302: for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) { ! 303: register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr; ! 304: if ((sa2 -> x25_udlen == sa -> x25_udlen) && ! 305: (sa2 -> x25_udlen == 0 || ! 306: (bcmp (sa2 -> x25_udata, sa -> x25_udata, ! 307: min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0))) ! 308: return (EADDRINUSE); ! 309: } ! 310: lcp -> lcd_laddr = *sa; ! 311: lcp -> lcd_ceaddr = &lcp -> lcd_laddr; ! 312: return (0); ! 313: } ! 314: ! 315: /* ! 316: * Include a bound control block in the list of listeners. ! 317: */ ! 318: pk_listen (lcp) ! 319: register struct pklcd *lcp; ! 320: { ! 321: register struct pklcd **pp; ! 322: ! 323: if (lcp -> lcd_ceaddr == 0) ! 324: return (EDESTADDRREQ); ! 325: ! 326: lcp -> lcd_state = LISTEN; ! 327: /* ! 328: * Add default listener at end, any others at start. ! 329: */ ! 330: if (lcp -> lcd_ceaddr -> x25_udlen == 0) { ! 331: for (pp = &pk_listenhead; *pp; ) ! 332: pp = &((*pp) -> lcd_listen); ! 333: *pp = lcp; ! 334: } else { ! 335: lcp -> lcd_listen = pk_listenhead; ! 336: pk_listenhead = lcp; ! 337: } ! 338: return (0); ! 339: } ! 340: /* ! 341: * Include a listening control block for the benefit of other protocols. ! 342: */ ! 343: pk_protolisten (spi, spilen, callee) ! 344: int (*callee) (); ! 345: { ! 346: register struct pklcd *lcp = pk_attach ((struct socket *)0); ! 347: register struct mbuf *nam; ! 348: register struct sockaddr_x25 *sa; ! 349: int error = ENOBUFS; ! 350: ! 351: if (lcp) { ! 352: if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) { ! 353: sa = mtod (nam, struct sockaddr_x25 *); ! 354: sa -> x25_family = AF_CCITT; ! 355: sa -> x25_len = nam -> m_len = sizeof (*sa); ! 356: sa -> x25_udlen = spilen; ! 357: sa -> x25_udata[0] = spi; ! 358: lcp -> lcd_upper = callee; ! 359: lcp -> lcd_flags = X25_MBS_HOLD; ! 360: if ((error = pk_bind (lcp, nam)) == 0) ! 361: error = pk_listen (lcp); ! 362: (void) m_free (nam); ! 363: } ! 364: if (error) ! 365: pk_freelcd (lcp); ! 366: } ! 367: return error; /* Hopefully Zero !*/ ! 368: } ! 369: ! 370: /* ! 371: * Associate a logical channel descriptor with a network. ! 372: * Fill in the default network specific parameters and then ! 373: * set any parameters explicitly specified by the user or ! 374: * by the remote DTE. ! 375: */ ! 376: ! 377: pk_assoc (pkp, lcp, sa) ! 378: register struct pkcb *pkp; ! 379: register struct pklcd *lcp; ! 380: register struct sockaddr_x25 *sa; ! 381: { ! 382: ! 383: lcp -> lcd_pkp = pkp; ! 384: lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; ! 385: lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; ! 386: lcp -> lcd_rsn = MODULUS - 1; ! 387: pkp -> pk_chan[lcp -> lcd_lcn] = lcp; ! 388: ! 389: if (sa -> x25_opts.op_psize) ! 390: lcp -> lcd_packetsize = sa -> x25_opts.op_psize; ! 391: else ! 392: sa -> x25_opts.op_psize = lcp -> lcd_packetsize; ! 393: if (sa -> x25_opts.op_wsize) ! 394: lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; ! 395: else ! 396: sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; ! 397: sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; ! 398: lcp -> lcd_flags |= sa -> x25_opts.op_flags; ! 399: lcp -> lcd_stime = time.tv_sec; ! 400: } ! 401: ! 402: pk_connect (lcp, sa) ! 403: register struct pklcd *lcp; ! 404: register struct sockaddr_x25 *sa; ! 405: { ! 406: register struct pkcb *pkp; ! 407: ! 408: if (sa -> x25_addr[0] == '\0') ! 409: return (EDESTADDRREQ); ! 410: if (lcp -> lcd_pkp == 0) ! 411: for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { ! 412: if (pkp == 0) ! 413: return (ENETUNREACH); ! 414: /* ! 415: * use first net configured (last in list ! 416: * headed by pkcbhead) if net is zero ! 417: * ! 418: * This is clearly bogus for many llc2's sharing ! 419: * the same xcp; we will replace this with a ! 420: * routing lookup. ! 421: */ ! 422: if (sa -> x25_net == 0 && pkp -> pk_next == 0) ! 423: break; ! 424: if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net) ! 425: break; ! 426: } ! 427: ! 428: if (pkp -> pk_state != DTE_READY) ! 429: return (ENETDOWN); ! 430: if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) ! 431: return (EMFILE); ! 432: lcp -> lcd_faddr = *sa; ! 433: lcp -> lcd_ceaddr = & lcp -> lcd_faddr; ! 434: pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); ! 435: if (lcp -> lcd_so) ! 436: soisconnecting (lcp -> lcd_so); ! 437: lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); ! 438: pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); ! 439: return (*pkp -> pk_ia -> ia_start) (lcp); ! 440: } ! 441: ! 442: struct bcdinfo { ! 443: octet *cp; ! 444: unsigned posn; ! 445: }; ! 446: /* ! 447: * Build the rest of the CALL REQUEST packet. Fill in calling ! 448: * address, facilities fields and the user data field. ! 449: */ ! 450: ! 451: pk_callrequest (lcp, sa, xcp) ! 452: struct pklcd *lcp; ! 453: register struct sockaddr_x25 *sa; ! 454: register struct x25config *xcp; ! 455: { ! 456: register struct x25_calladdr *a; ! 457: register struct mbuf *m = lcp -> lcd_template; ! 458: register struct x25_packet *xp = mtod (m, struct x25_packet *); ! 459: struct bcdinfo b; ! 460: ! 461: if (lcp -> lcd_flags & X25_DBIT) ! 462: xp -> d_bit = 1; ! 463: a = (struct x25_calladdr *) &xp -> packet_data; ! 464: b.cp = (octet *) a -> address_field; ! 465: b.posn = 0; ! 466: a -> called_addrlen = to_bcd (&b, sa, xcp); ! 467: a -> calling_addrlen = to_bcd (&b, &xcp -> xc_addr, xcp); ! 468: if (b.posn & 0x01) ! 469: *b.cp++ &= 0xf0; ! 470: m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a; ! 471: ! 472: if (lcp -> lcd_facilities) { ! 473: m -> m_pkthdr.len += ! 474: (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len; ! 475: lcp -> lcd_facilities = 0; ! 476: } else ! 477: pk_build_facilities (m, sa, (int)xcp -> xc_type); ! 478: ! 479: m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata); ! 480: } ! 481: ! 482: pk_build_facilities (m, sa, type) ! 483: register struct mbuf *m; ! 484: struct sockaddr_x25 *sa; ! 485: { ! 486: register octet *cp; ! 487: register octet *fcp; ! 488: register int revcharge; ! 489: ! 490: cp = mtod (m, octet *) + m -> m_len; ! 491: fcp = cp + 1; ! 492: revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; ! 493: /* ! 494: * This is specific to Datapac X.25(1976) DTEs. International ! 495: * calls must have the "hi priority" bit on. ! 496: */ ! 497: if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) ! 498: revcharge |= 02; ! 499: if (revcharge) { ! 500: *fcp++ = FACILITIES_REVERSE_CHARGE; ! 501: *fcp++ = revcharge; ! 502: } ! 503: switch (type) { ! 504: case X25_1980: ! 505: case X25_1984: ! 506: *fcp++ = FACILITIES_PACKETSIZE; ! 507: *fcp++ = sa -> x25_opts.op_psize; ! 508: *fcp++ = sa -> x25_opts.op_psize; ! 509: ! 510: *fcp++ = FACILITIES_WINDOWSIZE; ! 511: *fcp++ = sa -> x25_opts.op_wsize; ! 512: *fcp++ = sa -> x25_opts.op_wsize; ! 513: } ! 514: *cp = fcp - cp - 1; ! 515: m -> m_pkthdr.len = (m -> m_len += *cp + 1); ! 516: } ! 517: ! 518: to_bcd (b, sa, xcp) ! 519: register struct bcdinfo *b; ! 520: struct sockaddr_x25 *sa; ! 521: register struct x25config *xcp; ! 522: { ! 523: register char *x = sa -> x25_addr; ! 524: unsigned start = b -> posn; ! 525: /* ! 526: * The nodnic and prepnd0 stuff looks tedious, ! 527: * but it does allow full X.121 addresses to be used, ! 528: * which is handy for routing info (& OSI type 37 addresses). ! 529: */ ! 530: if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { ! 531: char dnicname[sizeof(long) * NBBY/3 + 2]; ! 532: register char *p = dnicname; ! 533: ! 534: sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff); ! 535: for (; *p; p++) /* *p == 0 means dnic matched */ ! 536: if ((*p ^ *x++) & 0x0f) ! 537: break; ! 538: if (*p || xcp -> xc_nodnic == 0) ! 539: x = sa -> x25_addr; ! 540: if (*p && xcp -> xc_prepnd0) { ! 541: if ((b -> posn)++ & 0x01) ! 542: *(b -> cp)++; ! 543: else ! 544: *(b -> cp) = 0; ! 545: } ! 546: } ! 547: while (*x) ! 548: if ((b -> posn)++ & 0x01) ! 549: *(b -> cp)++ |= *x++ & 0x0F; ! 550: else ! 551: *(b -> cp) = *x++ << 4; ! 552: return ((b -> posn) - start); ! 553: } ! 554: ! 555: /* ! 556: * This routine gets the first available logical channel number. The ! 557: * search is from the highest number to lowest number (DTE). ! 558: */ ! 559: ! 560: pk_getlcn (pkp) ! 561: register struct pkcb *pkp; ! 562: { ! 563: register int i; ! 564: ! 565: if (pkp -> pk_chan == 0) ! 566: return (0); ! 567: for (i = pkp -> pk_maxlcn; i > 0; --i) ! 568: if (pkp -> pk_chan[i] == NULL) ! 569: break; ! 570: return (i); ! 571: ! 572: } ! 573: ! 574: /* ! 575: * This procedure sends a CLEAR request packet. The lc state is ! 576: * set to "SENT_CLEAR". ! 577: */ ! 578: ! 579: pk_clear (lcp, diagnostic, abortive) ! 580: register struct pklcd *lcp; ! 581: { ! 582: register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); ! 583: ! 584: m -> m_len += 2; ! 585: mtod (m, struct x25_packet *) -> packet_data = 0; ! 586: mtod (m, octet *)[4] = diagnostic; ! 587: if (lcp -> lcd_facilities) { ! 588: m -> m_next = lcp -> lcd_facilities; ! 589: m -> m_pkthdr.len += m -> m_next -> m_len; ! 590: lcp -> lcd_facilities = 0; ! 591: } ! 592: if (abortive) ! 593: lcp -> lcd_template = m; ! 594: else { ! 595: struct socket *so = lcp -> lcd_so; ! 596: struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; ! 597: sbappendrecord (sb, m); ! 598: } ! 599: pk_output (lcp); ! 600: ! 601: } ! 602: ! 603: /* ! 604: * This procedure generates RNR's or RR's to inhibit or enable ! 605: * inward data flow, if the current state changes (blocked ==> open or ! 606: * vice versa), or if forced to generate one. One forces RNR's to ack data. ! 607: */ ! 608: pk_flowcontrol (lcp, inhibit, forced) ! 609: register struct pklcd *lcp; ! 610: { ! 611: inhibit = (inhibit != 0); ! 612: if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || ! 613: (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) ! 614: return; ! 615: lcp -> lcd_rxrnr_condition = inhibit; ! 616: lcp -> lcd_template = ! 617: pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR); ! 618: pk_output (lcp); ! 619: } ! 620: ! 621: /* ! 622: * This procedure sends a RESET request packet. It re-intializes ! 623: * virtual circuit. ! 624: */ ! 625: ! 626: static ! 627: pk_reset (lcp, diagnostic) ! 628: register struct pklcd *lcp; ! 629: { ! 630: register struct mbuf *m; ! 631: register struct socket *so = lcp -> lcd_so; ! 632: ! 633: if (lcp -> lcd_state != DATA_TRANSFER) ! 634: return; ! 635: ! 636: if (so) ! 637: so -> so_error = ECONNRESET; ! 638: lcp -> lcd_reset_condition = TRUE; ! 639: ! 640: /* Reset all the control variables for the channel. */ ! 641: pk_flush (lcp); ! 642: lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = ! 643: lcp -> lcd_intrconf_pending = FALSE; ! 644: lcp -> lcd_rsn = MODULUS - 1; ! 645: lcp -> lcd_ssn = 0; ! 646: lcp -> lcd_output_window = lcp -> lcd_input_window = ! 647: lcp -> lcd_last_transmitted_pr = 0; ! 648: m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); ! 649: m -> m_pkthdr.len = m -> m_len += 2; ! 650: mtod (m, struct x25_packet *) -> packet_data = 0; ! 651: mtod (m, octet *)[4] = diagnostic; ! 652: pk_output (lcp); ! 653: ! 654: } ! 655: ! 656: /* ! 657: * This procedure frees all data queued for output or delivery on a ! 658: * virtual circuit. ! 659: */ ! 660: ! 661: pk_flush (lcp) ! 662: register struct pklcd *lcp; ! 663: { ! 664: register struct socket *so; ! 665: ! 666: if (lcp -> lcd_template) ! 667: m_freem (lcp -> lcd_template); ! 668: ! 669: if (lcp -> lcd_cps) { ! 670: m_freem (lcp -> lcd_cps); ! 671: lcp -> lcd_cps = 0; ! 672: } ! 673: if (lcp -> lcd_facilities) { ! 674: m_freem (lcp -> lcd_facilities); ! 675: lcp -> lcd_facilities = 0; ! 676: } ! 677: if (so = lcp -> lcd_so) { ! 678: sbflush (&so -> so_rcv); ! 679: sbflush (&so -> so_snd); ! 680: } else ! 681: sbflush (&lcp -> lcd_sb); ! 682: } ! 683: ! 684: /* ! 685: * This procedure handles all local protocol procedure errors. ! 686: */ ! 687: ! 688: pk_procerror (error, lcp, errstr, diagnostic) ! 689: register struct pklcd *lcp; ! 690: char *errstr; ! 691: { ! 692: ! 693: pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); ! 694: ! 695: switch (error) { ! 696: case CLEAR: ! 697: if (lcp -> lcd_so) { ! 698: lcp -> lcd_so -> so_error = ECONNABORTED; ! 699: soisdisconnecting (lcp -> lcd_so); ! 700: } ! 701: pk_clear (lcp, diagnostic, 1); ! 702: break; ! 703: ! 704: case RESET: ! 705: pk_reset (lcp, diagnostic); ! 706: } ! 707: } ! 708: ! 709: /* ! 710: * This procedure is called during the DATA TRANSFER state to check ! 711: * and process the P(R) values received in the DATA, RR OR RNR ! 712: * packets. ! 713: */ ! 714: ! 715: pk_ack (lcp, pr) ! 716: struct pklcd *lcp; ! 717: unsigned pr; ! 718: { ! 719: register struct socket *so = lcp -> lcd_so; ! 720: ! 721: if (lcp -> lcd_output_window == pr) ! 722: return (PACKET_OK); ! 723: if (lcp -> lcd_output_window < lcp -> lcd_ssn) { ! 724: if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { ! 725: pk_procerror (RESET, lcp, ! 726: "p(r) flow control error", 2); ! 727: return (ERROR_PACKET); ! 728: } ! 729: } ! 730: else { ! 731: if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { ! 732: pk_procerror (RESET, lcp, ! 733: "p(r) flow control error #2", 2); ! 734: return (ERROR_PACKET); ! 735: } ! 736: } ! 737: ! 738: lcp -> lcd_output_window = pr; /* Rotate window. */ ! 739: if (lcp -> lcd_window_condition == TRUE) ! 740: lcp -> lcd_window_condition = FALSE; ! 741: ! 742: if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel)) ! 743: sowwakeup (so); ! 744: ! 745: return (PACKET_OK); ! 746: } ! 747: ! 748: /* ! 749: * This procedure decodes the X.25 level 3 packet returning a ! 750: * code to be used in switchs or arrays. ! 751: */ ! 752: ! 753: pk_decode (xp) ! 754: register struct x25_packet *xp; ! 755: { ! 756: register int type; ! 757: ! 758: if (xp -> fmt_identifier != 1) ! 759: return (INVALID_PACKET); ! 760: #ifdef ancient_history ! 761: /* ! 762: * Make sure that the logical channel group number is 0. ! 763: * This restriction may be removed at some later date. ! 764: */ ! 765: if (xp -> lc_group_number != 0) ! 766: return (INVALID_PACKET); ! 767: #endif ! 768: /* ! 769: * Test for data packet first. ! 770: */ ! 771: if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) ! 772: return (DATA); ! 773: ! 774: /* ! 775: * Test if flow control packet (RR or RNR). ! 776: */ ! 777: if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) ! 778: switch (xp -> packet_type & 0x1f) { ! 779: case X25_RR: ! 780: return (RR); ! 781: case X25_RNR: ! 782: return (RNR); ! 783: case X25_REJECT: ! 784: return (REJECT); ! 785: } ! 786: ! 787: /* ! 788: * Determine the rest of the packet types. ! 789: */ ! 790: switch (xp -> packet_type) { ! 791: case X25_CALL: ! 792: type = CALL; ! 793: break; ! 794: ! 795: case X25_CALL_ACCEPTED: ! 796: type = CALL_ACCEPTED; ! 797: break; ! 798: ! 799: case X25_CLEAR: ! 800: type = CLEAR; ! 801: break; ! 802: ! 803: case X25_CLEAR_CONFIRM: ! 804: type = CLEAR_CONF; ! 805: break; ! 806: ! 807: case X25_INTERRUPT: ! 808: type = INTERRUPT; ! 809: break; ! 810: ! 811: case X25_INTERRUPT_CONFIRM: ! 812: type = INTERRUPT_CONF; ! 813: break; ! 814: ! 815: case X25_RESET: ! 816: type = RESET; ! 817: break; ! 818: ! 819: case X25_RESET_CONFIRM: ! 820: type = RESET_CONF; ! 821: break; ! 822: ! 823: case X25_RESTART: ! 824: type = RESTART; ! 825: break; ! 826: ! 827: case X25_RESTART_CONFIRM: ! 828: type = RESTART_CONF; ! 829: break; ! 830: ! 831: case X25_DIAGNOSTIC: ! 832: type = DIAG_TYPE; ! 833: break; ! 834: ! 835: default: ! 836: type = INVALID_PACKET; ! 837: } ! 838: return (type); ! 839: } ! 840: ! 841: /* ! 842: * A restart packet has been received. Print out the reason ! 843: * for the restart. ! 844: */ ! 845: ! 846: pk_restartcause (pkp, xp) ! 847: struct pkcb *pkp; ! 848: register struct x25_packet *xp; ! 849: { ! 850: register struct x25config *xcp = pkp -> pk_xcp; ! 851: register int lcn = LCN(xp); ! 852: ! 853: switch (xp -> packet_data) { ! 854: case X25_RESTART_LOCAL_PROCEDURE_ERROR: ! 855: pk_message (lcn, xcp, "restart: local procedure error"); ! 856: break; ! 857: ! 858: case X25_RESTART_NETWORK_CONGESTION: ! 859: pk_message (lcn, xcp, "restart: network congestion"); ! 860: break; ! 861: ! 862: case X25_RESTART_NETWORK_OPERATIONAL: ! 863: pk_message (lcn, xcp, "restart: network operational"); ! 864: break; ! 865: ! 866: default: ! 867: pk_message (lcn, xcp, "restart: unknown cause"); ! 868: } ! 869: } ! 870: ! 871: #define MAXRESETCAUSE 7 ! 872: ! 873: int Reset_cause[] = { ! 874: EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG ! 875: }; ! 876: ! 877: /* ! 878: * A reset packet has arrived. Return the cause to the user. ! 879: */ ! 880: ! 881: pk_resetcause (pkp, xp) ! 882: struct pkcb *pkp; ! 883: register struct x25_packet *xp; ! 884: { ! 885: register struct pklcd *lcp = ! 886: pkp -> pk_chan[LCN(xp)]; ! 887: register int code = xp -> packet_data; ! 888: ! 889: if (code > MAXRESETCAUSE) ! 890: code = 7; /* EXRNCG */ ! 891: ! 892: pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x", ! 893: xp -> packet_data, 4[(u_char *)xp]); ! 894: ! 895: if (lcp -> lcd_so) ! 896: lcp -> lcd_so -> so_error = Reset_cause[code]; ! 897: } ! 898: ! 899: #define MAXCLEARCAUSE 25 ! 900: ! 901: int Clear_cause[] = { ! 902: EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, ! 903: 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, ! 904: 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC ! 905: }; ! 906: ! 907: /* ! 908: * A clear packet has arrived. Return the cause to the user. ! 909: */ ! 910: ! 911: pk_clearcause (pkp, xp) ! 912: struct pkcb *pkp; ! 913: register struct x25_packet *xp; ! 914: { ! 915: register struct pklcd *lcp = ! 916: pkp -> pk_chan[LCN(xp)]; ! 917: register int code = xp -> packet_data; ! 918: ! 919: if (code > MAXCLEARCAUSE) ! 920: code = 5; /* EXRNCG */ ! 921: if (lcp -> lcd_so) ! 922: lcp -> lcd_so -> so_error = Clear_cause[code]; ! 923: } ! 924: ! 925: char * ! 926: format_ntn (xcp) ! 927: register struct x25config *xcp; ! 928: { ! 929: ! 930: return (xcp -> xc_addr.x25_addr); ! 931: } ! 932: ! 933: /* VARARGS1 */ ! 934: pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) ! 935: struct x25config *xcp; ! 936: char *fmt; ! 937: { ! 938: ! 939: if (lcn) ! 940: if (pkcbhead -> pk_next) ! 941: printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); ! 942: else ! 943: printf ("X.25: lcn %d: ", lcn); ! 944: else ! 945: if (pkcbhead -> pk_next) ! 946: printf ("X.25(%s): ", format_ntn (xcp)); ! 947: else ! 948: printf ("X.25: "); ! 949: ! 950: printf (fmt, a1, a2, a3, a4, a5, a6); ! 951: printf ("\n"); ! 952: } ! 953: ! 954: pk_fragment (lcp, m0, qbit, mbit, wait) ! 955: struct mbuf *m0; ! 956: register struct pklcd *lcp; ! 957: { ! 958: register struct mbuf *m = m0; ! 959: register struct x25_packet *xp; ! 960: register struct sockbuf *sb; ! 961: struct mbuf *head = 0, *next, **mp = &head, *m_split (); ! 962: int totlen, psize = 1 << (lcp -> lcd_packetsize); ! 963: ! 964: if (m == 0) ! 965: return 0; ! 966: if (m -> m_flags & M_PKTHDR == 0) ! 967: panic ("pk_fragment"); ! 968: totlen = m -> m_pkthdr.len; ! 969: m -> m_act = 0; ! 970: sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; ! 971: do { ! 972: if (totlen > psize) { ! 973: if ((next = m_split (m, psize, wait)) == 0) ! 974: goto abort; ! 975: totlen -= psize; ! 976: } else ! 977: next = 0; ! 978: M_PREPEND(m, PKHEADERLN, wait); ! 979: if (m == 0) ! 980: goto abort; ! 981: *mp = m; ! 982: mp = & m -> m_act; ! 983: *mp = 0; ! 984: xp = mtod (m, struct x25_packet *); ! 985: 0[(char *)xp] = 0; ! 986: if (qbit) ! 987: xp -> q_bit = 1; ! 988: if (lcp -> lcd_flags & X25_DBIT) ! 989: xp -> d_bit = 1; ! 990: xp -> fmt_identifier = 1; ! 991: xp -> packet_type = X25_DATA; ! 992: SET_LCN(xp, lcp -> lcd_lcn); ! 993: if (next || (mbit && (totlen == psize || ! 994: (lcp -> lcd_flags & X25_DBIT)))) ! 995: MBIT(xp) = 1; ! 996: } while (m = next); ! 997: for (m = head; m; m = next) { ! 998: next = m -> m_act; ! 999: m -> m_act = 0; ! 1000: sbappendrecord (sb, m); ! 1001: } ! 1002: return 0; ! 1003: abort: ! 1004: if (wait) ! 1005: panic ("pk_fragment null mbuf after wait"); ! 1006: if (next) ! 1007: m_freem (next); ! 1008: for (m = head; m; m = next) { ! 1009: next = m -> m_act; ! 1010: m_freem (m); ! 1011: } ! 1012: return ENOBUFS; ! 1013: } ! 1014: ! 1015: struct mbuf * ! 1016: m_split (m0, len0, wait) ! 1017: register struct mbuf *m0; ! 1018: int len0; ! 1019: { ! 1020: register struct mbuf *m, *n; ! 1021: unsigned len = len0, remain; ! 1022: ! 1023: for (m = m0; m && len > m -> m_len; m = m -> m_next) ! 1024: len -= m -> m_len; ! 1025: if (m == 0) ! 1026: return (0); ! 1027: remain = m -> m_len - len; ! 1028: if (m0 -> m_flags & M_PKTHDR) { ! 1029: MGETHDR(n, wait, m0 -> m_type); ! 1030: if (n == 0) ! 1031: return (0); ! 1032: n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif; ! 1033: n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0; ! 1034: m0 -> m_pkthdr.len = len0; ! 1035: if (m -> m_flags & M_EXT) ! 1036: goto extpacket; ! 1037: if (remain > MHLEN) { ! 1038: /* m can't be the lead packet */ ! 1039: MH_ALIGN(n, 0); ! 1040: n -> m_next = m_split (m, len, wait); ! 1041: if (n -> m_next == 0) { ! 1042: (void) m_free (n); ! 1043: return (0); ! 1044: } else ! 1045: return (n); ! 1046: } else ! 1047: MH_ALIGN(n, remain); ! 1048: } else if (remain == 0) { ! 1049: n = m -> m_next; ! 1050: m -> m_next = 0; ! 1051: return (n); ! 1052: } else { ! 1053: MGET(n, wait, m -> m_type); ! 1054: if (n == 0) ! 1055: return (0); ! 1056: M_ALIGN(n, remain); ! 1057: } ! 1058: extpacket: ! 1059: if (m -> m_flags & M_EXT) { ! 1060: n -> m_flags |= M_EXT; ! 1061: n -> m_ext = m -> m_ext; ! 1062: mclrefcnt[mtocl (m -> m_ext.ext_buf)]++; ! 1063: n -> m_data = m -> m_data + len; ! 1064: } else { ! 1065: bcopy (mtod (m, caddr_t) + len, mtod (n, caddr_t), remain); ! 1066: } ! 1067: n -> m_len = remain; ! 1068: m -> m_len = len; ! 1069: n -> m_next = m -> m_next; ! 1070: m -> m_next = 0; ! 1071: return (n); ! 1072: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.