|
|
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_usrreq.c 7.16 (Berkeley) 6/27/91 ! 39: */ ! 40: ! 41: #include "param.h" ! 42: #include "systm.h" ! 43: #include "mbuf.h" ! 44: #include "socket.h" ! 45: #include "socketvar.h" ! 46: #include "protosw.h" ! 47: #include "errno.h" ! 48: #include "ioctl.h" ! 49: #include "stat.h" ! 50: ! 51: #include "../net/if.h" ! 52: #include "../net/route.h" ! 53: ! 54: #include "x25.h" ! 55: #include "pk.h" ! 56: #include "pk_var.h" ! 57: ! 58: /* ! 59: * ! 60: * X.25 Packet level protocol interface to socket abstraction. ! 61: * ! 62: * Process an X.25 user request on a logical channel. If this is a send ! 63: * request then m is the mbuf chain of the send data. If this is a timer ! 64: * expiration (called from the software clock routine) them timertype is ! 65: * the particular timer. ! 66: * ! 67: */ ! 68: ! 69: pk_usrreq (so, req, m, nam, control) ! 70: struct socket *so; ! 71: int req; ! 72: register struct mbuf *m, *nam; ! 73: struct mbuf *control; ! 74: { ! 75: register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; ! 76: register int error = 0; ! 77: ! 78: if (req == PRU_CONTROL) ! 79: return (pk_control (so, (int)m, (caddr_t)nam, ! 80: (struct ifnet *)control)); ! 81: if (control && control -> m_len) { ! 82: error = EINVAL; ! 83: goto release; ! 84: } ! 85: if (lcp == NULL && req != PRU_ATTACH) { ! 86: error = EINVAL; ! 87: goto release; ! 88: } ! 89: ! 90: /* ! 91: pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, ! 92: req, (struct x25_packet *)0); ! 93: */ ! 94: ! 95: switch (req) { ! 96: /* ! 97: * X.25 attaches to socket via PRU_ATTACH and allocates a logical ! 98: * channel descriptor. If the socket is to receive connections, ! 99: * then the LISTEN state is entered. ! 100: */ ! 101: case PRU_ATTACH: ! 102: if (lcp) { ! 103: error = EISCONN; ! 104: /* Socket already connected. */ ! 105: break; ! 106: } ! 107: lcp = pk_attach (so); ! 108: if (lcp == 0) ! 109: error = ENOBUFS; ! 110: break; ! 111: ! 112: /* ! 113: * Detach a logical channel from the socket. If the state of the ! 114: * channel is embryonic, simply discard it. Otherwise we have to ! 115: * initiate a PRU_DISCONNECT which will finish later. ! 116: */ ! 117: case PRU_DETACH: ! 118: pk_disconnect (lcp); ! 119: break; ! 120: ! 121: /* ! 122: * Give the socket an address. ! 123: */ ! 124: case PRU_BIND: ! 125: if (nam -> m_len == sizeof (struct x25_sockaddr)) ! 126: old_to_new (nam); ! 127: error = pk_bind (lcp, nam); ! 128: break; ! 129: ! 130: /* ! 131: * Prepare to accept connections. ! 132: */ ! 133: case PRU_LISTEN: ! 134: error = pk_listen (lcp); ! 135: break; ! 136: ! 137: /* ! 138: * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL ! 139: * and mark the socket as connecting. Set timer waiting for ! 140: * CALL ACCEPT or CLEAR. ! 141: */ ! 142: case PRU_CONNECT: ! 143: if (nam -> m_len == sizeof (struct x25_sockaddr)) ! 144: old_to_new (nam); ! 145: if (pk_checksockaddr (nam)) ! 146: return (EINVAL); ! 147: error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *)); ! 148: break; ! 149: ! 150: /* ! 151: * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. ! 152: * The socket will be disconnected when we receive a confirmation ! 153: * or a clear collision. ! 154: */ ! 155: case PRU_DISCONNECT: ! 156: pk_disconnect (lcp); ! 157: break; ! 158: ! 159: /* ! 160: * Accept an INCOMING CALL. Most of the work has already been done ! 161: * by pk_input. Just return the callers address to the user. ! 162: */ ! 163: case PRU_ACCEPT: ! 164: if (lcp -> lcd_craddr == NULL) ! 165: break; ! 166: bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), ! 167: sizeof (struct sockaddr_x25)); ! 168: nam -> m_len = sizeof (struct sockaddr_x25); ! 169: if (lcp -> lcd_flags & X25_OLDSOCKADDR) ! 170: new_to_old (nam); ! 171: break; ! 172: ! 173: /* ! 174: * After a receive, we should send a RR. ! 175: */ ! 176: case PRU_RCVD: ! 177: pk_flowcontrol (lcp, /*sbspace (&so -> so_rcv) <= */ 0, 1); ! 178: break; ! 179: ! 180: /* ! 181: * Send INTERRUPT packet. ! 182: */ ! 183: case PRU_SENDOOB: ! 184: if (m == 0) { ! 185: MGETHDR(m, M_WAITOK, MT_OOBDATA); ! 186: m -> m_pkthdr.len = m -> m_len = 1; ! 187: *mtod (m, octet *) = 0; ! 188: } ! 189: if (m -> m_pkthdr.len > 32) { ! 190: m_freem (m); ! 191: error = EMSGSIZE; ! 192: break; ! 193: } ! 194: MCHTYPE(m, MT_OOBDATA); ! 195: /* FALLTHROUGH */ ! 196: ! 197: /* ! 198: * Do send by placing data on the socket output queue. ! 199: */ ! 200: case PRU_SEND: ! 201: if (control) { ! 202: register struct cmsghdr *ch = mtod (m, struct cmsghdr *); ! 203: control -> m_len -= sizeof (*ch); ! 204: control -> m_data += sizeof (*ch); ! 205: error = pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level, ! 206: ch -> cmsg_type, &control); ! 207: } ! 208: if (error == 0 && m) ! 209: error = pk_send (lcp, m); ! 210: break; ! 211: ! 212: /* ! 213: * Abort a virtual circuit. For example all completed calls ! 214: * waiting acceptance. ! 215: */ ! 216: case PRU_ABORT: ! 217: pk_disconnect (lcp); ! 218: break; ! 219: ! 220: /* Begin unimplemented hooks. */ ! 221: ! 222: case PRU_SHUTDOWN: ! 223: error = EOPNOTSUPP; ! 224: break; ! 225: ! 226: case PRU_CONTROL: ! 227: error = EOPNOTSUPP; ! 228: break; ! 229: ! 230: case PRU_SENSE: ! 231: #ifdef BSD4_3 ! 232: ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; ! 233: #else ! 234: error = EOPNOTSUPP; ! 235: #endif ! 236: break; ! 237: ! 238: /* End unimplemented hooks. */ ! 239: ! 240: case PRU_SOCKADDR: ! 241: if (lcp -> lcd_ceaddr == 0) ! 242: return (EADDRNOTAVAIL); ! 243: nam -> m_len = sizeof (struct sockaddr_x25); ! 244: bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), ! 245: sizeof (struct sockaddr_x25)); ! 246: if (lcp -> lcd_flags & X25_OLDSOCKADDR) ! 247: new_to_old (nam); ! 248: break; ! 249: ! 250: case PRU_PEERADDR: ! 251: if (lcp -> lcd_state != DATA_TRANSFER) ! 252: return (ENOTCONN); ! 253: nam -> m_len = sizeof (struct sockaddr_x25); ! 254: bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : ! 255: (caddr_t)lcp -> lcd_ceaddr, ! 256: mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); ! 257: if (lcp -> lcd_flags & X25_OLDSOCKADDR) ! 258: new_to_old (nam); ! 259: break; ! 260: ! 261: /* ! 262: * Receive INTERRUPT packet. ! 263: */ ! 264: case PRU_RCVOOB: ! 265: if (so -> so_options & SO_OOBINLINE) { ! 266: register struct mbuf *n = so -> so_rcv.sb_mb; ! 267: if (n && n -> m_type == MT_OOBDATA) { ! 268: unsigned len = n -> m_pkthdr.len; ! 269: so -> so_rcv.sb_mb = n -> m_nextpkt; ! 270: if (len != n -> m_len && ! 271: (n = m_pullup (n, len)) == 0) ! 272: break; ! 273: m -> m_len = len; ! 274: bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len); ! 275: m_freem (n); ! 276: } ! 277: break; ! 278: } ! 279: m -> m_len = 1; ! 280: *mtod (m, char *) = lcp -> lcd_intrdata; ! 281: break; ! 282: ! 283: default: ! 284: panic ("pk_usrreq"); ! 285: } ! 286: release: ! 287: if (control != NULL) ! 288: m_freem (control); ! 289: return (error); ! 290: } ! 291: ! 292: /* ! 293: * If you want to use UBC X.25 level 3 in conjunction with some ! 294: * other X.25 level 2 driver, have the ifp -> if_ioctl routine ! 295: * assign pk_start to ia -> ia_start when called with SIOCSIFCONF_X25. ! 296: */ ! 297: /* ARGSUSED */ ! 298: pk_start (lcp) ! 299: register struct pklcd *lcp; ! 300: { ! 301: pk_output (lcp); ! 302: return (0); /* XXX pk_output should return a value */ ! 303: } ! 304: ! 305: #ifndef _offsetof ! 306: #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) ! 307: #endif ! 308: struct sockaddr_x25 pk_sockmask = { ! 309: _offsetof(struct sockaddr_x25, x25_addr[0]), ! 310: 0, -1}; ! 311: ! 312: /*ARGSUSED*/ ! 313: pk_control (so, cmd, data, ifp) ! 314: struct socket *so; ! 315: int cmd; ! 316: caddr_t data; ! 317: register struct ifnet *ifp; ! 318: { ! 319: register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; ! 320: register struct ifaddr *ifa = 0; ! 321: register struct x25_ifaddr *ia = 0; ! 322: struct pklcd *dev_lcp = 0; ! 323: int error, s, old_maxlcn; ! 324: unsigned n; ! 325: ! 326: /* ! 327: * Find address for this interface, if it exists. ! 328: */ ! 329: if (ifp) ! 330: for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next) ! 331: if (ifa -> ifa_addr -> sa_family == AF_CCITT) ! 332: break; ! 333: ! 334: ia = (struct x25_ifaddr *)ifa; ! 335: switch (cmd) { ! 336: case SIOCGIFCONF_X25: ! 337: if (ifa == 0) ! 338: return (EADDRNOTAVAIL); ! 339: ifr -> ifr_xc = ia -> ia_xc; ! 340: return (0); ! 341: ! 342: case SIOCSIFCONF_X25: ! 343: if ((so->so_state & SS_PRIV) == 0) ! 344: return (EPERM); ! 345: if (ifp == 0) ! 346: panic ("pk_control"); ! 347: if (ifa == (struct ifaddr *)0) { ! 348: register struct mbuf *m; ! 349: ! 350: MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), ! 351: M_IFADDR, M_WAITOK); ! 352: if (ia == 0) ! 353: return (ENOBUFS); ! 354: bzero ((caddr_t)ia, sizeof (*ia)); ! 355: if (ifa = ifp -> if_addrlist) { ! 356: for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next) ! 357: ; ! 358: ifa -> ifa_next = &ia -> ia_ifa; ! 359: } else ! 360: ifp -> if_addrlist = &ia -> ia_ifa; ! 361: ifa = &ia -> ia_ifa; ! 362: ifa -> ifa_netmask = (struct sockaddr *)&pk_sockmask; ! 363: ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr; ! 364: ifa -> ifa_dstaddr = (struct sockaddr *)&ia -> ia_dstaddr; /* XXX */ ! 365: ia -> ia_ifp = ifp; ! 366: ia -> ia_dstaddr.x25_family = AF_CCITT; ! 367: ia -> ia_dstaddr.x25_len = pk_sockmask.x25_len; ! 368: } else { ! 369: rtinit (ifa, (int)RTM_DELETE, 0); ! 370: } ! 371: old_maxlcn = ia -> ia_maxlcn; ! 372: ia -> ia_xc = ifr -> ifr_xc; ! 373: ia -> ia_dstaddr.x25_net = ia -> ia_xc.xc_addr.x25_net; ! 374: if (ia -> ia_maxlcn != old_maxlcn && old_maxlcn != 0) { ! 375: /* VERY messy XXX */ ! 376: register struct pkcb *pkp; ! 377: for (pkp = pkcbhead; pkp; pkp = pkp -> pk_next) ! 378: if (pkp -> pk_ia == ia) ! 379: pk_resize (pkp); ! 380: } ! 381: /* ! 382: * Give the interface a chance to initialize if this ! 383: * is its first address, and to validate the address. ! 384: */ ! 385: ia -> ia_start = pk_start; ! 386: s = splimp(); ! 387: if (ifp -> if_ioctl) ! 388: error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25, ifa); ! 389: if (error) ! 390: ifp -> if_flags &= ~IFF_UP; ! 391: else ! 392: error = rtinit (ifa, (int)RTM_ADD, RTF_UP); ! 393: splx (s); ! 394: return (error); ! 395: ! 396: default: ! 397: if (ifp == 0 || ifp -> if_ioctl == 0) ! 398: return (EOPNOTSUPP); ! 399: return ((*ifp -> if_ioctl)(ifp, cmd, data)); ! 400: } ! 401: } ! 402: ! 403: pk_ctloutput (cmd, so, level, optname, mp) ! 404: struct socket *so; ! 405: struct mbuf **mp; ! 406: int cmd, level, optname; ! 407: { ! 408: register struct mbuf *m = *mp; ! 409: register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; ! 410: int error = EOPNOTSUPP; ! 411: ! 412: if (m == 0) ! 413: return (EINVAL); ! 414: if (cmd == PRCO_SETOPT) switch (optname) { ! 415: case PK_FACILITIES: ! 416: if (m == 0) ! 417: return (EINVAL); ! 418: lcp -> lcd_facilities = m; ! 419: *mp = 0; ! 420: return (0); ! 421: ! 422: case PK_ACCTFILE: ! 423: if ((so->so_state & SS_PRIV) == 0) ! 424: error = EPERM; ! 425: else if (m -> m_len) ! 426: error = pk_accton (mtod (m, char *)); ! 427: else ! 428: error = pk_accton ((char *)0); ! 429: break; ! 430: ! 431: case PK_RTATTACH: ! 432: error = pk_rtattach (so, m); ! 433: break; ! 434: ! 435: case PK_PRLISTEN: ! 436: error = pk_user_protolisten (mtod (m, u_char *)); ! 437: } ! 438: if (*mp) { ! 439: (void) m_freem (*mp); ! 440: *mp = 0; ! 441: } ! 442: return (error); ! 443: ! 444: } ! 445: ! 446: ! 447: /* ! 448: * Do an in-place conversion of an "old style" ! 449: * socket address to the new style ! 450: */ ! 451: ! 452: static ! 453: old_to_new (m) ! 454: register struct mbuf *m; ! 455: { ! 456: register struct x25_sockaddr *oldp; ! 457: register struct sockaddr_x25 *newp; ! 458: register char *ocp, *ncp; ! 459: struct sockaddr_x25 new; ! 460: ! 461: oldp = mtod (m, struct x25_sockaddr *); ! 462: newp = &new; ! 463: bzero ((caddr_t)newp, sizeof (*newp)); ! 464: ! 465: newp -> x25_family = AF_CCITT; ! 466: newp -> x25_len = sizeof(*newp); ! 467: newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE) ! 468: | X25_MQBIT | X25_OLDSOCKADDR; ! 469: if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ ! 470: newp -> x25_opts.op_psize = X25_PS128; ! 471: bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, ! 472: (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); ! 473: if (bcmp ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4) != 0) { ! 474: bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); ! 475: newp -> x25_udlen = 4; ! 476: } ! 477: ocp = (caddr_t)oldp -> xaddr_userdata; ! 478: ncp = newp -> x25_udata + 4; ! 479: while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { ! 480: if (newp -> x25_udlen == 0) ! 481: newp -> x25_udlen = 4; ! 482: *ncp++ = *ocp++; ! 483: newp -> x25_udlen++; ! 484: } ! 485: bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); ! 486: m -> m_len = sizeof (*newp); ! 487: } ! 488: ! 489: /* ! 490: * Do an in-place conversion of a new style ! 491: * socket address to the old style ! 492: */ ! 493: ! 494: static ! 495: new_to_old (m) ! 496: register struct mbuf *m; ! 497: { ! 498: register struct x25_sockaddr *oldp; ! 499: register struct sockaddr_x25 *newp; ! 500: register char *ocp, *ncp; ! 501: struct x25_sockaddr old; ! 502: ! 503: oldp = &old; ! 504: newp = mtod (m, struct sockaddr_x25 *); ! 505: bzero ((caddr_t)oldp, sizeof (*oldp)); ! 506: ! 507: oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; ! 508: if (newp -> x25_opts.op_psize == X25_PS128) ! 509: oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ ! 510: ocp = (char *)oldp -> xaddr_addr; ! 511: ncp = newp -> x25_addr; ! 512: while (*ncp) { ! 513: *ocp++ = *ncp++; ! 514: oldp -> xaddr_len++; ! 515: } ! 516: ! 517: bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); ! 518: if (newp -> x25_udlen > 4) ! 519: bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, ! 520: (unsigned)(newp -> x25_udlen - 4)); ! 521: ! 522: bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); ! 523: m -> m_len = sizeof (*oldp); ! 524: } ! 525: ! 526: ! 527: pk_checksockaddr (m) ! 528: struct mbuf *m; ! 529: { ! 530: register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *); ! 531: register char *cp; ! 532: ! 533: if (m -> m_len != sizeof (struct sockaddr_x25)) ! 534: return (1); ! 535: if (sa -> x25_family != AF_CCITT || ! 536: sa -> x25_udlen > sizeof (sa -> x25_udata)) ! 537: return (1); ! 538: for (cp = sa -> x25_addr; *cp; cp++) { ! 539: if (*cp < '0' || *cp > '9' || ! 540: cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1]) ! 541: return (1); ! 542: } ! 543: return (0); ! 544: } ! 545: ! 546: pk_send (lcp, m) ! 547: struct pklcd *lcp; ! 548: register struct mbuf *m; ! 549: { ! 550: int mqbit = 0, error = 0; ! 551: register struct x25_packet *xp; ! 552: register struct socket *so; ! 553: ! 554: if (m -> m_type == MT_OOBDATA) { ! 555: if (lcp -> lcd_intrconf_pending) ! 556: error = ETOOMANYREFS; ! 557: if (m -> m_pkthdr.len > 32) ! 558: error = EMSGSIZE; ! 559: M_PREPEND(m, PKHEADERLN, M_WAITOK); ! 560: if (m == 0 || error) ! 561: goto bad; ! 562: *(mtod (m, octet *)) = 0; ! 563: xp = mtod (m, struct x25_packet *); ! 564: xp -> fmt_identifier = 1; ! 565: xp -> packet_type = X25_INTERRUPT; ! 566: SET_LCN(xp, lcp -> lcd_lcn); ! 567: sbinsertoob ( (so = lcp -> lcd_so) ? ! 568: &so -> so_snd : &lcp -> lcd_sb, m); ! 569: goto send; ! 570: } ! 571: /* ! 572: * Application has elected (at call setup time) to prepend ! 573: * a control byte to each packet written indicating m-bit ! 574: * and q-bit status. Examine and then discard this byte. ! 575: */ ! 576: if (lcp -> lcd_flags & X25_MQBIT) { ! 577: if (m -> m_len < 1) { ! 578: m_freem (m); ! 579: return (EMSGSIZE); ! 580: } ! 581: mqbit = *(mtod (m, u_char *)); ! 582: m -> m_len--; ! 583: m -> m_data++; ! 584: m -> m_pkthdr.len--; ! 585: } ! 586: error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1); ! 587: send: ! 588: if (error == 0 && lcp -> lcd_state == DATA_TRANSFER) ! 589: lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */ ! 590: return (error); ! 591: bad: ! 592: if (m) ! 593: m_freem (m); ! 594: return (error); ! 595: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.