home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netccitt / pk_usrreq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  15.1 KB  |  596 lines

  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. }
  596.