1*41709Ssklower /* 2*41709Ssklower * Copyright (c) University of British Columbia, 1984 3*41709Ssklower * Copyright (c) 1990 The Regents of the University of California. 4*41709Ssklower * All rights reserved. 5*41709Ssklower * 6*41709Ssklower * This code is derived from software contributed to Berkeley by 7*41709Ssklower * the Laboratory for Computation Vision and the Computer Science Department 8*41709Ssklower * of the University of British Columbia. 9*41709Ssklower * 10*41709Ssklower * %sccs.include.redist.c% 11*41709Ssklower * 12*41709Ssklower * @(#)pk_usrreq.c 7.2 (Berkeley) 05/11/90 13*41709Ssklower */ 1441595Ssklower 1541595Ssklower #include "../h/param.h" 1641595Ssklower #include "../h/systm.h" 1741595Ssklower #include "../h/mbuf.h" 1841595Ssklower #include "../h/socket.h" 1941595Ssklower #include "../h/protosw.h" 2041595Ssklower #include "../h/socketvar.h" 2141595Ssklower #include "../h/errno.h" 2241595Ssklower #ifdef BSD4_3 2341595Ssklower #include "../net/if.h" 2441595Ssklower #include "ioctl.h" 2541595Ssklower #include "dir.h" 2641595Ssklower #include "user.h" 2741595Ssklower #include "stat.h" 2841595Ssklower #endif 2941595Ssklower 3041595Ssklower #include "../netccitt/x25.h" 3141595Ssklower #include "../netccitt/pk.h" 3241595Ssklower #include "../netccitt/pk_var.h" 3341595Ssklower 3441595Ssklower struct x25_packet *pk_template (); 3541595Ssklower 3641595Ssklower /* 3741595Ssklower * 3841595Ssklower * X.25 Packet level protocol interface to socket abstraction. 3941595Ssklower * 4041595Ssklower * Process an X.25 user request on a logical channel. If this is a send 4141595Ssklower * request then m is the mbuf chain of the send data. If this is a timer 4241595Ssklower * expiration (called from the software clock routine) them timertype is 4341595Ssklower * the particular timer. 4441595Ssklower * 4541595Ssklower */ 4641595Ssklower 4741595Ssklower pk_usrreq (so, req, m, nam, rights) 4841595Ssklower struct socket *so; 4941595Ssklower int req; 5041595Ssklower register struct mbuf *m, *nam; 5141595Ssklower struct mbuf *rights; 5241595Ssklower { 5341595Ssklower register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 5441595Ssklower register struct x25_packet *xp; 5541595Ssklower register int s = splnet (), error = 0; 5641595Ssklower 5741595Ssklower #ifdef BSD4_3 5841595Ssklower if (req == PRU_CONTROL) { 5941595Ssklower error = pk_control(so, (int)m, (caddr_t)nam, 6041595Ssklower (struct ifnet *)rights); 6141595Ssklower splx (s); 6241595Ssklower return (error); 6341595Ssklower } 6441595Ssklower #endif 6541595Ssklower if (rights && rights -> m_len) { 6641595Ssklower splx (s); 6741595Ssklower return (EINVAL); 6841595Ssklower } 6941595Ssklower 7041595Ssklower /* 7141595Ssklower pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, 7241595Ssklower req, (struct x25_packet *)0); 7341595Ssklower */ 7441595Ssklower 7541595Ssklower if (lcp == NULL && req != PRU_ATTACH) { 7641595Ssklower splx (s); 7741595Ssklower return (EINVAL); 7841595Ssklower } 7941595Ssklower 8041595Ssklower switch (req) { 8141595Ssklower /* 8241595Ssklower * X.25 attaches to socket via PRU_ATTACH and allocates a logical 8341595Ssklower * channel descriptor. If the socket is to receive connections, 8441595Ssklower * then the LISTEN state is entered. 8541595Ssklower */ 8641595Ssklower case PRU_ATTACH: 8741595Ssklower if (lcp) { 8841595Ssklower error = EISCONN; 8941595Ssklower /* Socket already connected. */ 9041595Ssklower break; 9141595Ssklower } 9241595Ssklower error = pk_attach (so); 9341595Ssklower break; 9441595Ssklower 9541595Ssklower /* 9641595Ssklower * Detach a logical channel from the socket. If the state of the 9741595Ssklower * channel is embryonic, simply discard it. Otherwise we have to 9841595Ssklower * initiate a PRU_DISCONNECT which will finish later. 9941595Ssklower */ 10041595Ssklower case PRU_DETACH: 10141595Ssklower pk_disconnect (lcp); 10241595Ssklower break; 10341595Ssklower 10441595Ssklower /* 10541595Ssklower * Give the socket an address. 10641595Ssklower */ 10741595Ssklower case PRU_BIND: 10841595Ssklower if (nam -> m_len == sizeof (struct x25_sockaddr)) 10941595Ssklower old_to_new (nam); 11041595Ssklower error = pk_bind (lcp, nam); 11141595Ssklower break; 11241595Ssklower 11341595Ssklower /* 11441595Ssklower * Prepare to accept connections. 11541595Ssklower */ 11641595Ssklower case PRU_LISTEN: 11741595Ssklower if (lcp -> lcd_ceaddr == 0) { 11841595Ssklower error = EDESTADDRREQ; 11941595Ssklower break; 12041595Ssklower } 12141595Ssklower lcp -> lcd_state = LISTEN; 12241595Ssklower lcp -> lcd_listen = pk_listenhead; 12341595Ssklower pk_listenhead = lcp; 12441595Ssklower break; 12541595Ssklower 12641595Ssklower /* 12741595Ssklower * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL 12841595Ssklower * and mark the socket as connecting. Set timer waiting for 12941595Ssklower * CALL ACCEPT or CLEAR. 13041595Ssklower */ 13141595Ssklower case PRU_CONNECT: 13241595Ssklower if (nam -> m_len == sizeof (struct x25_sockaddr)) 13341595Ssklower old_to_new (nam); 13441595Ssklower error = pk_connect (lcp, nam); 13541595Ssklower break; 13641595Ssklower 13741595Ssklower /* 13841595Ssklower * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. 13941595Ssklower * The socket will be disconnected when we receive a confirmation 14041595Ssklower * or a clear collision. 14141595Ssklower */ 14241595Ssklower case PRU_DISCONNECT: 14341595Ssklower pk_disconnect (lcp); 14441595Ssklower break; 14541595Ssklower 14641595Ssklower /* 14741595Ssklower * Accept an INCOMING CALL. Most of the work has already been done 14841595Ssklower * by pk_input. Just return the callers address to the user. 14941595Ssklower */ 15041595Ssklower case PRU_ACCEPT: 15141595Ssklower if (lcp -> lcd_craddr == NULL) 15241595Ssklower break; 15341595Ssklower bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), 15441595Ssklower sizeof (struct sockaddr_x25)); 15541595Ssklower nam -> m_len = sizeof (struct sockaddr_x25); 15641595Ssklower if (lcp -> lcd_flags & X25_OLDSOCKADDR) 15741595Ssklower new_to_old (nam); 15841595Ssklower break; 15941595Ssklower 16041595Ssklower /* 16141595Ssklower * After a receive, we should send a RR. 16241595Ssklower */ 16341595Ssklower case PRU_RCVD: 16441595Ssklower lcp -> lcd_rxcnt++; 16541595Ssklower lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR); 16641595Ssklower pk_output (lcp); 16741595Ssklower break; 16841595Ssklower 16941595Ssklower /* 17041595Ssklower * Do send by placing data on the socket output queue. 17141595Ssklower * SHOULD WE USE m_cat HERE. 17241595Ssklower */ 17341595Ssklower case PRU_SEND: 17441595Ssklower error = pk_send (lcp, m); 17541595Ssklower break; 17641595Ssklower 17741595Ssklower /* 17841595Ssklower * Abort a virtual circuit. For example all completed calls 17941595Ssklower * waiting acceptance. 18041595Ssklower */ 18141595Ssklower case PRU_ABORT: 18241595Ssklower pk_disconnect (lcp); 18341595Ssklower break; 18441595Ssklower 18541595Ssklower /* Begin unimplemented hooks. */ 18641595Ssklower 18741595Ssklower case PRU_SHUTDOWN: 18841595Ssklower error = EOPNOTSUPP; 18941595Ssklower break; 19041595Ssklower 19141595Ssklower case PRU_CONTROL: 19241595Ssklower error = EOPNOTSUPP; 19341595Ssklower break; 19441595Ssklower 19541595Ssklower case PRU_SENSE: 19641595Ssklower #ifdef BSD4_3 19741595Ssklower ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; 19841595Ssklower #else 19941595Ssklower error = EOPNOTSUPP; 20041595Ssklower #endif 20141595Ssklower break; 20241595Ssklower 20341595Ssklower /* End unimplemented hooks. */ 20441595Ssklower 20541595Ssklower case PRU_SOCKADDR: 20641595Ssklower if (lcp -> lcd_ceaddr == 0) 20741595Ssklower return (EADDRNOTAVAIL); 20841595Ssklower nam -> m_len = sizeof (struct sockaddr_x25); 20941595Ssklower bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), 21041595Ssklower sizeof (struct sockaddr_x25)); 21141595Ssklower if (lcp -> lcd_flags & X25_OLDSOCKADDR) 21241595Ssklower new_to_old (nam); 21341595Ssklower break; 21441595Ssklower 21541595Ssklower case PRU_PEERADDR: 21641595Ssklower if (lcp -> lcd_state != DATA_TRANSFER) 21741595Ssklower return (ENOTCONN); 21841595Ssklower nam -> m_len = sizeof (struct sockaddr_x25); 21941595Ssklower bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : 22041595Ssklower (caddr_t)lcp -> lcd_ceaddr, 22141595Ssklower mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); 22241595Ssklower if (lcp -> lcd_flags & X25_OLDSOCKADDR) 22341595Ssklower new_to_old (nam); 22441595Ssklower break; 22541595Ssklower 22641595Ssklower /* 22741595Ssklower * Receive INTERRUPT packet. 22841595Ssklower */ 22941595Ssklower case PRU_RCVOOB: 23041595Ssklower m -> m_len = 1; 23141595Ssklower *mtod (m, char *) = lcp -> lcd_intrdata; 23241595Ssklower break; 23341595Ssklower 23441595Ssklower /* 23541595Ssklower * Send INTERRUPT packet. 23641595Ssklower */ 23741595Ssklower case PRU_SENDOOB: 23841595Ssklower m_freem (m); 23941595Ssklower if (lcp -> lcd_intrconf_pending) { 24041595Ssklower error = ETOOMANYREFS; 24141595Ssklower break; 24241595Ssklower } 24341595Ssklower lcp -> lcd_intrcnt++; 24441595Ssklower xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT); 24541595Ssklower xp -> packet_data = 0; 24641595Ssklower (dtom (xp)) -> m_len++; 24741595Ssklower pk_output (lcp); 24841595Ssklower break; 24941595Ssklower 25041595Ssklower default: 25141595Ssklower panic ("pk_usrreq"); 25241595Ssklower } 25341595Ssklower 25441595Ssklower splx (s); 25541595Ssklower return (error); 25641595Ssklower } 25741595Ssklower 25841595Ssklower #ifdef BSD4_3 25941595Ssklower /*ARGSUSED*/ 26041595Ssklower pk_control (so, cmd, data, ifp) 26141595Ssklower struct socket *so; 26241595Ssklower int cmd; 26341595Ssklower caddr_t data; 26441595Ssklower register struct ifnet *ifp; 26541595Ssklower { 26641595Ssklower register struct ifreq *ifr = (struct ifreq *)data; 26741595Ssklower register struct ifaddr *ifa = 0; 26841595Ssklower register int error, s; 26941595Ssklower struct sockaddr oldaddr; 27041595Ssklower 27141595Ssklower /* 27241595Ssklower * Find address for this interface, if it exists. 27341595Ssklower */ 27441595Ssklower if (ifp) 27541595Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 27641595Ssklower if (ifa->ifa_addr.sa_family == AF_CCITT) 27741595Ssklower break; 27841595Ssklower 27941595Ssklower switch (cmd) { 28041595Ssklower case SIOCGIFADDR: 28141595Ssklower if (ifa == 0) 28241595Ssklower return (EADDRNOTAVAIL); 28341595Ssklower ifr -> ifr_addr = ifa->ifa_addr; 28441595Ssklower return (0); 28541595Ssklower 28641595Ssklower case SIOCSIFADDR: 28741595Ssklower if (!suser()) 28841595Ssklower return (u.u_error); 28941595Ssklower 29041595Ssklower if (ifp == 0) 29141595Ssklower panic("pk_control"); 29241595Ssklower if (ifa == (struct ifaddr *)0) { 29341595Ssklower register struct ifaddr *ia; 29441595Ssklower register struct mbuf *m; 29541595Ssklower 29641595Ssklower m = m_getclr(M_WAIT, MT_IFADDR); 29741595Ssklower if (m == (struct mbuf *)NULL) 29841595Ssklower return (ENOBUFS); 29941595Ssklower ia = mtod(m, struct ifaddr *); 30041595Ssklower if (ifa = ifp->if_addrlist) { 30141595Ssklower for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 30241595Ssklower ; 30341595Ssklower ifa->ifa_next = ia; 30441595Ssklower } else 30541595Ssklower ifp->if_addrlist = ia; 30641595Ssklower ifa = ia; 30741595Ssklower ifa->ifa_ifp = ifp; 30841595Ssklower } 30941595Ssklower oldaddr = ifa->ifa_addr; 31041595Ssklower s = splimp(); 31141595Ssklower ifa->ifa_addr = ifr->ifr_addr; 31241595Ssklower /* 31341595Ssklower * Give the interface a chance to initialize if this 31441595Ssklower * is its first address, and to validate the address. 31541595Ssklower */ 31641595Ssklower if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ifa))) { 31741595Ssklower splx(s); 31841595Ssklower ifa->ifa_addr = oldaddr; 31941595Ssklower return (error); 32041595Ssklower } 32141595Ssklower splx(s); 32241595Ssklower #ifndef WATERLOO 32341595Ssklower (void) pk_accton (); 32441595Ssklower #endif 32541595Ssklower return (0); 32641595Ssklower 32741595Ssklower default: 32841595Ssklower if (ifp == 0 || ifp->if_ioctl == 0) 32941595Ssklower return (EOPNOTSUPP); 33041595Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 33141595Ssklower } 33241595Ssklower } 33341595Ssklower #endif 33441595Ssklower 33541595Ssklower /* 33641595Ssklower * Do an in-place conversion of an "old style" 33741595Ssklower * socket address to the new style 33841595Ssklower */ 33941595Ssklower 34041595Ssklower static 34141595Ssklower old_to_new (m) 34241595Ssklower register struct mbuf *m; 34341595Ssklower { 34441595Ssklower register struct x25_sockaddr *oldp; 34541595Ssklower register struct sockaddr_x25 *newp; 34641595Ssklower register char *ocp, *ncp; 34741595Ssklower struct sockaddr_x25 new; 34841595Ssklower 34941595Ssklower oldp = mtod (m, struct x25_sockaddr *); 35041595Ssklower newp = &new; 35141595Ssklower bzero ((caddr_t)newp, sizeof (*newp)); 35241595Ssklower 35341595Ssklower newp -> x25_family = AF_CCITT; 35441595Ssklower newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 35541595Ssklower | X25_MQBIT | X25_OLDSOCKADDR; 35641595Ssklower if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 35741595Ssklower newp -> x25_opts.op_psize = X25_PS128; 35841595Ssklower bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 35941595Ssklower (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 36041595Ssklower bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 36141595Ssklower newp -> x25_udlen = 4; 36241595Ssklower 36341595Ssklower ocp = (caddr_t)oldp -> xaddr_userdata; 36441595Ssklower ncp = newp -> x25_udata + 4; 36541595Ssklower while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 36641595Ssklower *ncp++ = *ocp++; 36741595Ssklower newp -> x25_udlen++; 36841595Ssklower } 36941595Ssklower 37041595Ssklower bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 37141595Ssklower m->m_len = sizeof (*newp); 37241595Ssklower } 37341595Ssklower 37441595Ssklower /* 37541595Ssklower * Do an in-place conversion of a new style 37641595Ssklower * socket address to the old style 37741595Ssklower */ 37841595Ssklower 37941595Ssklower static 38041595Ssklower new_to_old (m) 38141595Ssklower register struct mbuf *m; 38241595Ssklower { 38341595Ssklower register struct x25_sockaddr *oldp; 38441595Ssklower register struct sockaddr_x25 *newp; 38541595Ssklower register char *ocp, *ncp; 38641595Ssklower struct x25_sockaddr old; 38741595Ssklower 38841595Ssklower oldp = &old; 38941595Ssklower newp = mtod (m, struct sockaddr_x25 *); 39041595Ssklower bzero ((caddr_t)oldp, sizeof (*oldp)); 39141595Ssklower 39241595Ssklower oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 39341595Ssklower if (newp -> x25_opts.op_psize == X25_PS128) 39441595Ssklower oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 39541595Ssklower ocp = (char *)oldp -> xaddr_addr; 39641595Ssklower ncp = newp -> x25_addr; 39741595Ssklower while (*ncp) { 39841595Ssklower *ocp++ = *ncp++; 39941595Ssklower oldp -> xaddr_len++; 40041595Ssklower } 40141595Ssklower 40241595Ssklower bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 40341595Ssklower bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 40441595Ssklower (unsigned)(newp -> x25_udlen - 4)); 40541595Ssklower 40641595Ssklower bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 40741595Ssklower m -> m_len = sizeof (*oldp); 40841595Ssklower } 40941595Ssklower 41041595Ssklower pk_send (lcp, m) 41141595Ssklower register struct pklcd *lcp; 41241595Ssklower register struct mbuf *m; 41341595Ssklower { 41441595Ssklower register struct x25_packet *xp; 41541595Ssklower register struct mbuf *m0; 41641595Ssklower register int len; 41741595Ssklower 41841595Ssklower m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA))); 41941595Ssklower m0 -> m_next = m; 42041595Ssklower /* 42141595Ssklower * Application has elected (at call setup time) to prepend 42241595Ssklower * a control byte to each packet written indicating m-bit 42341595Ssklower * and q-bit status. Examine and then discard this byte. 42441595Ssklower */ 42541595Ssklower if (lcp -> lcd_flags & X25_MQBIT) { 42641595Ssklower register octet *cp; 42741595Ssklower 42841595Ssklower if (m -> m_len < 1) { 42941595Ssklower m_freem (m0); 43041595Ssklower return (EMSGSIZE); 43141595Ssklower } 43241595Ssklower cp = mtod (m, octet *); 43341595Ssklower if (*cp & 0x80) /* XXX */ 43441595Ssklower xp -> q_bit = 1; 43541595Ssklower xp -> packet_type |= (*cp & 0x40) >> 2; /* XXX */ 43641595Ssklower m -> m_len--; 43741595Ssklower m -> m_off++; 43841595Ssklower } 43941595Ssklower len = m -> m_len; 44041595Ssklower while (m -> m_next) { 44141595Ssklower m = m -> m_next; 44241595Ssklower len += m -> m_len; 44341595Ssklower } 44441595Ssklower if (len > (1 << lcp -> lcd_packetsize)) { 44541595Ssklower m_freem (m0); 44641595Ssklower return (EMSGSIZE); 44741595Ssklower } 44841595Ssklower 44941595Ssklower #ifdef BSD4_3 45041595Ssklower sbappendrecord (&lcp -> lcd_so -> so_snd, m0); 45141595Ssklower #else 45241595Ssklower m -> m_act = (struct mbuf *) 1; 45341595Ssklower sbappend (&lcp -> lcd_so -> so_snd, m0); 45441595Ssklower #endif 45541595Ssklower lcp -> lcd_template = 0; 45641595Ssklower lcp -> lcd_txcnt++; 45741595Ssklower pk_output (lcp); 45841595Ssklower return (0); 45941595Ssklower } 460