138414Smckusick /* 238414Smckusick * Copyright (c) 1989 The Regents of the University of California. 338414Smckusick * All rights reserved. 438414Smckusick * 538414Smckusick * This code is derived from software contributed to Berkeley by 638414Smckusick * Rick Macklem at The University of Guelph. 738414Smckusick * 838414Smckusick * Redistribution and use in source and binary forms are permitted 938414Smckusick * provided that the above copyright notice and this paragraph are 1038414Smckusick * duplicated in all such forms and that any documentation, 1138414Smckusick * advertising materials, and other materials related to such 1238414Smckusick * distribution and use acknowledge that the software was developed 1338414Smckusick * by the University of California, Berkeley. The name of the 1438414Smckusick * University may not be used to endorse or promote products derived 1538414Smckusick * from this software without specific prior written permission. 1638414Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738414Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838414Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938414Smckusick * 20*39494Smckusick * @(#)nfs_socket.c 7.4 (Berkeley) 11/03/89 2138414Smckusick */ 2238414Smckusick 2338414Smckusick /* 2438414Smckusick * Socket operations for use by nfs (similar to uipc_socket.c, but never 2538414Smckusick * with copies to/from a uio vector) 2638414Smckusick * NB: For now, they only work for UDP datagram sockets. 2738414Smckusick * (Use on stream sockets would require some record boundary mark in the 2838414Smckusick * stream such as Sun's RM (Section 3.2 of the Sun RPC Message Protocol 2938414Smckusick * manual, in Networking on the Sun Workstation, Part #800-1324-03 3038414Smckusick * and different versions of send, receive and reply that do not assume 3138414Smckusick * an atomic protocol 3238414Smckusick */ 3338414Smckusick 3438414Smckusick #include "types.h" 3538414Smckusick #include "param.h" 3638414Smckusick #include "uio.h" 3738414Smckusick #include "user.h" 3838414Smckusick #include "mount.h" 3938414Smckusick #include "kernel.h" 4038414Smckusick #include "malloc.h" 4138414Smckusick #include "mbuf.h" 4238414Smckusick #include "vnode.h" 4338414Smckusick #include "domain.h" 4438414Smckusick #include "protosw.h" 4538414Smckusick #include "socket.h" 4638414Smckusick #include "socketvar.h" 4738414Smckusick #include "netinet/in.h" 4838414Smckusick #include "rpcv2.h" 4938414Smckusick #include "nfsv2.h" 5038414Smckusick #include "nfs.h" 5138414Smckusick #include "xdr_subs.h" 5238414Smckusick #include "nfsm_subs.h" 5338414Smckusick #include "nfsmount.h" 5438414Smckusick 5538414Smckusick #define TRUE 1 5638414Smckusick 5738414Smckusick /* set lock on sockbuf sb, sleep at neg prio */ 5838414Smckusick #define nfs_sblock(sb) { \ 5938414Smckusick while ((sb)->sb_flags & SB_LOCK) { \ 6038414Smckusick (sb)->sb_flags |= SB_WANT; \ 6138414Smckusick sleep((caddr_t)&(sb)->sb_flags, PZERO-1); \ 6238414Smckusick } \ 6338414Smckusick (sb)->sb_flags |= SB_LOCK; \ 6438414Smckusick } 6538414Smckusick 6638414Smckusick /* 6738414Smckusick * External data, mostly RPC constants in XDR form 6838414Smckusick */ 6938414Smckusick extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, 7038414Smckusick rpc_msgaccepted, rpc_call; 7138414Smckusick extern u_long nfs_prog, nfs_vers; 7238414Smckusick int nfsrv_null(), 7338414Smckusick nfsrv_getattr(), 7438414Smckusick nfsrv_setattr(), 7538414Smckusick nfsrv_lookup(), 7638414Smckusick nfsrv_readlink(), 7738414Smckusick nfsrv_read(), 7838414Smckusick nfsrv_write(), 7938414Smckusick nfsrv_create(), 8038414Smckusick nfsrv_remove(), 8138414Smckusick nfsrv_rename(), 8238414Smckusick nfsrv_link(), 8338414Smckusick nfsrv_symlink(), 8438414Smckusick nfsrv_mkdir(), 8538414Smckusick nfsrv_rmdir(), 8638414Smckusick nfsrv_readdir(), 8738414Smckusick nfsrv_statfs(), 8838414Smckusick nfsrv_noop(); 8938414Smckusick 9038414Smckusick int (*nfsrv_procs[NFS_NPROCS])() = { 9138414Smckusick nfsrv_null, 9238414Smckusick nfsrv_getattr, 9338414Smckusick nfsrv_setattr, 9438414Smckusick nfsrv_noop, 9538414Smckusick nfsrv_lookup, 9638414Smckusick nfsrv_readlink, 9738414Smckusick nfsrv_read, 9838414Smckusick nfsrv_noop, 9938414Smckusick nfsrv_write, 10038414Smckusick nfsrv_create, 10138414Smckusick nfsrv_remove, 10238414Smckusick nfsrv_rename, 10338414Smckusick nfsrv_link, 10438414Smckusick nfsrv_symlink, 10538414Smckusick nfsrv_mkdir, 10638414Smckusick nfsrv_rmdir, 10738414Smckusick nfsrv_readdir, 10838414Smckusick nfsrv_statfs, 10938414Smckusick }; 11038414Smckusick 11138414Smckusick 11238414Smckusick /* 11338414Smckusick * This is a stripped down version of sosend() specific to 11438414Smckusick * udp/ip and uses the mbuf list provdied 11538414Smckusick */ 11638414Smckusick nfs_udpsend(so, nam, top, flags, siz) 11738414Smckusick register struct socket *so; 11838414Smckusick struct mbuf *nam; 11938414Smckusick struct mbuf *top; 12038414Smckusick int flags; 12138414Smckusick int siz; 12238414Smckusick { 12338414Smckusick register int space; 124*39494Smckusick int error = 0, s, dontroute; 12538414Smckusick 12638414Smckusick dontroute = 12738414Smckusick (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 12838414Smckusick (so->so_proto->pr_flags & PR_ATOMIC); 12938414Smckusick #define snderr(errno) { error = errno; splx(s); goto release; } 13038414Smckusick 13138414Smckusick #ifdef MGETHDR 13238414Smckusick top->m_pkthdr.len = siz; 13338414Smckusick #endif 13438414Smckusick restart: 13538414Smckusick nfs_sblock(&so->so_snd); 13638414Smckusick s = splnet(); 13738414Smckusick if (so->so_state & SS_CANTSENDMORE) 13838414Smckusick snderr(EPIPE); 13938414Smckusick if (so->so_error) 14038414Smckusick snderr(so->so_error); 14138414Smckusick space = sbspace(&so->so_snd); 14238414Smckusick if (space < siz) { 14338414Smckusick sbunlock(&so->so_snd); 14438414Smckusick nfs_sbwait(&so->so_snd); 14538414Smckusick splx(s); 14638414Smckusick goto restart; 14738414Smckusick } 14838414Smckusick splx(s); 14938414Smckusick if (dontroute) 15038414Smckusick so->so_options |= SO_DONTROUTE; 15138414Smckusick s = splnet(); /* XXX */ 15238414Smckusick error = (*so->so_proto->pr_usrreq)(so, 15338414Smckusick PRU_SEND, 15438414Smckusick top, (caddr_t)nam, (struct mbuf *)0, (struct mbuf *)0); 15538414Smckusick splx(s); 15638414Smckusick if (dontroute) 15738414Smckusick so->so_options &= ~SO_DONTROUTE; 15838414Smckusick top = (struct mbuf *)0; 15938414Smckusick 16038414Smckusick release: 16138414Smckusick sbunlock(&so->so_snd); 16238414Smckusick if (top) 16338414Smckusick m_freem(top); 16438414Smckusick return (error); 16538414Smckusick } 16638414Smckusick 16738414Smckusick /* 16838414Smckusick * This is a stripped down udp specific version of soreceive() 16938414Smckusick */ 17038414Smckusick nfs_udpreceive(so, aname, mp) 17138414Smckusick register struct socket *so; 17238414Smckusick struct mbuf **aname; 17338414Smckusick struct mbuf **mp; 17438414Smckusick { 17538414Smckusick register struct mbuf *m; 17638414Smckusick int s, error = 0; 17738414Smckusick struct mbuf *nextrecord; 17838414Smckusick 17938414Smckusick if (aname) 18038414Smckusick *aname = 0; 18138414Smckusick 18238414Smckusick restart: 18338414Smckusick sblock(&so->so_rcv); 18438414Smckusick s = splnet(); 18538414Smckusick 18638414Smckusick if (so->so_rcv.sb_cc == 0) { 18738414Smckusick if (so->so_error) { 18838414Smckusick error = so->so_error; 18938414Smckusick so->so_error = 0; 19038414Smckusick goto release; 19138414Smckusick } 19238414Smckusick if (so->so_state & SS_CANTRCVMORE) 19338414Smckusick goto release; 19438414Smckusick sbunlock(&so->so_rcv); 19538414Smckusick sbwait(&so->so_rcv); 19638414Smckusick splx(s); 19738414Smckusick goto restart; 19838414Smckusick } 19938414Smckusick m = so->so_rcv.sb_mb; 20038414Smckusick if (m == 0) 20138414Smckusick panic("nfs_receive 1"); 20238414Smckusick nextrecord = m->m_nextpkt; 20338414Smckusick if (m->m_type != MT_SONAME) 20438414Smckusick panic("nfs_receive 1a"); 20538414Smckusick sbfree(&so->so_rcv, m); 20638414Smckusick if (aname) { 20738414Smckusick *aname = m; 20838414Smckusick so->so_rcv.sb_mb = m->m_next; 20938414Smckusick m->m_next = 0; 21038414Smckusick m = so->so_rcv.sb_mb; 21138414Smckusick } else { 21238414Smckusick MFREE(m, so->so_rcv.sb_mb); 21338414Smckusick m = so->so_rcv.sb_mb; 21438414Smckusick } 21538414Smckusick if (m && m->m_type == MT_RIGHTS) 21638414Smckusick panic("nfs_receive 2"); 21738414Smckusick if (m && m->m_type == MT_CONTROL) { 21838414Smckusick sbfree(&so->so_rcv, m); 21938414Smckusick MFREE(m, so->so_rcv.sb_mb); 22038414Smckusick m = so->so_rcv.sb_mb; 22138414Smckusick } 22238414Smckusick *mp = m; 22338414Smckusick while (m) { 22438414Smckusick if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 22538414Smckusick panic("nfs_receive 3"); 22638414Smckusick sbfree(&so->so_rcv, m); 22738414Smckusick m = so->so_rcv.sb_mb = m->m_next; 22838414Smckusick } 22938414Smckusick so->so_rcv.sb_mb = nextrecord; 23038414Smckusick so->so_state &= ~SS_RCVATMARK; /* Necessary ?? */ 23138414Smckusick release: 23238414Smckusick sbunlock(&so->so_rcv); 23338414Smckusick splx(s); 23438414Smckusick return (error); 23538414Smckusick } 23638414Smckusick 23738414Smckusick struct nfsreq nfsreqh = { 23838414Smckusick (struct nfsreq *)0, 23938414Smckusick (struct nfsreq *)0, 24038414Smckusick (struct mbuf *)0, 24138414Smckusick (struct mbuf *)0, 24238414Smckusick (struct nfsmount *)0, 24338414Smckusick 0, 0, 0, 0, 0, 24438414Smckusick }; 24538414Smckusick 24638414Smckusick struct rpc_replyhead { 24738414Smckusick u_long r_xid; 24838414Smckusick u_long r_rep; 24938414Smckusick }; 25038414Smckusick 25138414Smckusick /* 25238414Smckusick * Implement receipt of reply on a socket. 25338414Smckusick * We depend on the way that records are added to the sockbuf 25438414Smckusick * by sbappend*. In particular, each record (mbufs linked through m_next) 25538414Smckusick * must begin with an address, followed by optional MT_CONTROL mbuf 25638414Smckusick * and then zero or more mbufs of data. 25738414Smckusick * Although the sockbuf is locked, new data may still be appended, 25838414Smckusick * and thus we must maintain consistency of the sockbuf during that time. 25938414Smckusick * We must search through the list of received datagrams matching them 26038414Smckusick * with outstanding requests using the xid, until ours is found. 26138414Smckusick */ 262*39494Smckusick /* ARGSUSED */ 26339344Smckusick nfs_udpreply(so, mntp, myrep) 26438414Smckusick register struct socket *so; 26538414Smckusick struct nfsmount *mntp; 26639344Smckusick struct nfsreq *myrep; 26738414Smckusick { 26838414Smckusick register struct mbuf *m; 26938414Smckusick register struct nfsreq *rep; 27038414Smckusick register int error = 0, s; 27138414Smckusick struct mbuf *nextrecord; 27239344Smckusick struct sockaddr_in *saddr; 27339344Smckusick u_long inaddr; 27438414Smckusick struct rpc_replyhead replyh; 27538414Smckusick struct mbuf *mp; 27638414Smckusick char *cp; 27738414Smckusick int cnt, xfer; 27838414Smckusick int found; 27938414Smckusick 28038414Smckusick restart: 28139344Smckusick nfs_sblock(&so->so_rcv); 28238414Smckusick /* Already received, bye bye */ 28339344Smckusick if (myrep->r_mrep != NULL) { 28439344Smckusick sbunlock(&so->so_rcv); 28538414Smckusick return (0); 28639344Smckusick } 28738414Smckusick /* If a soft mount and we have run out of retries */ 28839344Smckusick if (myrep->r_retry == 0 && myrep->r_timer == 0) { 28939344Smckusick sbunlock(&so->so_rcv); 29038414Smckusick return (ETIMEDOUT); 29139344Smckusick } 29238414Smckusick s = splnet(); 29338414Smckusick 29439344Smckusick m = so->so_rcv.sb_mb; 29539344Smckusick if (m == 0) { 29639344Smckusick if (so->so_rcv.sb_cc) 29739344Smckusick panic("nfs_soreply 1"); 29838414Smckusick if (so->so_error) { 29938414Smckusick error = so->so_error; 30038414Smckusick so->so_error = 0; 30138414Smckusick goto release; 30238414Smckusick } 30338414Smckusick if (so->so_state & SS_CANTRCVMORE) 30438414Smckusick goto release; 30538414Smckusick sbunlock(&so->so_rcv); 30638414Smckusick nfs_sbwait(&so->so_rcv); 30738414Smckusick splx(s); 30838414Smckusick goto restart; 30938414Smckusick } 31038414Smckusick nextrecord = m->m_nextpkt; 31138414Smckusick 31238414Smckusick /* 31338414Smckusick * Take off the address, check for rights and ditch any control 31438414Smckusick * mbufs. 31538414Smckusick */ 31638414Smckusick if (m->m_type != MT_SONAME) 31738414Smckusick panic("nfs reply SONAME"); 31839344Smckusick saddr = mtod(m, struct sockaddr_in *); 31939344Smckusick inaddr = saddr->sin_addr.s_addr; 32038414Smckusick sbfree(&so->so_rcv, m); 32138414Smckusick MFREE(m, so->so_rcv.sb_mb); 32238414Smckusick m = so->so_rcv.sb_mb; 32338414Smckusick if (m && m->m_type == MT_RIGHTS) 32438414Smckusick panic("nfs reply RIGHTS"); 32538414Smckusick if (m && m->m_type == MT_CONTROL) { 32638414Smckusick sbfree(&so->so_rcv, m); 32738414Smckusick MFREE(m, so->so_rcv.sb_mb); 32838414Smckusick m = so->so_rcv.sb_mb; 32938414Smckusick } 33039344Smckusick if (m) { 33138414Smckusick m->m_nextpkt = nextrecord; 33239344Smckusick } else { 33339344Smckusick so->so_rcv.sb_mb = nextrecord; 33438414Smckusick sbunlock(&so->so_rcv); 33538414Smckusick splx(s); 33638414Smckusick goto restart; 33738414Smckusick } 33838414Smckusick 33938414Smckusick /* 34038414Smckusick * Get the xid and check that it is an rpc reply 34138414Smckusick */ 34238414Smckusick mp = m; 34338414Smckusick if (m->m_len >= 2*NFSX_UNSIGNED) 34438414Smckusick bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED); 34538414Smckusick else { 34638414Smckusick cnt = 2*NFSX_UNSIGNED; 34738414Smckusick cp = (caddr_t)&replyh; 34838414Smckusick while (mp && cnt > 0) { 34938414Smckusick if (mp->m_len > 0) { 35038414Smckusick xfer = (mp->m_len >= cnt) ? cnt : mp->m_len; 35138414Smckusick bcopy(mtod(mp, caddr_t), cp, xfer); 35238414Smckusick cnt -= xfer; 35338414Smckusick cp += xfer; 35438414Smckusick } 35538414Smckusick if (cnt > 0) 35638414Smckusick mp = mp->m_next; 35738414Smckusick } 35838414Smckusick } 35939344Smckusick found = 0; 36038414Smckusick if (replyh.r_rep != rpc_reply || mp == NULL) 36138414Smckusick goto dropit; 36238414Smckusick /* 36338414Smckusick * Loop through the request list to match up the reply 36438414Smckusick * Iff no match, just drop the datagram 36538414Smckusick */ 36639344Smckusick rep = nfsreqh.r_next; 36739344Smckusick while (!found && rep != &nfsreqh) { 36839344Smckusick if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid && 36939344Smckusick inaddr == rep->r_inaddr) { 37038414Smckusick /* Found it.. */ 37138414Smckusick rep->r_mrep = m; 37238414Smckusick while (m) { 37338414Smckusick if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 37438414Smckusick panic("nfs_soreply 3"); 37538414Smckusick sbfree(&so->so_rcv, m); 37638414Smckusick m = so->so_rcv.sb_mb = m->m_next; 37738414Smckusick } 37838414Smckusick so->so_rcv.sb_mb = nextrecord; 37938414Smckusick if (rep == myrep) 38038414Smckusick goto release; 38138414Smckusick found++; 38238414Smckusick } 38338414Smckusick rep = rep->r_next; 38438414Smckusick } 38538414Smckusick /* Iff not matched to request, drop it */ 38638414Smckusick dropit: 38739344Smckusick if (!found) { 38838414Smckusick sbdroprecord(&so->so_rcv); 38939344Smckusick } else if (so->so_rcv.sb_flags & SB_WAIT) { 39039344Smckusick so->so_rcv.sb_flags &= ~SB_WAIT; 39139344Smckusick wakeup((caddr_t)&so->so_rcv.sb_cc); 39239344Smckusick } 39338414Smckusick sbunlock(&so->so_rcv); 39438414Smckusick splx(s); 39538414Smckusick goto restart; 39638414Smckusick release: 39738414Smckusick sbunlock(&so->so_rcv); 39838414Smckusick splx(s); 39938414Smckusick return (error); 40038414Smckusick } 40138414Smckusick 40238414Smckusick /* 40338414Smckusick * nfs_request - goes something like this 40438414Smckusick * - fill in request struct 40538414Smckusick * - links it into list 40638414Smckusick * - calls nfs_sosend() for first transmit 40738414Smckusick * - calls nfs_soreceive() to get reply 40838414Smckusick * - break down rpc header and return with nfs reply pointed to 40938414Smckusick * by mrep or error 41038414Smckusick * nb: always frees up mreq mbuf list 41138414Smckusick */ 41238414Smckusick nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp) 41338414Smckusick struct vnode *vp; 41438414Smckusick struct mbuf *mreq; 41538414Smckusick u_long xid; 41638414Smckusick struct mount *mp; 41738414Smckusick struct mbuf **mrp; 41838414Smckusick struct mbuf **mdp; 41938414Smckusick caddr_t *dposp; 42038414Smckusick { 42138414Smckusick register struct mbuf *m, *mrep; 42238414Smckusick register struct nfsreq *rep; 42338414Smckusick register u_long *p; 42438414Smckusick register int len; 42538414Smckusick struct nfsmount *mntp; 42638414Smckusick struct mbuf *md; 42739344Smckusick struct sockaddr_in *saddr; 42839344Smckusick struct nfsreq *reph; 42938414Smckusick caddr_t dpos; 43038414Smckusick char *cp2; 43138414Smckusick int t1; 43238414Smckusick int s; 43338414Smckusick int error; 43438414Smckusick 43538414Smckusick mntp = vfs_to_nfs(mp); 43638414Smckusick m = mreq; 43738414Smckusick MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); 43838414Smckusick rep->r_xid = xid; 43938414Smckusick rep->r_mntp = mntp; 44039344Smckusick saddr = mtod(mntp->nm_sockaddr, struct sockaddr_in *); 44139344Smckusick rep->r_inaddr = saddr->sin_addr.s_addr; 44238414Smckusick rep->r_vp = vp; 44338414Smckusick if (mntp->nm_flag & NFSMNT_SOFT) 44438414Smckusick rep->r_retry = mntp->nm_retrans; 44538414Smckusick else 44638414Smckusick rep->r_retry = VNOVAL; 44738414Smckusick rep->r_mrep = NULL; 44838414Smckusick rep->r_mreq = m; 44938414Smckusick rep->r_timer = rep->r_timeout = mntp->nm_timeo; 45038414Smckusick len = 0; 45138414Smckusick while (m) { 45238414Smckusick len += m->m_len; 45338414Smckusick m = m->m_next; 45438414Smckusick } 45538414Smckusick rep->r_msiz = len; 45638414Smckusick m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT); 45738414Smckusick 45838414Smckusick /* Chain it into list of outstanding requests */ 45939344Smckusick reph = &nfsreqh; 46038414Smckusick s = splnet(); 46139344Smckusick if (reph->r_prev == NULL) { 46239344Smckusick reph->r_next = rep; 46339344Smckusick rep->r_prev = reph; 46439344Smckusick } else { 46539344Smckusick reph->r_prev->r_next = rep; 46639344Smckusick rep->r_prev = reph->r_prev; 46739344Smckusick } 46839344Smckusick reph->r_prev = rep; 46939344Smckusick rep->r_next = reph; 47038414Smckusick splx(s); 47138414Smckusick 47238414Smckusick /* 47338414Smckusick * Iff the NFSMCOPY above succeeded, send it off... 47438414Smckusick * otherwise the timer will retransmit later 47538414Smckusick */ 47638414Smckusick if (m != NULL) 47738414Smckusick error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len); 47839344Smckusick error = nfs_udpreply(mntp->nm_so, mntp, rep); 47938414Smckusick 48038414Smckusick s = splnet(); 48138414Smckusick rep->r_prev->r_next = rep->r_next; 48239344Smckusick rep->r_next->r_prev = rep->r_prev; 48338414Smckusick splx(s); 48438414Smckusick m_freem(rep->r_mreq); 48538414Smckusick mrep = md = rep->r_mrep; 48638414Smckusick FREE((caddr_t)rep, M_NFSREQ); 48738414Smckusick if (error) 48838414Smckusick return (error); 48938414Smckusick 49038414Smckusick /* 49138414Smckusick * break down the rpc header and check if ok 49238414Smckusick */ 49338414Smckusick dpos = mtod(md, caddr_t); 49438414Smckusick nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED); 49538414Smckusick p += 2; 49638414Smckusick if (*p++ == rpc_msgdenied) { 49738414Smckusick if (*p == rpc_mismatch) 49838414Smckusick error = EOPNOTSUPP; 49938414Smckusick else 50038414Smckusick error = EACCES; 50138414Smckusick m_freem(mrep); 50238414Smckusick return (error); 50338414Smckusick } 50438414Smckusick /* 50538414Smckusick * skip over the auth_verf, someday we may want to cache auth_short's 50638414Smckusick * for nfs_reqhead(), but for now just dump it 50738414Smckusick */ 50838414Smckusick if (*++p != 0) { 50938414Smckusick len = nfsm_rndup(fxdr_unsigned(long, *p)); 51038414Smckusick nfsm_adv(len); 51138414Smckusick } 51238414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 51338414Smckusick /* 0 == ok */ 51438414Smckusick if (*p == 0) { 51538414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 51638414Smckusick if (*p != 0) { 51738414Smckusick error = fxdr_unsigned(int, *p); 51838414Smckusick m_freem(mrep); 51938414Smckusick return (error); 52038414Smckusick } 52138414Smckusick *mrp = mrep; 52238414Smckusick *mdp = md; 52338414Smckusick *dposp = dpos; 52438414Smckusick return (0); 52538414Smckusick } 52638414Smckusick m_freem(mrep); 52738414Smckusick return (EPROTONOSUPPORT); 52838414Smckusick nfsmout: 52938414Smckusick return (error); 53038414Smckusick } 53138414Smckusick 53238414Smckusick /* 53338414Smckusick * Get a request for the server main loop 53438414Smckusick * - receive a request via. nfs_soreceive() 53538414Smckusick * - verify it 53638414Smckusick * - fill in the cred struct. 53738414Smckusick */ 53838414Smckusick nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr) 53938414Smckusick struct socket *so; 54038414Smckusick u_long prog; 54138414Smckusick u_long vers; 54238414Smckusick int maxproc; 54338414Smckusick struct mbuf **nam; 54438414Smckusick struct mbuf **mrp; 54538414Smckusick struct mbuf **mdp; 54638414Smckusick caddr_t *dposp; 54738414Smckusick u_long *retxid; 54838414Smckusick u_long *proc; 54938414Smckusick register struct ucred *cr; 55038414Smckusick { 55138414Smckusick register int i; 552*39494Smckusick register u_long *p; 553*39494Smckusick register long t1; 554*39494Smckusick caddr_t dpos, cp2; 555*39494Smckusick int error = 0; 556*39494Smckusick struct mbuf *mrep, *md; 557*39494Smckusick int len; 55838414Smckusick 55938414Smckusick if (error = nfs_udpreceive(so, nam, &mrep)) 56038414Smckusick return (error); 56138414Smckusick md = mrep; 56238414Smckusick dpos = mtod(mrep, caddr_t); 56338414Smckusick nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED); 56438414Smckusick *retxid = *p++; 56538414Smckusick if (*p++ != rpc_call) { 56638414Smckusick m_freem(mrep); 56738414Smckusick return (ERPCMISMATCH); 56838414Smckusick } 56938414Smckusick if (*p++ != rpc_vers) { 57038414Smckusick m_freem(mrep); 57138414Smckusick return (ERPCMISMATCH); 57238414Smckusick } 57338414Smckusick if (*p++ != prog) { 57438414Smckusick m_freem(mrep); 57538414Smckusick return (EPROGUNAVAIL); 57638414Smckusick } 57738414Smckusick if (*p++ != vers) { 57838414Smckusick m_freem(mrep); 57938414Smckusick return (EPROGMISMATCH); 58038414Smckusick } 58138414Smckusick *proc = fxdr_unsigned(u_long, *p++); 58238414Smckusick if (*proc == NFSPROC_NULL) { 58338414Smckusick *mrp = mrep; 58438414Smckusick return (0); 58538414Smckusick } 58638414Smckusick if (*proc > maxproc || *p++ != rpc_auth_unix) { 58738414Smckusick m_freem(mrep); 58838414Smckusick return (EPROCUNAVAIL); 58938414Smckusick } 590*39494Smckusick (void) fxdr_unsigned(int, *p++); 591*39494Smckusick len = fxdr_unsigned(int, *++p); 592*39494Smckusick nfsm_adv(nfsm_rndup(len)); 59338414Smckusick nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED); 59438414Smckusick cr->cr_uid = fxdr_unsigned(uid_t, *p++); 59538414Smckusick cr->cr_gid = fxdr_unsigned(gid_t, *p++); 596*39494Smckusick len = fxdr_unsigned(int, *p); 597*39494Smckusick if (len > 10) { 59838414Smckusick m_freem(mrep); 59938414Smckusick return (EBADRPC); 60038414Smckusick } 601*39494Smckusick nfsm_disect(p, u_long *, (len + 2)*NFSX_UNSIGNED); 602*39494Smckusick for (i = 1; i <= len; i++) 60338414Smckusick cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++); 604*39494Smckusick cr->cr_ngroups = len + 1; 60538414Smckusick /* 60638414Smckusick * Do we have any use for the verifier. 60738414Smckusick * According to the "Remote Procedure Call Protocol Spec." it 60838414Smckusick * should be AUTH_NULL, but some clients make it AUTH_UNIX? 60938414Smckusick * For now, just skip over it 61038414Smckusick */ 611*39494Smckusick len = fxdr_unsigned(int, *++p); 612*39494Smckusick if (len > 0) 613*39494Smckusick nfsm_adv(nfsm_rndup(len)); 61438414Smckusick *mrp = mrep; 61538414Smckusick *mdp = md; 61638414Smckusick *dposp = dpos; 61738414Smckusick return (0); 61838414Smckusick nfsmout: 61938414Smckusick return (error); 62038414Smckusick } 62138414Smckusick 62238414Smckusick /* 62338414Smckusick * Generate the rpc reply header 62438414Smckusick * siz arg. is used to decide if adding a cluster is worthwhile 62538414Smckusick */ 62638414Smckusick nfs_rephead(siz, retxid, err, mrq, mbp, bposp) 62738414Smckusick int siz; 62838414Smckusick u_long retxid; 62938414Smckusick int err; 63038414Smckusick struct mbuf **mrq; 63138414Smckusick struct mbuf **mbp; 63238414Smckusick caddr_t *bposp; 63338414Smckusick { 634*39494Smckusick register u_long *p; 635*39494Smckusick register long t1; 636*39494Smckusick caddr_t bpos; 637*39494Smckusick struct mbuf *mreq, *mb, *mb2; 63838414Smckusick 63938414Smckusick NFSMGETHDR(mreq); 64038414Smckusick mb = mreq; 64138414Smckusick if ((siz+RPC_REPLYSIZ) > MHLEN) 64238414Smckusick NFSMCLGET(mreq, M_WAIT); 64338414Smckusick p = mtod(mreq, u_long *); 64438414Smckusick mreq->m_len = 6*NFSX_UNSIGNED; 64538414Smckusick bpos = ((caddr_t)p)+mreq->m_len; 64638414Smckusick *p++ = retxid; 64738414Smckusick *p++ = rpc_reply; 64838414Smckusick if (err == ERPCMISMATCH) { 64938414Smckusick *p++ = rpc_msgdenied; 65038414Smckusick *p++ = rpc_mismatch; 65138414Smckusick *p++ = txdr_unsigned(2); 65238414Smckusick *p = txdr_unsigned(2); 65338414Smckusick } else { 65438414Smckusick *p++ = rpc_msgaccepted; 65538414Smckusick *p++ = 0; 65638414Smckusick *p++ = 0; 65738414Smckusick switch (err) { 65838414Smckusick case EPROGUNAVAIL: 65938414Smckusick *p = txdr_unsigned(RPC_PROGUNAVAIL); 66038414Smckusick break; 66138414Smckusick case EPROGMISMATCH: 66238414Smckusick *p = txdr_unsigned(RPC_PROGMISMATCH); 66338414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 66438414Smckusick *p++ = txdr_unsigned(2); 66538414Smckusick *p = txdr_unsigned(2); /* someday 3 */ 66638414Smckusick break; 66738414Smckusick case EPROCUNAVAIL: 66838414Smckusick *p = txdr_unsigned(RPC_PROCUNAVAIL); 66938414Smckusick break; 67038414Smckusick default: 67138414Smckusick *p = 0; 67238414Smckusick if (err != VNOVAL) { 67338414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED); 67438414Smckusick *p = txdr_unsigned(err); 67538414Smckusick } 67638414Smckusick break; 67738414Smckusick }; 67838414Smckusick } 67938414Smckusick *mrq = mreq; 68038414Smckusick *mbp = mb; 68138414Smckusick *bposp = bpos; 68238414Smckusick if (err != 0 && err != VNOVAL) 68338414Smckusick nfsstats.srvrpc_errs++; 68438414Smckusick return (0); 68538414Smckusick } 68638414Smckusick 68738414Smckusick /* 68838414Smckusick * Nfs timer routine 68938414Smckusick * Scan the nfsreq list and retranmit any requests that have timed out 69038414Smckusick * To avoid retransmission attempts on STREAM sockets (in the future) make 69138414Smckusick * sure to set the r_retry field to 0. 69238414Smckusick */ 69338414Smckusick nfs_timer() 69438414Smckusick { 69538414Smckusick register struct nfsreq *rep; 69638414Smckusick register struct mbuf *m; 69738414Smckusick register struct socket *so; 698*39494Smckusick int s; 69938414Smckusick 70038414Smckusick s = splnet(); 70138414Smckusick rep = nfsreqh.r_next; 70239344Smckusick while (rep && rep != &nfsreqh) { 70338414Smckusick if (rep->r_timer > 0) 70438414Smckusick rep->r_timer--; 70538414Smckusick else if (rep->r_mrep == NULL && rep->r_retry > 0) { 70638414Smckusick so = rep->r_mntp->nm_so; 70738414Smckusick if ((so->so_state & SS_CANTSENDMORE) == 0 && 70838414Smckusick !so->so_error && 70938414Smckusick sbspace(&so->so_snd) >= rep->r_msiz) { 71038414Smckusick m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT); 71138414Smckusick if (m != NULL) { 71238414Smckusick nfsstats.rpcretries++; 71338425Smckusick rep->r_timeout <<= 2; /* x4 backoff */ 71438425Smckusick if (rep->r_timeout > NFS_MAXTIMEO) 71538425Smckusick rep->r_timeout = NFS_MAXTIMEO; 71638414Smckusick rep->r_timer = rep->r_timeout; 71738414Smckusick if (rep->r_retry != VNOVAL) 71838414Smckusick rep->r_retry--; 71938414Smckusick #ifdef MGETHDR 72038414Smckusick m->m_pkthdr.len = rep->r_msiz; 72138414Smckusick #endif 72238414Smckusick (*so->so_proto->pr_usrreq)(so, PRU_SEND, 72338414Smckusick m, (caddr_t)0, (struct mbuf *)0, 72438414Smckusick (struct mbuf *)0); 72538414Smckusick } 72638414Smckusick } 72738414Smckusick } 72838414Smckusick rep = rep->r_next; 72938414Smckusick } 73038414Smckusick splx(s); 73138425Smckusick timeout(nfs_timer, (caddr_t)0, hz/10); 73238414Smckusick } 73338414Smckusick 73438414Smckusick /* 73538414Smckusick * nfs_sbwait() is simply sbwait() but at a negative priority so that it 73638414Smckusick * can not be interrupted by a signal. 73738414Smckusick */ 73838414Smckusick nfs_sbwait(sb) 73938414Smckusick struct sockbuf *sb; 74038414Smckusick { 74138414Smckusick sb->sb_flags |= SB_WAIT; 74239344Smckusick sleep((caddr_t)&sb->sb_cc, PZERO-2); 74338414Smckusick } 744