141709Ssklower /* 241709Ssklower * Copyright (c) University of British Columbia, 1984 341709Ssklower * Copyright (c) 1990 The Regents of the University of California. 441709Ssklower * All rights reserved. 541709Ssklower * 641709Ssklower * This code is derived from software contributed to Berkeley by 741709Ssklower * the Laboratory for Computation Vision and the Computer Science Department 841709Ssklower * of the University of British Columbia. 941709Ssklower * 1041709Ssklower * %sccs.include.redist.c% 1141709Ssklower * 12*45165Ssklower * @(#)pk_usrreq.c 7.7 (Berkeley) 08/30/90 1341709Ssklower */ 1441595Ssklower 1542140Ssklower #include "param.h" 1642140Ssklower #include "systm.h" 1742140Ssklower #include "mbuf.h" 1842140Ssklower #include "socket.h" 1942140Ssklower #include "protosw.h" 2042140Ssklower #include "socketvar.h" 2142140Ssklower #include "errno.h" 2241595Ssklower #include "ioctl.h" 2341595Ssklower #include "user.h" 2441595Ssklower #include "stat.h" 2541595Ssklower 2642140Ssklower #include "../net/if.h" 2741595Ssklower 2842140Ssklower #include "x25.h" 2942140Ssklower #include "pk.h" 3042140Ssklower #include "pk_var.h" 3142140Ssklower 3241595Ssklower struct x25_packet *pk_template (); 3341595Ssklower 3441595Ssklower /* 3541595Ssklower * 3641595Ssklower * X.25 Packet level protocol interface to socket abstraction. 3741595Ssklower * 3841595Ssklower * Process an X.25 user request on a logical channel. If this is a send 3941595Ssklower * request then m is the mbuf chain of the send data. If this is a timer 4041595Ssklower * expiration (called from the software clock routine) them timertype is 4141595Ssklower * the particular timer. 4241595Ssklower * 4341595Ssklower */ 4441595Ssklower 4541936Ssklower pk_usrreq (so, req, m, nam, control) 4641595Ssklower struct socket *so; 4741595Ssklower int req; 4841595Ssklower register struct mbuf *m, *nam; 4941936Ssklower struct mbuf *control; 5041595Ssklower { 5141595Ssklower register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 5241595Ssklower register struct x25_packet *xp; 5341936Ssklower register int error = 0; 5441595Ssklower 5541936Ssklower if (req == PRU_CONTROL) 5641936Ssklower return (pk_control(so, (int)m, (caddr_t)nam, 5741936Ssklower (struct ifnet *)control)); 5841936Ssklower if (control && control->m_len) { 5941936Ssklower error = EINVAL; 6041936Ssklower goto release; 6141595Ssklower } 6241936Ssklower if (lcp == NULL && req != PRU_ATTACH) { 6341936Ssklower error = EINVAL; 6441936Ssklower goto release; 6541595Ssklower } 6641595Ssklower 6741595Ssklower /* 6841595Ssklower pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, 6941595Ssklower req, (struct x25_packet *)0); 7041595Ssklower */ 7141595Ssklower 7241595Ssklower switch (req) { 7341595Ssklower /* 7441595Ssklower * X.25 attaches to socket via PRU_ATTACH and allocates a logical 7541595Ssklower * channel descriptor. If the socket is to receive connections, 7641595Ssklower * then the LISTEN state is entered. 7741595Ssklower */ 7841595Ssklower case PRU_ATTACH: 7941595Ssklower if (lcp) { 8041595Ssklower error = EISCONN; 8141595Ssklower /* Socket already connected. */ 8241595Ssklower break; 8341595Ssklower } 84*45165Ssklower lcp = pk_attach (so); 85*45165Ssklower if (lcp == 0) 86*45165Ssklower error = ENOBUFS; 8741595Ssklower break; 8841595Ssklower 8941595Ssklower /* 9041595Ssklower * Detach a logical channel from the socket. If the state of the 9141595Ssklower * channel is embryonic, simply discard it. Otherwise we have to 9241595Ssklower * initiate a PRU_DISCONNECT which will finish later. 9341595Ssklower */ 9441595Ssklower case PRU_DETACH: 9541595Ssklower pk_disconnect (lcp); 9641595Ssklower break; 9741595Ssklower 9841595Ssklower /* 9941595Ssklower * Give the socket an address. 10041595Ssklower */ 10141595Ssklower case PRU_BIND: 10241595Ssklower if (nam -> m_len == sizeof (struct x25_sockaddr)) 10341595Ssklower old_to_new (nam); 10441595Ssklower error = pk_bind (lcp, nam); 10541595Ssklower break; 10641595Ssklower 10741595Ssklower /* 10841595Ssklower * Prepare to accept connections. 10941595Ssklower */ 11041595Ssklower case PRU_LISTEN: 11141595Ssklower if (lcp -> lcd_ceaddr == 0) { 11241595Ssklower error = EDESTADDRREQ; 11341595Ssklower break; 11441595Ssklower } 11541595Ssklower lcp -> lcd_state = LISTEN; 11641595Ssklower lcp -> lcd_listen = pk_listenhead; 11741595Ssklower pk_listenhead = lcp; 11841595Ssklower break; 11941595Ssklower 12041595Ssklower /* 12141595Ssklower * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL 12241595Ssklower * and mark the socket as connecting. Set timer waiting for 12341595Ssklower * CALL ACCEPT or CLEAR. 12441595Ssklower */ 12541595Ssklower case PRU_CONNECT: 12641595Ssklower if (nam -> m_len == sizeof (struct x25_sockaddr)) 12741595Ssklower old_to_new (nam); 12842277Ssklower error = pk_connect (lcp, nam, (struct sockaddr_25 *)0); 12941595Ssklower break; 13041595Ssklower 13141595Ssklower /* 13241595Ssklower * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. 13341595Ssklower * The socket will be disconnected when we receive a confirmation 13441595Ssklower * or a clear collision. 13541595Ssklower */ 13641595Ssklower case PRU_DISCONNECT: 13741595Ssklower pk_disconnect (lcp); 13841595Ssklower break; 13941595Ssklower 14041595Ssklower /* 14141595Ssklower * Accept an INCOMING CALL. Most of the work has already been done 14241595Ssklower * by pk_input. Just return the callers address to the user. 14341595Ssklower */ 14441595Ssklower case PRU_ACCEPT: 14541595Ssklower if (lcp -> lcd_craddr == NULL) 14641595Ssklower break; 14741595Ssklower bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), 14841595Ssklower sizeof (struct sockaddr_x25)); 14941595Ssklower nam -> m_len = sizeof (struct sockaddr_x25); 15041595Ssklower if (lcp -> lcd_flags & X25_OLDSOCKADDR) 15141595Ssklower new_to_old (nam); 15241595Ssklower break; 15341595Ssklower 15441595Ssklower /* 15541595Ssklower * After a receive, we should send a RR. 15641595Ssklower */ 15741595Ssklower case PRU_RCVD: 15841595Ssklower lcp -> lcd_rxcnt++; 15941595Ssklower lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR); 16041595Ssklower pk_output (lcp); 16141595Ssklower break; 16241595Ssklower 16341595Ssklower /* 16441595Ssklower * Do send by placing data on the socket output queue. 16541595Ssklower * SHOULD WE USE m_cat HERE. 16641595Ssklower */ 16741595Ssklower case PRU_SEND: 16841595Ssklower error = pk_send (lcp, m); 16941595Ssklower break; 17041595Ssklower 17141595Ssklower /* 17241595Ssklower * Abort a virtual circuit. For example all completed calls 17341595Ssklower * waiting acceptance. 17441595Ssklower */ 17541595Ssklower case PRU_ABORT: 17641595Ssklower pk_disconnect (lcp); 17741595Ssklower break; 17841595Ssklower 17941595Ssklower /* Begin unimplemented hooks. */ 18041595Ssklower 18141595Ssklower case PRU_SHUTDOWN: 18241595Ssklower error = EOPNOTSUPP; 18341595Ssklower break; 18441595Ssklower 18541595Ssklower case PRU_CONTROL: 18641595Ssklower error = EOPNOTSUPP; 18741595Ssklower break; 18841595Ssklower 18941595Ssklower case PRU_SENSE: 19041595Ssklower #ifdef BSD4_3 19141595Ssklower ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; 19241595Ssklower #else 19341595Ssklower error = EOPNOTSUPP; 19441595Ssklower #endif 19541595Ssklower break; 19641595Ssklower 19741595Ssklower /* End unimplemented hooks. */ 19841595Ssklower 19941595Ssklower case PRU_SOCKADDR: 20041595Ssklower if (lcp -> lcd_ceaddr == 0) 20141595Ssklower return (EADDRNOTAVAIL); 20241595Ssklower nam -> m_len = sizeof (struct sockaddr_x25); 20341595Ssklower bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), 20441595Ssklower sizeof (struct sockaddr_x25)); 20541595Ssklower if (lcp -> lcd_flags & X25_OLDSOCKADDR) 20641595Ssklower new_to_old (nam); 20741595Ssklower break; 20841595Ssklower 20941595Ssklower case PRU_PEERADDR: 21041595Ssklower if (lcp -> lcd_state != DATA_TRANSFER) 21141595Ssklower return (ENOTCONN); 21241595Ssklower nam -> m_len = sizeof (struct sockaddr_x25); 21341595Ssklower bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : 21441595Ssklower (caddr_t)lcp -> lcd_ceaddr, 21541595Ssklower mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); 21641595Ssklower if (lcp -> lcd_flags & X25_OLDSOCKADDR) 21741595Ssklower new_to_old (nam); 21841595Ssklower break; 21941595Ssklower 22041595Ssklower /* 22141595Ssklower * Receive INTERRUPT packet. 22241595Ssklower */ 22341595Ssklower case PRU_RCVOOB: 22441595Ssklower m -> m_len = 1; 22541595Ssklower *mtod (m, char *) = lcp -> lcd_intrdata; 22641595Ssklower break; 22741595Ssklower 22841595Ssklower /* 22941595Ssklower * Send INTERRUPT packet. 23041595Ssklower */ 23141595Ssklower case PRU_SENDOOB: 23241595Ssklower m_freem (m); 23341595Ssklower if (lcp -> lcd_intrconf_pending) { 23441595Ssklower error = ETOOMANYREFS; 23541595Ssklower break; 23641595Ssklower } 23741595Ssklower lcp -> lcd_intrcnt++; 23841595Ssklower xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT); 23941595Ssklower xp -> packet_data = 0; 24041595Ssklower (dtom (xp)) -> m_len++; 24141595Ssklower pk_output (lcp); 24241595Ssklower break; 24341595Ssklower 24441595Ssklower default: 24541595Ssklower panic ("pk_usrreq"); 24641595Ssklower } 24741936Ssklower release: 24841936Ssklower if (control != NULL) 24941936Ssklower m_freem(control); 25041936Ssklower if (m != NULL) 25141936Ssklower m_freem(m); 25241595Ssklower return (error); 25341595Ssklower } 25441595Ssklower 25542277Ssklower /* 25642277Ssklower * If you want to use UBC X.25 level 3 in conjunction with some 25742277Ssklower * other X.25 level 2 driver, have the ifp->if_ioctl routine 25842277Ssklower * assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25. 25942277Ssklower */ 26042277Ssklower /* ARGSUSED */ 26142277Ssklower pk_start (lcp) 26242277Ssklower register struct pklcd *lcp; 26342277Ssklower { 26442277Ssklower extern int pk_send(); 26542277Ssklower 266*45165Ssklower lcp -> lcd_send = pk_send; 26742277Ssklower return (pk_output(lcp)); 26842277Ssklower } 26942277Ssklower 27041595Ssklower /*ARGSUSED*/ 27141595Ssklower pk_control (so, cmd, data, ifp) 27241595Ssklower struct socket *so; 27341595Ssklower int cmd; 27441595Ssklower caddr_t data; 27541595Ssklower register struct ifnet *ifp; 27641595Ssklower { 27742140Ssklower register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; 27841595Ssklower register struct ifaddr *ifa = 0; 27941936Ssklower register struct x25_ifaddr *ia = 0; 28042277Ssklower struct pklcd *dev_lcp = 0; 28141936Ssklower int error, s; 28241936Ssklower unsigned n; 28341595Ssklower 28441595Ssklower /* 28541595Ssklower * Find address for this interface, if it exists. 28641595Ssklower */ 28741595Ssklower if (ifp) 28841595Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 28942140Ssklower if (ifa->ifa_addr->sa_family == AF_CCITT) 29041595Ssklower break; 29141595Ssklower 29241936Ssklower ia = (struct x25_ifaddr *)ifa; 29341595Ssklower switch (cmd) { 29442140Ssklower case SIOCGIFCONF_X25: 29541595Ssklower if (ifa == 0) 29641595Ssklower return (EADDRNOTAVAIL); 297*45165Ssklower ifr->ifr_xc = ia->ia_xc; 29841595Ssklower return (0); 29941595Ssklower 30042140Ssklower case SIOCSIFCONF_X25: 301*45165Ssklower if (error = suser(u.u_cred, &u.u_acflag)) 302*45165Ssklower return (error); 30341595Ssklower if (ifp == 0) 30441595Ssklower panic("pk_control"); 30541595Ssklower if (ifa == (struct ifaddr *)0) { 30641595Ssklower register struct mbuf *m; 30741595Ssklower 30842277Ssklower MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), 30942277Ssklower M_IFADDR, M_WAITOK); 31042277Ssklower if (ia == 0) 31141595Ssklower return (ENOBUFS); 31241595Ssklower if (ifa = ifp->if_addrlist) { 31341595Ssklower for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 31441595Ssklower ; 31541936Ssklower ifa->ifa_next = &ia->ia_ifa; 31641595Ssklower } else 31741936Ssklower ifp->if_addrlist = &ia->ia_ifa; 31841936Ssklower ifa = &ia->ia_ifa; 31942140Ssklower ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 320*45165Ssklower ifa->ifa_addr = (struct sockaddr *)&ia->ia_xc.xc_addr; 32142140Ssklower ia->ia_ifp = ifp; 32242140Ssklower ia->ia_pkcb.pk_ia = ia; 32342140Ssklower ia->ia_pkcb.pk_next = pkcbhead; 32442140Ssklower pkcbhead = &ia->ia_pkcb; 32541595Ssklower } 32642140Ssklower ia->ia_xcp = &(ifr->ifr_xc); 327*45165Ssklower if (ia->ia_chan && (ia->ia_maxlcn != ia->ia_xcp->xc_maxlcn)) { 328*45165Ssklower pk_restart(&ia->ia_pkcb, X25_RESTART_NETWORK_CONGESTION); 32942277Ssklower dev_lcp = ia->ia_chan[0]; 33041936Ssklower free((caddr_t)ia->ia_chan, M_IFADDR); 33142277Ssklower ia->ia_chan = 0; 33241936Ssklower } 33342277Ssklower if (ia->ia_chan == 0) { 33442277Ssklower n = ia->ia_maxlcn * sizeof(struct pklcd *); 33542140Ssklower ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR); 33642277Ssklower if (ia->ia_chan) { 33742277Ssklower bzero((caddr_t)ia->ia_chan, n); 33842277Ssklower if (dev_lcp == 0) 33942277Ssklower dev_lcp = pk_attach((struct socket *)0); 340*45165Ssklower ia->ia_chan[0] = dev_lcp; 34142277Ssklower } else { 34242277Ssklower if (dev_lcp) 34342277Ssklower pk_close(dev_lcp); 34442277Ssklower ia->ia_xcp = &ia->ia_xc; 34542277Ssklower return (ENOBUFS); 34642277Ssklower } 34742140Ssklower } 34841595Ssklower /* 34941595Ssklower * Give the interface a chance to initialize if this 35041595Ssklower * is its first address, and to validate the address. 35141595Ssklower */ 35241936Ssklower s = splimp(); 35341936Ssklower if (ifp->if_ioctl) 354*45165Ssklower error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa); 35541595Ssklower splx(s); 35641936Ssklower if (error == 0) { 35741936Ssklower ia->ia_xc = *ia->ia_xcp; 35841936Ssklower } 35941936Ssklower ia->ia_xcp = &ia->ia_xc; 36041936Ssklower return (error); 36141595Ssklower 36241595Ssklower default: 36341595Ssklower if (ifp == 0 || ifp->if_ioctl == 0) 36441595Ssklower return (EOPNOTSUPP); 36541595Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 36641595Ssklower } 36741595Ssklower } 36841595Ssklower 369*45165Ssklower pk_ctloutput(cmd, so, level, optname, mp) 370*45165Ssklower struct socket *so; 371*45165Ssklower struct mbuf **mp; 372*45165Ssklower int cmd, level, optname; 373*45165Ssklower { 374*45165Ssklower register struct mbuf *m = *mp; 375*45165Ssklower int error; 376*45165Ssklower 377*45165Ssklower if (cmd == PRCO_SETOPT) switch (optname) { 378*45165Ssklower case PK_ACCTFILE: 379*45165Ssklower if (m == 0) 380*45165Ssklower return (EINVAL); 381*45165Ssklower if (m->m_len) 382*45165Ssklower error = pk_accton(mtod(m, char *)); 383*45165Ssklower else 384*45165Ssklower error = pk_accton((char *)0); 385*45165Ssklower (void) m_freem(m); 386*45165Ssklower *mp = 0; 387*45165Ssklower return (error); 388*45165Ssklower } 389*45165Ssklower if (*mp) { 390*45165Ssklower (void) m_freem(*mp); 391*45165Ssklower *mp = 0; 392*45165Ssklower } 393*45165Ssklower return (EOPNOTSUPP); 394*45165Ssklower 395*45165Ssklower } 396*45165Ssklower 39741595Ssklower /* 39841595Ssklower * Do an in-place conversion of an "old style" 39941595Ssklower * socket address to the new style 40041595Ssklower */ 40141595Ssklower 40241595Ssklower static 40341595Ssklower old_to_new (m) 40441595Ssklower register struct mbuf *m; 40541595Ssklower { 40641595Ssklower register struct x25_sockaddr *oldp; 40741595Ssklower register struct sockaddr_x25 *newp; 40841595Ssklower register char *ocp, *ncp; 40941595Ssklower struct sockaddr_x25 new; 41041595Ssklower 41141595Ssklower oldp = mtod (m, struct x25_sockaddr *); 41241595Ssklower newp = &new; 41341595Ssklower bzero ((caddr_t)newp, sizeof (*newp)); 41441595Ssklower 41541595Ssklower newp -> x25_family = AF_CCITT; 41641595Ssklower newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 41741595Ssklower | X25_MQBIT | X25_OLDSOCKADDR; 41841595Ssklower if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 41941595Ssklower newp -> x25_opts.op_psize = X25_PS128; 42041595Ssklower bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 42141595Ssklower (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 42241595Ssklower bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 42341595Ssklower newp -> x25_udlen = 4; 42441595Ssklower 42541595Ssklower ocp = (caddr_t)oldp -> xaddr_userdata; 42641595Ssklower ncp = newp -> x25_udata + 4; 42741595Ssklower while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 42841595Ssklower *ncp++ = *ocp++; 42941595Ssklower newp -> x25_udlen++; 43041595Ssklower } 43141595Ssklower 43241595Ssklower bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 43341595Ssklower m->m_len = sizeof (*newp); 43441595Ssklower } 43541595Ssklower 43641595Ssklower /* 43741595Ssklower * Do an in-place conversion of a new style 43841595Ssklower * socket address to the old style 43941595Ssklower */ 44041595Ssklower 44141595Ssklower static 44241595Ssklower new_to_old (m) 44341595Ssklower register struct mbuf *m; 44441595Ssklower { 44541595Ssklower register struct x25_sockaddr *oldp; 44641595Ssklower register struct sockaddr_x25 *newp; 44741595Ssklower register char *ocp, *ncp; 44841595Ssklower struct x25_sockaddr old; 44941595Ssklower 45041595Ssklower oldp = &old; 45141595Ssklower newp = mtod (m, struct sockaddr_x25 *); 45241595Ssklower bzero ((caddr_t)oldp, sizeof (*oldp)); 45341595Ssklower 45441595Ssklower oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 45541595Ssklower if (newp -> x25_opts.op_psize == X25_PS128) 45641595Ssklower oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 45741595Ssklower ocp = (char *)oldp -> xaddr_addr; 45841595Ssklower ncp = newp -> x25_addr; 45941595Ssklower while (*ncp) { 46041595Ssklower *ocp++ = *ncp++; 46141595Ssklower oldp -> xaddr_len++; 46241595Ssklower } 46341595Ssklower 46441595Ssklower bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 46541595Ssklower bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 46641595Ssklower (unsigned)(newp -> x25_udlen - 4)); 46741595Ssklower 46841595Ssklower bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 46941595Ssklower m -> m_len = sizeof (*oldp); 47041595Ssklower } 47141595Ssklower 47241595Ssklower pk_send (lcp, m) 47341595Ssklower register struct pklcd *lcp; 47441595Ssklower register struct mbuf *m; 47541595Ssklower { 47641595Ssklower register struct x25_packet *xp; 47741595Ssklower register struct mbuf *m0; 47841595Ssklower register int len; 47941595Ssklower 48041595Ssklower m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA))); 48141595Ssklower m0 -> m_next = m; 48241595Ssklower /* 48341595Ssklower * Application has elected (at call setup time) to prepend 48441595Ssklower * a control byte to each packet written indicating m-bit 48541595Ssklower * and q-bit status. Examine and then discard this byte. 48641595Ssklower */ 48741595Ssklower if (lcp -> lcd_flags & X25_MQBIT) { 48841595Ssklower register octet *cp; 48941595Ssklower 49041595Ssklower if (m -> m_len < 1) { 49141595Ssklower m_freem (m0); 49241595Ssklower return (EMSGSIZE); 49341595Ssklower } 49441595Ssklower cp = mtod (m, octet *); 49541595Ssklower if (*cp & 0x80) /* XXX */ 49641595Ssklower xp -> q_bit = 1; 49741595Ssklower xp -> packet_type |= (*cp & 0x40) >> 2; /* XXX */ 49841595Ssklower m -> m_len--; 49941936Ssklower m -> m_data++; 50041595Ssklower } 50141595Ssklower len = m -> m_len; 50241595Ssklower while (m -> m_next) { 50341595Ssklower m = m -> m_next; 50441595Ssklower len += m -> m_len; 50541595Ssklower } 50641595Ssklower if (len > (1 << lcp -> lcd_packetsize)) { 50741595Ssklower m_freem (m0); 50841595Ssklower return (EMSGSIZE); 50941595Ssklower } 51042277Ssklower if (lcp -> lcd_so) 51142277Ssklower sbappendrecord (&lcp -> lcd_so -> so_snd, m0); 51242277Ssklower else 51343362Ssklower sbappendrecord (&lcp -> lcd_sb, m0); 51441595Ssklower lcp -> lcd_template = 0; 51541595Ssklower lcp -> lcd_txcnt++; 51641595Ssklower pk_output (lcp); 51741595Ssklower return (0); 51841595Ssklower } 519