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*42277Ssklower * @(#)pk_usrreq.c 7.5 (Berkeley) 05/22/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 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); 128*42277Ssklower 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 255*42277Ssklower /* 256*42277Ssklower * If you want to use UBC X.25 level 3 in conjunction with some 257*42277Ssklower * other X.25 level 2 driver, have the ifp->if_ioctl routine 258*42277Ssklower * assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25. 259*42277Ssklower */ 260*42277Ssklower /* ARGSUSED */ 261*42277Ssklower pk_start (lcp) 262*42277Ssklower register struct pklcd *lcp; 263*42277Ssklower { 264*42277Ssklower extern int pk_send(); 265*42277Ssklower 266*42277Ssklower lcp -> lcp_downq.pq_put = pk_send; 267*42277Ssklower return (pk_output(lcp)); 268*42277Ssklower } 269*42277Ssklower 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; 280*42277Ssklower 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); 29742140Ssklower ifr->ifr_xc = *(struct sockaddr *)ia->ia_xc; 29841595Ssklower return (0); 29941595Ssklower 30042140Ssklower case SIOCSIFCONF_X25: 30141595Ssklower if (!suser()) 30241595Ssklower return (u.u_error); 30341595Ssklower 30441595Ssklower if (ifp == 0) 30541595Ssklower panic("pk_control"); 30641595Ssklower if (ifa == (struct ifaddr *)0) { 30741595Ssklower register struct mbuf *m; 30841595Ssklower 309*42277Ssklower MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), 310*42277Ssklower M_IFADDR, M_WAITOK); 311*42277Ssklower if (ia == 0) 31241595Ssklower return (ENOBUFS); 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; 32141936Ssklower ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 32242140Ssklower ia->ia_ifp = ifp; 32342140Ssklower ia->ia_pkcb.pk_ia = ia; 32442140Ssklower ia->ia_pkcb.pk_next = pkcbhead; 32542140Ssklower pkcbhead = &ia->ia_pkcb; 32641595Ssklower } 32742140Ssklower ia->ia_xcp = &(ifr->ifr_xc); 32841936Ssklower if (ia->ia_chan && (ia->ia_maxlcn != ia->xcp->xc_maxlcn)) { 329*42277Ssklower pk_restart(&ia->ia_pkp, X25_RESTART_NETWORK_CONGESTION); 330*42277Ssklower dev_lcp = ia->ia_chan[0]; 33141936Ssklower free((caddr_t)ia->ia_chan, M_IFADDR); 332*42277Ssklower ia->ia_chan = 0; 33341936Ssklower } 334*42277Ssklower if (ia->ia_chan == 0) { 335*42277Ssklower n = ia->ia_maxlcn * sizeof(struct pklcd *); 33642140Ssklower ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR); 337*42277Ssklower if (ia->ia_chan) { 338*42277Ssklower bzero((caddr_t)ia->ia_chan, n); 339*42277Ssklower if (dev_lcp == 0) 340*42277Ssklower dev_lcp = pk_attach((struct socket *)0); 341*42277Ssklower ia->ia_chan = dev_lcp; 342*42277Ssklower } else { 343*42277Ssklower if (dev_lcp) 344*42277Ssklower pk_close(dev_lcp); 345*42277Ssklower ia->ia_xcp = &ia->ia_xc; 346*42277Ssklower return (ENOBUFS); 347*42277Ssklower } 34842140Ssklower } 34941595Ssklower /* 35041595Ssklower * Give the interface a chance to initialize if this 35141595Ssklower * is its first address, and to validate the address. 35241595Ssklower */ 35341936Ssklower s = splimp(); 35441936Ssklower if (ifp->if_ioctl) 35542140Ssklower error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa))); 35641595Ssklower splx(s); 35741936Ssklower if (error == 0) { 35841936Ssklower ia->ia_xc = *ia->ia_xcp; 35941595Ssklower #ifndef WATERLOO 36041936Ssklower (void) pk_accton (); 36141595Ssklower #endif 36241936Ssklower } 36341936Ssklower ia->ia_xcp = &ia->ia_xc; 36441936Ssklower return (error); 36541595Ssklower 36641595Ssklower default: 36741595Ssklower if (ifp == 0 || ifp->if_ioctl == 0) 36841595Ssklower return (EOPNOTSUPP); 36941595Ssklower return ((*ifp->if_ioctl)(ifp, cmd, data)); 37041595Ssklower } 37141595Ssklower } 37241595Ssklower 37341595Ssklower /* 37441595Ssklower * Do an in-place conversion of an "old style" 37541595Ssklower * socket address to the new style 37641595Ssklower */ 37741595Ssklower 37841595Ssklower static 37941595Ssklower old_to_new (m) 38041595Ssklower register struct mbuf *m; 38141595Ssklower { 38241595Ssklower register struct x25_sockaddr *oldp; 38341595Ssklower register struct sockaddr_x25 *newp; 38441595Ssklower register char *ocp, *ncp; 38541595Ssklower struct sockaddr_x25 new; 38641595Ssklower 38741595Ssklower oldp = mtod (m, struct x25_sockaddr *); 38841595Ssklower newp = &new; 38941595Ssklower bzero ((caddr_t)newp, sizeof (*newp)); 39041595Ssklower 39141595Ssklower newp -> x25_family = AF_CCITT; 39241595Ssklower newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 39341595Ssklower | X25_MQBIT | X25_OLDSOCKADDR; 39441595Ssklower if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 39541595Ssklower newp -> x25_opts.op_psize = X25_PS128; 39641595Ssklower bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 39741595Ssklower (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 39841595Ssklower bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 39941595Ssklower newp -> x25_udlen = 4; 40041595Ssklower 40141595Ssklower ocp = (caddr_t)oldp -> xaddr_userdata; 40241595Ssklower ncp = newp -> x25_udata + 4; 40341595Ssklower while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 40441595Ssklower *ncp++ = *ocp++; 40541595Ssklower newp -> x25_udlen++; 40641595Ssklower } 40741595Ssklower 40841595Ssklower bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 40941595Ssklower m->m_len = sizeof (*newp); 41041595Ssklower } 41141595Ssklower 41241595Ssklower /* 41341595Ssklower * Do an in-place conversion of a new style 41441595Ssklower * socket address to the old style 41541595Ssklower */ 41641595Ssklower 41741595Ssklower static 41841595Ssklower new_to_old (m) 41941595Ssklower register struct mbuf *m; 42041595Ssklower { 42141595Ssklower register struct x25_sockaddr *oldp; 42241595Ssklower register struct sockaddr_x25 *newp; 42341595Ssklower register char *ocp, *ncp; 42441595Ssklower struct x25_sockaddr old; 42541595Ssklower 42641595Ssklower oldp = &old; 42741595Ssklower newp = mtod (m, struct sockaddr_x25 *); 42841595Ssklower bzero ((caddr_t)oldp, sizeof (*oldp)); 42941595Ssklower 43041595Ssklower oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 43141595Ssklower if (newp -> x25_opts.op_psize == X25_PS128) 43241595Ssklower oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 43341595Ssklower ocp = (char *)oldp -> xaddr_addr; 43441595Ssklower ncp = newp -> x25_addr; 43541595Ssklower while (*ncp) { 43641595Ssklower *ocp++ = *ncp++; 43741595Ssklower oldp -> xaddr_len++; 43841595Ssklower } 43941595Ssklower 44041595Ssklower bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 44141595Ssklower bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 44241595Ssklower (unsigned)(newp -> x25_udlen - 4)); 44341595Ssklower 44441595Ssklower bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 44541595Ssklower m -> m_len = sizeof (*oldp); 44641595Ssklower } 44741595Ssklower 44841595Ssklower pk_send (lcp, m) 44941595Ssklower register struct pklcd *lcp; 45041595Ssklower register struct mbuf *m; 45141595Ssklower { 45241595Ssklower register struct x25_packet *xp; 45341595Ssklower register struct mbuf *m0; 45441595Ssklower register int len; 45541595Ssklower 45641595Ssklower m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA))); 45741595Ssklower m0 -> m_next = m; 45841595Ssklower /* 45941595Ssklower * Application has elected (at call setup time) to prepend 46041595Ssklower * a control byte to each packet written indicating m-bit 46141595Ssklower * and q-bit status. Examine and then discard this byte. 46241595Ssklower */ 46341595Ssklower if (lcp -> lcd_flags & X25_MQBIT) { 46441595Ssklower register octet *cp; 46541595Ssklower 46641595Ssklower if (m -> m_len < 1) { 46741595Ssklower m_freem (m0); 46841595Ssklower return (EMSGSIZE); 46941595Ssklower } 47041595Ssklower cp = mtod (m, octet *); 47141595Ssklower if (*cp & 0x80) /* XXX */ 47241595Ssklower xp -> q_bit = 1; 47341595Ssklower xp -> packet_type |= (*cp & 0x40) >> 2; /* XXX */ 47441595Ssklower m -> m_len--; 47541936Ssklower m -> m_data++; 47641595Ssklower } 47741595Ssklower len = m -> m_len; 47841595Ssklower while (m -> m_next) { 47941595Ssklower m = m -> m_next; 48041595Ssklower len += m -> m_len; 48141595Ssklower } 48241595Ssklower if (len > (1 << lcp -> lcd_packetsize)) { 48341595Ssklower m_freem (m0); 48441595Ssklower return (EMSGSIZE); 48541595Ssklower } 486*42277Ssklower if (lcp -> lcd_so) 487*42277Ssklower sbappendrecord (&lcp -> lcd_so -> so_snd, m0); 488*42277Ssklower else 489*42277Ssklower pq_appendrecord (&lcp -> lcd_downq, m0); 49041595Ssklower lcp -> lcd_template = 0; 49141595Ssklower lcp -> lcd_txcnt++; 49241595Ssklower pk_output (lcp); 49341595Ssklower return (0); 49441595Ssklower } 495