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*45297Ssklower * @(#)pk_usrreq.c 7.8 (Berkeley) 10/04/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 } 8445165Ssklower lcp = pk_attach (so); 8545165Ssklower if (lcp == 0) 8645165Ssklower 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 26645165Ssklower 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; 281*45297Ssklower int error, s, old_maxlcn; 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); 29745165Ssklower ifr->ifr_xc = ia->ia_xc; 29841595Ssklower return (0); 29941595Ssklower 30042140Ssklower case SIOCSIFCONF_X25: 30145165Ssklower if (error = suser(u.u_cred, &u.u_acflag)) 30245165Ssklower 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); 312*45297Ssklower bzero((caddr_t)ia, sizeof (*ia)); 31341595Ssklower if (ifa = ifp->if_addrlist) { 31441595Ssklower for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 31541595Ssklower ; 31641936Ssklower ifa->ifa_next = &ia->ia_ifa; 31741595Ssklower } else 31841936Ssklower ifp->if_addrlist = &ia->ia_ifa; 31941936Ssklower ifa = &ia->ia_ifa; 32042140Ssklower ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 32145165Ssklower ifa->ifa_addr = (struct sockaddr *)&ia->ia_xc.xc_addr; 322*45297Ssklower ia->ia_xcp = &ia->ia_xc; 32342140Ssklower ia->ia_ifp = ifp; 32442140Ssklower ia->ia_pkcb.pk_ia = ia; 32542140Ssklower ia->ia_pkcb.pk_next = pkcbhead; 326*45297Ssklower ia->ia_pkcb.pk_state = DTE_WAITING; 32742140Ssklower pkcbhead = &ia->ia_pkcb; 32841595Ssklower } 329*45297Ssklower old_maxlcn = ia->ia_maxlcn; 330*45297Ssklower ia->ia_xc = ifr->ifr_xc; 331*45297Ssklower if (ia->ia_chan && (ia->ia_maxlcn != old_maxlcn)) { 33245165Ssklower pk_restart(&ia->ia_pkcb, X25_RESTART_NETWORK_CONGESTION); 33342277Ssklower dev_lcp = ia->ia_chan[0]; 33441936Ssklower free((caddr_t)ia->ia_chan, M_IFADDR); 33542277Ssklower ia->ia_chan = 0; 33641936Ssklower } 33742277Ssklower if (ia->ia_chan == 0) { 338*45297Ssklower n = (ia->ia_maxlcn + 1) * sizeof(struct pklcd *); 339*45297Ssklower ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR, M_WAITOK); 34042277Ssklower if (ia->ia_chan) { 34142277Ssklower bzero((caddr_t)ia->ia_chan, n); 34242277Ssklower if (dev_lcp == 0) 34342277Ssklower dev_lcp = pk_attach((struct socket *)0); 34445165Ssklower ia->ia_chan[0] = dev_lcp; 345*45297Ssklower dev_lcp->lcd_state = READY; 346*45297Ssklower dev_lcp->lcd_pkp = &ia->ia_pkcb; 34742277Ssklower } else { 34842277Ssklower if (dev_lcp) 34942277Ssklower pk_close(dev_lcp); 35042277Ssklower return (ENOBUFS); 35142277Ssklower } 35242140Ssklower } 35341595Ssklower /* 35441595Ssklower * Give the interface a chance to initialize if this 35541595Ssklower * is its first address, and to validate the address. 35641595Ssklower */ 35741936Ssklower s = splimp(); 35841936Ssklower if (ifp->if_ioctl) 35945165Ssklower error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa); 360*45297Ssklower if (error) 361*45297Ssklower ifp->if_flags &= ~IFF_UP; 36241595Ssklower splx(s); 36341936Ssklower return (error); 36441595Ssklower 36541595Ssklower default: 36641595Ssklower if (ifp == 0 || ifp->if_ioctl == 0) 36741595Ssklower return (EOPNOTSUPP); 36841595Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 36941595Ssklower } 37041595Ssklower } 37141595Ssklower 37245165Ssklower pk_ctloutput(cmd, so, level, optname, mp) 37345165Ssklower struct socket *so; 37445165Ssklower struct mbuf **mp; 37545165Ssklower int cmd, level, optname; 37645165Ssklower { 37745165Ssklower register struct mbuf *m = *mp; 37845165Ssklower int error; 37945165Ssklower 38045165Ssklower if (cmd == PRCO_SETOPT) switch (optname) { 38145165Ssklower case PK_ACCTFILE: 38245165Ssklower if (m == 0) 38345165Ssklower return (EINVAL); 38445165Ssklower if (m->m_len) 38545165Ssklower error = pk_accton(mtod(m, char *)); 38645165Ssklower else 38745165Ssklower error = pk_accton((char *)0); 38845165Ssklower (void) m_freem(m); 38945165Ssklower *mp = 0; 39045165Ssklower return (error); 39145165Ssklower } 39245165Ssklower if (*mp) { 39345165Ssklower (void) m_freem(*mp); 39445165Ssklower *mp = 0; 39545165Ssklower } 39645165Ssklower return (EOPNOTSUPP); 39745165Ssklower 39845165Ssklower } 39945165Ssklower 40041595Ssklower /* 40141595Ssklower * Do an in-place conversion of an "old style" 40241595Ssklower * socket address to the new style 40341595Ssklower */ 40441595Ssklower 40541595Ssklower static 40641595Ssklower old_to_new (m) 40741595Ssklower register struct mbuf *m; 40841595Ssklower { 40941595Ssklower register struct x25_sockaddr *oldp; 41041595Ssklower register struct sockaddr_x25 *newp; 41141595Ssklower register char *ocp, *ncp; 41241595Ssklower struct sockaddr_x25 new; 41341595Ssklower 41441595Ssklower oldp = mtod (m, struct x25_sockaddr *); 41541595Ssklower newp = &new; 41641595Ssklower bzero ((caddr_t)newp, sizeof (*newp)); 41741595Ssklower 41841595Ssklower newp -> x25_family = AF_CCITT; 41941595Ssklower newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 42041595Ssklower | X25_MQBIT | X25_OLDSOCKADDR; 42141595Ssklower if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 42241595Ssklower newp -> x25_opts.op_psize = X25_PS128; 42341595Ssklower bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 42441595Ssklower (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 42541595Ssklower bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 42641595Ssklower newp -> x25_udlen = 4; 42741595Ssklower 42841595Ssklower ocp = (caddr_t)oldp -> xaddr_userdata; 42941595Ssklower ncp = newp -> x25_udata + 4; 43041595Ssklower while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 43141595Ssklower *ncp++ = *ocp++; 43241595Ssklower newp -> x25_udlen++; 43341595Ssklower } 43441595Ssklower 43541595Ssklower bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 43641595Ssklower m->m_len = sizeof (*newp); 43741595Ssklower } 43841595Ssklower 43941595Ssklower /* 44041595Ssklower * Do an in-place conversion of a new style 44141595Ssklower * socket address to the old style 44241595Ssklower */ 44341595Ssklower 44441595Ssklower static 44541595Ssklower new_to_old (m) 44641595Ssklower register struct mbuf *m; 44741595Ssklower { 44841595Ssklower register struct x25_sockaddr *oldp; 44941595Ssklower register struct sockaddr_x25 *newp; 45041595Ssklower register char *ocp, *ncp; 45141595Ssklower struct x25_sockaddr old; 45241595Ssklower 45341595Ssklower oldp = &old; 45441595Ssklower newp = mtod (m, struct sockaddr_x25 *); 45541595Ssklower bzero ((caddr_t)oldp, sizeof (*oldp)); 45641595Ssklower 45741595Ssklower oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 45841595Ssklower if (newp -> x25_opts.op_psize == X25_PS128) 45941595Ssklower oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 46041595Ssklower ocp = (char *)oldp -> xaddr_addr; 46141595Ssklower ncp = newp -> x25_addr; 46241595Ssklower while (*ncp) { 46341595Ssklower *ocp++ = *ncp++; 46441595Ssklower oldp -> xaddr_len++; 46541595Ssklower } 46641595Ssklower 46741595Ssklower bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 46841595Ssklower bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 46941595Ssklower (unsigned)(newp -> x25_udlen - 4)); 47041595Ssklower 47141595Ssklower bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 47241595Ssklower m -> m_len = sizeof (*oldp); 47341595Ssklower } 47441595Ssklower 47541595Ssklower pk_send (lcp, m) 476*45297Ssklower struct pklcd *lcp; 47741595Ssklower register struct mbuf *m; 47841595Ssklower { 479*45297Ssklower int mqbit = 0, error; 48041595Ssklower 48141595Ssklower /* 48241595Ssklower * Application has elected (at call setup time) to prepend 48341595Ssklower * a control byte to each packet written indicating m-bit 48441595Ssklower * and q-bit status. Examine and then discard this byte. 48541595Ssklower */ 48641595Ssklower if (lcp -> lcd_flags & X25_MQBIT) { 48741595Ssklower if (m -> m_len < 1) { 488*45297Ssklower m_freem (m); 48941595Ssklower return (EMSGSIZE); 49041595Ssklower } 491*45297Ssklower mqbit = *(mtod(m, u_char *)); 49241595Ssklower m -> m_len--; 49341936Ssklower m -> m_data++; 494*45297Ssklower m -> m_pkthdr.len--; 49541595Ssklower } 496*45297Ssklower if ((error = pk_fragment(lcp, m, mqbit & 0x80, mqbit &0x40, 1)) == 0) 497*45297Ssklower error = pk_output (lcp); 498*45297Ssklower return (error); 49941595Ssklower } 500