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*42140Ssklower * @(#)pk_usrreq.c 7.4 (Berkeley) 05/16/90 1341709Ssklower */ 1441595Ssklower 15*42140Ssklower #include "param.h" 16*42140Ssklower #include "systm.h" 17*42140Ssklower #include "mbuf.h" 18*42140Ssklower #include "socket.h" 19*42140Ssklower #include "protosw.h" 20*42140Ssklower #include "socketvar.h" 21*42140Ssklower #include "errno.h" 2241595Ssklower #include "ioctl.h" 2341595Ssklower #include "user.h" 2441595Ssklower #include "stat.h" 2541595Ssklower 26*42140Ssklower #include "../net/if.h" 2741595Ssklower 28*42140Ssklower #include "x25.h" 29*42140Ssklower #include "pk.h" 30*42140Ssklower #include "pk_var.h" 31*42140Ssklower 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 return (EINVAL); 7341595Ssklower 7441595Ssklower switch (req) { 7541595Ssklower /* 7641595Ssklower * X.25 attaches to socket via PRU_ATTACH and allocates a logical 7741595Ssklower * channel descriptor. If the socket is to receive connections, 7841595Ssklower * then the LISTEN state is entered. 7941595Ssklower */ 8041595Ssklower case PRU_ATTACH: 8141595Ssklower if (lcp) { 8241595Ssklower error = EISCONN; 8341595Ssklower /* Socket already connected. */ 8441595Ssklower break; 8541595Ssklower } 8641595Ssklower error = pk_attach (so); 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); 12841595Ssklower error = pk_connect (lcp, nam); 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 25541595Ssklower /*ARGSUSED*/ 25641595Ssklower pk_control (so, cmd, data, ifp) 25741595Ssklower struct socket *so; 25841595Ssklower int cmd; 25941595Ssklower caddr_t data; 26041595Ssklower register struct ifnet *ifp; 26141595Ssklower { 262*42140Ssklower register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; 26341595Ssklower register struct ifaddr *ifa = 0; 26441936Ssklower register struct x25_ifaddr *ia = 0; 26541936Ssklower int error, s; 26641936Ssklower unsigned n; 26741595Ssklower 26841595Ssklower /* 26941595Ssklower * Find address for this interface, if it exists. 27041595Ssklower */ 27141595Ssklower if (ifp) 27241595Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 273*42140Ssklower if (ifa->ifa_addr->sa_family == AF_CCITT) 27441595Ssklower break; 27541595Ssklower 27641936Ssklower ia = (struct x25_ifaddr *)ifa; 27741595Ssklower switch (cmd) { 278*42140Ssklower case SIOCGIFCONF_X25: 27941595Ssklower if (ifa == 0) 28041595Ssklower return (EADDRNOTAVAIL); 281*42140Ssklower ifr->ifr_xc = *(struct sockaddr *)ia->ia_xc; 28241595Ssklower return (0); 28341595Ssklower 284*42140Ssklower case SIOCSIFCONF_X25: 28541595Ssklower if (!suser()) 28641595Ssklower return (u.u_error); 28741595Ssklower 28841595Ssklower if (ifp == 0) 28941595Ssklower panic("pk_control"); 29041595Ssklower if (ifa == (struct ifaddr *)0) { 29141595Ssklower register struct mbuf *m; 29241595Ssklower 29341595Ssklower m = m_getclr(M_WAIT, MT_IFADDR); 29441595Ssklower if (m == (struct mbuf *)NULL) 29541595Ssklower return (ENOBUFS); 29641936Ssklower ia = mtod(m, struct x25_ifaddr *); 29741595Ssklower if (ifa = ifp->if_addrlist) { 29841595Ssklower for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 29941595Ssklower ; 30041936Ssklower ifa->ifa_next = &ia->ia_ifa; 30141595Ssklower } else 30241936Ssklower ifp->if_addrlist = &ia->ia_ifa; 30341936Ssklower ifa = &ia->ia_ifa; 304*42140Ssklower ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 30541936Ssklower ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 306*42140Ssklower ia->ia_ifp = ifp; 307*42140Ssklower ia->ia_pkcb.pk_ia = ia; 308*42140Ssklower ia->ia_pkcb.pk_next = pkcbhead; 309*42140Ssklower pkcbhead = &ia->ia_pkcb; 31041595Ssklower } 311*42140Ssklower ia->ia_xcp = &(ifr->ifr_xc); 31241936Ssklower if (ia->ia_chan && (ia->ia_maxlcn != ia->xcp->xc_maxlcn)) { 31341936Ssklower free((caddr_t)ia->ia_chan, M_IFADDR); 31441936Ssklower ia->ia_ia_chan = 0; 31541936Ssklower } 31641936Ssklower n = ia->ia_maxlcn * sizeof(struct pklcd *); 31741936Ssklower if (ia->ia_chan == 0) 318*42140Ssklower ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR); 31941936Ssklower if (ia->ia_chan) 32041936Ssklower bzero((caddr_t)ia->ia_chan, n); 321*42140Ssklower else { 322*42140Ssklower ia->ia_xcp = &ia->ia_xc; 32341936Ssklower return (ENOBUFS); 324*42140Ssklower } 32541595Ssklower /* 32641595Ssklower * Give the interface a chance to initialize if this 32741595Ssklower * is its first address, and to validate the address. 32841595Ssklower */ 32941936Ssklower s = splimp(); 33041936Ssklower if (ifp->if_ioctl) 331*42140Ssklower error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa))); 33241595Ssklower splx(s); 33341936Ssklower if (error == 0) { 33441936Ssklower ia->ia_xc = *ia->ia_xcp; 33541595Ssklower #ifndef WATERLOO 33641936Ssklower (void) pk_accton (); 33741595Ssklower #endif 33841936Ssklower } 33941936Ssklower ia->ia_xcp = &ia->ia_xc; 34041936Ssklower return (error); 34141595Ssklower 34241595Ssklower default: 34341595Ssklower if (ifp == 0 || ifp->if_ioctl == 0) 34441595Ssklower return (EOPNOTSUPP); 34541595Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 34641595Ssklower } 34741595Ssklower } 34841595Ssklower 34941595Ssklower /* 35041595Ssklower * Do an in-place conversion of an "old style" 35141595Ssklower * socket address to the new style 35241595Ssklower */ 35341595Ssklower 35441595Ssklower static 35541595Ssklower old_to_new (m) 35641595Ssklower register struct mbuf *m; 35741595Ssklower { 35841595Ssklower register struct x25_sockaddr *oldp; 35941595Ssklower register struct sockaddr_x25 *newp; 36041595Ssklower register char *ocp, *ncp; 36141595Ssklower struct sockaddr_x25 new; 36241595Ssklower 36341595Ssklower oldp = mtod (m, struct x25_sockaddr *); 36441595Ssklower newp = &new; 36541595Ssklower bzero ((caddr_t)newp, sizeof (*newp)); 36641595Ssklower 36741595Ssklower newp -> x25_family = AF_CCITT; 36841595Ssklower newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 36941595Ssklower | X25_MQBIT | X25_OLDSOCKADDR; 37041595Ssklower if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 37141595Ssklower newp -> x25_opts.op_psize = X25_PS128; 37241595Ssklower bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 37341595Ssklower (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 37441595Ssklower bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 37541595Ssklower newp -> x25_udlen = 4; 37641595Ssklower 37741595Ssklower ocp = (caddr_t)oldp -> xaddr_userdata; 37841595Ssklower ncp = newp -> x25_udata + 4; 37941595Ssklower while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 38041595Ssklower *ncp++ = *ocp++; 38141595Ssklower newp -> x25_udlen++; 38241595Ssklower } 38341595Ssklower 38441595Ssklower bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 38541595Ssklower m->m_len = sizeof (*newp); 38641595Ssklower } 38741595Ssklower 38841595Ssklower /* 38941595Ssklower * Do an in-place conversion of a new style 39041595Ssklower * socket address to the old style 39141595Ssklower */ 39241595Ssklower 39341595Ssklower static 39441595Ssklower new_to_old (m) 39541595Ssklower register struct mbuf *m; 39641595Ssklower { 39741595Ssklower register struct x25_sockaddr *oldp; 39841595Ssklower register struct sockaddr_x25 *newp; 39941595Ssklower register char *ocp, *ncp; 40041595Ssklower struct x25_sockaddr old; 40141595Ssklower 40241595Ssklower oldp = &old; 40341595Ssklower newp = mtod (m, struct sockaddr_x25 *); 40441595Ssklower bzero ((caddr_t)oldp, sizeof (*oldp)); 40541595Ssklower 40641595Ssklower oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 40741595Ssklower if (newp -> x25_opts.op_psize == X25_PS128) 40841595Ssklower oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 40941595Ssklower ocp = (char *)oldp -> xaddr_addr; 41041595Ssklower ncp = newp -> x25_addr; 41141595Ssklower while (*ncp) { 41241595Ssklower *ocp++ = *ncp++; 41341595Ssklower oldp -> xaddr_len++; 41441595Ssklower } 41541595Ssklower 41641595Ssklower bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 41741595Ssklower bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 41841595Ssklower (unsigned)(newp -> x25_udlen - 4)); 41941595Ssklower 42041595Ssklower bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 42141595Ssklower m -> m_len = sizeof (*oldp); 42241595Ssklower } 42341595Ssklower 42441595Ssklower pk_send (lcp, m) 42541595Ssklower register struct pklcd *lcp; 42641595Ssklower register struct mbuf *m; 42741595Ssklower { 42841595Ssklower register struct x25_packet *xp; 42941595Ssklower register struct mbuf *m0; 43041595Ssklower register int len; 43141595Ssklower 43241595Ssklower m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA))); 43341595Ssklower m0 -> m_next = m; 43441595Ssklower /* 43541595Ssklower * Application has elected (at call setup time) to prepend 43641595Ssklower * a control byte to each packet written indicating m-bit 43741595Ssklower * and q-bit status. Examine and then discard this byte. 43841595Ssklower */ 43941595Ssklower if (lcp -> lcd_flags & X25_MQBIT) { 44041595Ssklower register octet *cp; 44141595Ssklower 44241595Ssklower if (m -> m_len < 1) { 44341595Ssklower m_freem (m0); 44441595Ssklower return (EMSGSIZE); 44541595Ssklower } 44641595Ssklower cp = mtod (m, octet *); 44741595Ssklower if (*cp & 0x80) /* XXX */ 44841595Ssklower xp -> q_bit = 1; 44941595Ssklower xp -> packet_type |= (*cp & 0x40) >> 2; /* XXX */ 45041595Ssklower m -> m_len--; 45141936Ssklower m -> m_data++; 45241595Ssklower } 45341595Ssklower len = m -> m_len; 45441595Ssklower while (m -> m_next) { 45541595Ssklower m = m -> m_next; 45641595Ssklower len += m -> m_len; 45741595Ssklower } 45841595Ssklower if (len > (1 << lcp -> lcd_packetsize)) { 45941595Ssklower m_freem (m0); 46041595Ssklower return (EMSGSIZE); 46141595Ssklower } 46241595Ssklower 46341595Ssklower sbappendrecord (&lcp -> lcd_so -> so_snd, m0); 46441595Ssklower lcp -> lcd_template = 0; 46541595Ssklower lcp -> lcd_txcnt++; 46641595Ssklower pk_output (lcp); 46741595Ssklower return (0); 46841595Ssklower } 469