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*39754Smckusick * @(#)nfs_socket.c 7.5 (Berkeley) 12/20/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 28*39754Smckusick * stream as defined by "RPC: Remote Procedure Call Protocol 29*39754Smckusick * Specification" RFC1057 Section 10) 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; 12439494Smckusick 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 */ 170*39754Smckusick nfs_udpreceive(so, msk, mtch, aname, mp) 17138414Smckusick register struct socket *so; 172*39754Smckusick u_long msk; 173*39754Smckusick u_long mtch; 17438414Smckusick struct mbuf **aname; 17538414Smckusick struct mbuf **mp; 17638414Smckusick { 17738414Smckusick register struct mbuf *m; 17838414Smckusick int s, error = 0; 17938414Smckusick struct mbuf *nextrecord; 180*39754Smckusick struct sockaddr_in *saddr; 18138414Smckusick 18238414Smckusick if (aname) 18338414Smckusick *aname = 0; 18438414Smckusick 18538414Smckusick restart: 18638414Smckusick sblock(&so->so_rcv); 18738414Smckusick s = splnet(); 18838414Smckusick 18938414Smckusick if (so->so_rcv.sb_cc == 0) { 19038414Smckusick if (so->so_error) { 19138414Smckusick error = so->so_error; 19238414Smckusick so->so_error = 0; 19338414Smckusick goto release; 19438414Smckusick } 19538414Smckusick if (so->so_state & SS_CANTRCVMORE) 19638414Smckusick goto release; 19738414Smckusick sbunlock(&so->so_rcv); 19838414Smckusick sbwait(&so->so_rcv); 19938414Smckusick splx(s); 20038414Smckusick goto restart; 20138414Smckusick } 20238414Smckusick m = so->so_rcv.sb_mb; 20338414Smckusick if (m == 0) 20438414Smckusick panic("nfs_receive 1"); 20538414Smckusick nextrecord = m->m_nextpkt; 20638414Smckusick if (m->m_type != MT_SONAME) 20738414Smckusick panic("nfs_receive 1a"); 208*39754Smckusick if (msk) { 209*39754Smckusick saddr = mtod(m, struct sockaddr_in *); 210*39754Smckusick if ((saddr->sin_addr.s_addr & msk) != mtch) { 211*39754Smckusick sbdroprecord(&so->so_rcv); 212*39754Smckusick sbunlock(&so->so_rcv); 213*39754Smckusick splx(s); 214*39754Smckusick goto restart; 215*39754Smckusick } 216*39754Smckusick } 21738414Smckusick sbfree(&so->so_rcv, m); 21838414Smckusick if (aname) { 21938414Smckusick *aname = m; 22038414Smckusick so->so_rcv.sb_mb = m->m_next; 22138414Smckusick m->m_next = 0; 22238414Smckusick m = so->so_rcv.sb_mb; 22338414Smckusick } else { 22438414Smckusick MFREE(m, so->so_rcv.sb_mb); 22538414Smckusick m = so->so_rcv.sb_mb; 22638414Smckusick } 22738414Smckusick if (m && m->m_type == MT_RIGHTS) 22838414Smckusick panic("nfs_receive 2"); 22938414Smckusick if (m && m->m_type == MT_CONTROL) { 23038414Smckusick sbfree(&so->so_rcv, m); 23138414Smckusick MFREE(m, so->so_rcv.sb_mb); 23238414Smckusick m = so->so_rcv.sb_mb; 23338414Smckusick } 23438414Smckusick *mp = m; 23538414Smckusick while (m) { 23638414Smckusick if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 23738414Smckusick panic("nfs_receive 3"); 23838414Smckusick sbfree(&so->so_rcv, m); 23938414Smckusick m = so->so_rcv.sb_mb = m->m_next; 24038414Smckusick } 24138414Smckusick so->so_rcv.sb_mb = nextrecord; 24238414Smckusick so->so_state &= ~SS_RCVATMARK; /* Necessary ?? */ 24338414Smckusick release: 24438414Smckusick sbunlock(&so->so_rcv); 24538414Smckusick splx(s); 24638414Smckusick return (error); 24738414Smckusick } 24838414Smckusick 24938414Smckusick struct nfsreq nfsreqh = { 25038414Smckusick (struct nfsreq *)0, 25138414Smckusick (struct nfsreq *)0, 25238414Smckusick (struct mbuf *)0, 25338414Smckusick (struct mbuf *)0, 25438414Smckusick (struct nfsmount *)0, 25538414Smckusick 0, 0, 0, 0, 0, 25638414Smckusick }; 25738414Smckusick 25838414Smckusick struct rpc_replyhead { 25938414Smckusick u_long r_xid; 26038414Smckusick u_long r_rep; 26138414Smckusick }; 26238414Smckusick 26338414Smckusick /* 26438414Smckusick * Implement receipt of reply on a socket. 26538414Smckusick * We depend on the way that records are added to the sockbuf 26638414Smckusick * by sbappend*. In particular, each record (mbufs linked through m_next) 26738414Smckusick * must begin with an address, followed by optional MT_CONTROL mbuf 26838414Smckusick * and then zero or more mbufs of data. 26938414Smckusick * Although the sockbuf is locked, new data may still be appended, 27038414Smckusick * and thus we must maintain consistency of the sockbuf during that time. 27138414Smckusick * We must search through the list of received datagrams matching them 27238414Smckusick * with outstanding requests using the xid, until ours is found. 27338414Smckusick */ 27439494Smckusick /* ARGSUSED */ 27539344Smckusick nfs_udpreply(so, mntp, myrep) 27638414Smckusick register struct socket *so; 27738414Smckusick struct nfsmount *mntp; 27839344Smckusick struct nfsreq *myrep; 27938414Smckusick { 28038414Smckusick register struct mbuf *m; 28138414Smckusick register struct nfsreq *rep; 28238414Smckusick register int error = 0, s; 28338414Smckusick struct mbuf *nextrecord; 28439344Smckusick struct sockaddr_in *saddr; 28539344Smckusick u_long inaddr; 28638414Smckusick struct rpc_replyhead replyh; 28738414Smckusick struct mbuf *mp; 28838414Smckusick char *cp; 28938414Smckusick int cnt, xfer; 29038414Smckusick int found; 29138414Smckusick 29238414Smckusick restart: 29339344Smckusick nfs_sblock(&so->so_rcv); 29438414Smckusick /* Already received, bye bye */ 29539344Smckusick if (myrep->r_mrep != NULL) { 29639344Smckusick sbunlock(&so->so_rcv); 29738414Smckusick return (0); 29839344Smckusick } 29938414Smckusick /* If a soft mount and we have run out of retries */ 30039344Smckusick if (myrep->r_retry == 0 && myrep->r_timer == 0) { 30139344Smckusick sbunlock(&so->so_rcv); 30238414Smckusick return (ETIMEDOUT); 30339344Smckusick } 30438414Smckusick s = splnet(); 30538414Smckusick 30639344Smckusick m = so->so_rcv.sb_mb; 30739344Smckusick if (m == 0) { 30839344Smckusick if (so->so_rcv.sb_cc) 30939344Smckusick panic("nfs_soreply 1"); 31038414Smckusick if (so->so_error) { 31138414Smckusick error = so->so_error; 31238414Smckusick so->so_error = 0; 31338414Smckusick goto release; 31438414Smckusick } 31538414Smckusick if (so->so_state & SS_CANTRCVMORE) 31638414Smckusick goto release; 31738414Smckusick sbunlock(&so->so_rcv); 31838414Smckusick nfs_sbwait(&so->so_rcv); 31938414Smckusick splx(s); 32038414Smckusick goto restart; 32138414Smckusick } 32238414Smckusick nextrecord = m->m_nextpkt; 32338414Smckusick 32438414Smckusick /* 32538414Smckusick * Take off the address, check for rights and ditch any control 32638414Smckusick * mbufs. 32738414Smckusick */ 32838414Smckusick if (m->m_type != MT_SONAME) 32938414Smckusick panic("nfs reply SONAME"); 33039344Smckusick saddr = mtod(m, struct sockaddr_in *); 33139344Smckusick inaddr = saddr->sin_addr.s_addr; 33238414Smckusick sbfree(&so->so_rcv, m); 33338414Smckusick MFREE(m, so->so_rcv.sb_mb); 33438414Smckusick m = so->so_rcv.sb_mb; 33538414Smckusick if (m && m->m_type == MT_RIGHTS) 33638414Smckusick panic("nfs reply RIGHTS"); 33738414Smckusick if (m && m->m_type == MT_CONTROL) { 33838414Smckusick sbfree(&so->so_rcv, m); 33938414Smckusick MFREE(m, so->so_rcv.sb_mb); 34038414Smckusick m = so->so_rcv.sb_mb; 34138414Smckusick } 34239344Smckusick if (m) { 34338414Smckusick m->m_nextpkt = nextrecord; 34439344Smckusick } else { 34539344Smckusick so->so_rcv.sb_mb = nextrecord; 34638414Smckusick sbunlock(&so->so_rcv); 34738414Smckusick splx(s); 34838414Smckusick goto restart; 34938414Smckusick } 35038414Smckusick 35138414Smckusick /* 35238414Smckusick * Get the xid and check that it is an rpc reply 35338414Smckusick */ 35438414Smckusick mp = m; 35538414Smckusick if (m->m_len >= 2*NFSX_UNSIGNED) 35638414Smckusick bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED); 35738414Smckusick else { 35838414Smckusick cnt = 2*NFSX_UNSIGNED; 35938414Smckusick cp = (caddr_t)&replyh; 36038414Smckusick while (mp && cnt > 0) { 36138414Smckusick if (mp->m_len > 0) { 36238414Smckusick xfer = (mp->m_len >= cnt) ? cnt : mp->m_len; 36338414Smckusick bcopy(mtod(mp, caddr_t), cp, xfer); 36438414Smckusick cnt -= xfer; 36538414Smckusick cp += xfer; 36638414Smckusick } 36738414Smckusick if (cnt > 0) 36838414Smckusick mp = mp->m_next; 36938414Smckusick } 37038414Smckusick } 37139344Smckusick found = 0; 37238414Smckusick if (replyh.r_rep != rpc_reply || mp == NULL) 37338414Smckusick goto dropit; 37438414Smckusick /* 37538414Smckusick * Loop through the request list to match up the reply 37638414Smckusick * Iff no match, just drop the datagram 37738414Smckusick */ 37839344Smckusick rep = nfsreqh.r_next; 37939344Smckusick while (!found && rep != &nfsreqh) { 38039344Smckusick if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid && 38139344Smckusick inaddr == rep->r_inaddr) { 38238414Smckusick /* Found it.. */ 38338414Smckusick rep->r_mrep = m; 38438414Smckusick while (m) { 38538414Smckusick if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 38638414Smckusick panic("nfs_soreply 3"); 38738414Smckusick sbfree(&so->so_rcv, m); 38838414Smckusick m = so->so_rcv.sb_mb = m->m_next; 38938414Smckusick } 39038414Smckusick so->so_rcv.sb_mb = nextrecord; 39138414Smckusick if (rep == myrep) 39238414Smckusick goto release; 39338414Smckusick found++; 39438414Smckusick } 39538414Smckusick rep = rep->r_next; 39638414Smckusick } 39738414Smckusick /* Iff not matched to request, drop it */ 39838414Smckusick dropit: 39939344Smckusick if (!found) { 40038414Smckusick sbdroprecord(&so->so_rcv); 40139344Smckusick } else if (so->so_rcv.sb_flags & SB_WAIT) { 40239344Smckusick so->so_rcv.sb_flags &= ~SB_WAIT; 40339344Smckusick wakeup((caddr_t)&so->so_rcv.sb_cc); 40439344Smckusick } 40538414Smckusick sbunlock(&so->so_rcv); 40638414Smckusick splx(s); 40738414Smckusick goto restart; 40838414Smckusick release: 40938414Smckusick sbunlock(&so->so_rcv); 41038414Smckusick splx(s); 41138414Smckusick return (error); 41238414Smckusick } 41338414Smckusick 41438414Smckusick /* 41538414Smckusick * nfs_request - goes something like this 41638414Smckusick * - fill in request struct 41738414Smckusick * - links it into list 41838414Smckusick * - calls nfs_sosend() for first transmit 41938414Smckusick * - calls nfs_soreceive() to get reply 42038414Smckusick * - break down rpc header and return with nfs reply pointed to 42138414Smckusick * by mrep or error 42238414Smckusick * nb: always frees up mreq mbuf list 42338414Smckusick */ 42438414Smckusick nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp) 42538414Smckusick struct vnode *vp; 42638414Smckusick struct mbuf *mreq; 42738414Smckusick u_long xid; 42838414Smckusick struct mount *mp; 42938414Smckusick struct mbuf **mrp; 43038414Smckusick struct mbuf **mdp; 43138414Smckusick caddr_t *dposp; 43238414Smckusick { 43338414Smckusick register struct mbuf *m, *mrep; 43438414Smckusick register struct nfsreq *rep; 43538414Smckusick register u_long *p; 43638414Smckusick register int len; 43738414Smckusick struct nfsmount *mntp; 43838414Smckusick struct mbuf *md; 43939344Smckusick struct sockaddr_in *saddr; 44039344Smckusick struct nfsreq *reph; 44138414Smckusick caddr_t dpos; 44238414Smckusick char *cp2; 44338414Smckusick int t1; 44438414Smckusick int s; 44538414Smckusick int error; 44638414Smckusick 44738414Smckusick mntp = vfs_to_nfs(mp); 44838414Smckusick m = mreq; 44938414Smckusick MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); 45038414Smckusick rep->r_xid = xid; 45138414Smckusick rep->r_mntp = mntp; 45239344Smckusick saddr = mtod(mntp->nm_sockaddr, struct sockaddr_in *); 45339344Smckusick rep->r_inaddr = saddr->sin_addr.s_addr; 45438414Smckusick rep->r_vp = vp; 45538414Smckusick if (mntp->nm_flag & NFSMNT_SOFT) 45638414Smckusick rep->r_retry = mntp->nm_retrans; 45738414Smckusick else 45838414Smckusick rep->r_retry = VNOVAL; 45938414Smckusick rep->r_mrep = NULL; 46038414Smckusick rep->r_mreq = m; 46138414Smckusick rep->r_timer = rep->r_timeout = mntp->nm_timeo; 46238414Smckusick len = 0; 46338414Smckusick while (m) { 46438414Smckusick len += m->m_len; 46538414Smckusick m = m->m_next; 46638414Smckusick } 46738414Smckusick rep->r_msiz = len; 46838414Smckusick m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT); 46938414Smckusick 47038414Smckusick /* Chain it into list of outstanding requests */ 47139344Smckusick reph = &nfsreqh; 47238414Smckusick s = splnet(); 47339344Smckusick if (reph->r_prev == NULL) { 47439344Smckusick reph->r_next = rep; 47539344Smckusick rep->r_prev = reph; 47639344Smckusick } else { 47739344Smckusick reph->r_prev->r_next = rep; 47839344Smckusick rep->r_prev = reph->r_prev; 47939344Smckusick } 48039344Smckusick reph->r_prev = rep; 48139344Smckusick rep->r_next = reph; 48238414Smckusick splx(s); 48338414Smckusick 48438414Smckusick /* 48538414Smckusick * Iff the NFSMCOPY above succeeded, send it off... 48638414Smckusick * otherwise the timer will retransmit later 48738414Smckusick */ 48838414Smckusick if (m != NULL) 48938414Smckusick error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len); 49039344Smckusick error = nfs_udpreply(mntp->nm_so, mntp, rep); 49138414Smckusick 49238414Smckusick s = splnet(); 49338414Smckusick rep->r_prev->r_next = rep->r_next; 49439344Smckusick rep->r_next->r_prev = rep->r_prev; 49538414Smckusick splx(s); 49638414Smckusick m_freem(rep->r_mreq); 49738414Smckusick mrep = md = rep->r_mrep; 49838414Smckusick FREE((caddr_t)rep, M_NFSREQ); 49938414Smckusick if (error) 50038414Smckusick return (error); 50138414Smckusick 50238414Smckusick /* 50338414Smckusick * break down the rpc header and check if ok 50438414Smckusick */ 50538414Smckusick dpos = mtod(md, caddr_t); 50638414Smckusick nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED); 50738414Smckusick p += 2; 50838414Smckusick if (*p++ == rpc_msgdenied) { 50938414Smckusick if (*p == rpc_mismatch) 51038414Smckusick error = EOPNOTSUPP; 51138414Smckusick else 51238414Smckusick error = EACCES; 51338414Smckusick m_freem(mrep); 51438414Smckusick return (error); 51538414Smckusick } 51638414Smckusick /* 51738414Smckusick * skip over the auth_verf, someday we may want to cache auth_short's 51838414Smckusick * for nfs_reqhead(), but for now just dump it 51938414Smckusick */ 52038414Smckusick if (*++p != 0) { 52138414Smckusick len = nfsm_rndup(fxdr_unsigned(long, *p)); 52238414Smckusick nfsm_adv(len); 52338414Smckusick } 52438414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 52538414Smckusick /* 0 == ok */ 52638414Smckusick if (*p == 0) { 52738414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 52838414Smckusick if (*p != 0) { 52938414Smckusick error = fxdr_unsigned(int, *p); 53038414Smckusick m_freem(mrep); 53138414Smckusick return (error); 53238414Smckusick } 53338414Smckusick *mrp = mrep; 53438414Smckusick *mdp = md; 53538414Smckusick *dposp = dpos; 53638414Smckusick return (0); 53738414Smckusick } 53838414Smckusick m_freem(mrep); 53938414Smckusick return (EPROTONOSUPPORT); 54038414Smckusick nfsmout: 54138414Smckusick return (error); 54238414Smckusick } 54338414Smckusick 54438414Smckusick /* 54538414Smckusick * Get a request for the server main loop 54638414Smckusick * - receive a request via. nfs_soreceive() 54738414Smckusick * - verify it 54838414Smckusick * - fill in the cred struct. 54938414Smckusick */ 550*39754Smckusick nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr, 551*39754Smckusick msk, mtch) 55238414Smckusick struct socket *so; 55338414Smckusick u_long prog; 55438414Smckusick u_long vers; 55538414Smckusick int maxproc; 55638414Smckusick struct mbuf **nam; 55738414Smckusick struct mbuf **mrp; 55838414Smckusick struct mbuf **mdp; 55938414Smckusick caddr_t *dposp; 56038414Smckusick u_long *retxid; 56138414Smckusick u_long *proc; 56238414Smckusick register struct ucred *cr; 563*39754Smckusick u_long msk; 564*39754Smckusick u_long mtch; 56538414Smckusick { 56638414Smckusick register int i; 56739494Smckusick register u_long *p; 56839494Smckusick register long t1; 56939494Smckusick caddr_t dpos, cp2; 57039494Smckusick int error = 0; 57139494Smckusick struct mbuf *mrep, *md; 57239494Smckusick int len; 57338414Smckusick 574*39754Smckusick if (error = nfs_udpreceive(so, msk, mtch, nam, &mrep)) 57538414Smckusick return (error); 57638414Smckusick md = mrep; 57738414Smckusick dpos = mtod(mrep, caddr_t); 57838414Smckusick nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED); 57938414Smckusick *retxid = *p++; 58038414Smckusick if (*p++ != rpc_call) { 58138414Smckusick m_freem(mrep); 58238414Smckusick return (ERPCMISMATCH); 58338414Smckusick } 58438414Smckusick if (*p++ != rpc_vers) { 58538414Smckusick m_freem(mrep); 58638414Smckusick return (ERPCMISMATCH); 58738414Smckusick } 58838414Smckusick if (*p++ != prog) { 58938414Smckusick m_freem(mrep); 59038414Smckusick return (EPROGUNAVAIL); 59138414Smckusick } 59238414Smckusick if (*p++ != vers) { 59338414Smckusick m_freem(mrep); 59438414Smckusick return (EPROGMISMATCH); 59538414Smckusick } 59638414Smckusick *proc = fxdr_unsigned(u_long, *p++); 59738414Smckusick if (*proc == NFSPROC_NULL) { 59838414Smckusick *mrp = mrep; 59938414Smckusick return (0); 60038414Smckusick } 60138414Smckusick if (*proc > maxproc || *p++ != rpc_auth_unix) { 60238414Smckusick m_freem(mrep); 60338414Smckusick return (EPROCUNAVAIL); 60438414Smckusick } 60539494Smckusick (void) fxdr_unsigned(int, *p++); 60639494Smckusick len = fxdr_unsigned(int, *++p); 60739494Smckusick nfsm_adv(nfsm_rndup(len)); 60838414Smckusick nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED); 60938414Smckusick cr->cr_uid = fxdr_unsigned(uid_t, *p++); 61038414Smckusick cr->cr_gid = fxdr_unsigned(gid_t, *p++); 61139494Smckusick len = fxdr_unsigned(int, *p); 61239494Smckusick if (len > 10) { 61338414Smckusick m_freem(mrep); 61438414Smckusick return (EBADRPC); 61538414Smckusick } 61639494Smckusick nfsm_disect(p, u_long *, (len + 2)*NFSX_UNSIGNED); 61739494Smckusick for (i = 1; i <= len; i++) 61838414Smckusick cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++); 61939494Smckusick cr->cr_ngroups = len + 1; 62038414Smckusick /* 62138414Smckusick * Do we have any use for the verifier. 62238414Smckusick * According to the "Remote Procedure Call Protocol Spec." it 62338414Smckusick * should be AUTH_NULL, but some clients make it AUTH_UNIX? 62438414Smckusick * For now, just skip over it 62538414Smckusick */ 62639494Smckusick len = fxdr_unsigned(int, *++p); 62739494Smckusick if (len > 0) 62839494Smckusick nfsm_adv(nfsm_rndup(len)); 62938414Smckusick *mrp = mrep; 63038414Smckusick *mdp = md; 63138414Smckusick *dposp = dpos; 63238414Smckusick return (0); 63338414Smckusick nfsmout: 63438414Smckusick return (error); 63538414Smckusick } 63638414Smckusick 63738414Smckusick /* 63838414Smckusick * Generate the rpc reply header 63938414Smckusick * siz arg. is used to decide if adding a cluster is worthwhile 64038414Smckusick */ 64138414Smckusick nfs_rephead(siz, retxid, err, mrq, mbp, bposp) 64238414Smckusick int siz; 64338414Smckusick u_long retxid; 64438414Smckusick int err; 64538414Smckusick struct mbuf **mrq; 64638414Smckusick struct mbuf **mbp; 64738414Smckusick caddr_t *bposp; 64838414Smckusick { 64939494Smckusick register u_long *p; 65039494Smckusick register long t1; 65139494Smckusick caddr_t bpos; 65239494Smckusick struct mbuf *mreq, *mb, *mb2; 65338414Smckusick 65438414Smckusick NFSMGETHDR(mreq); 65538414Smckusick mb = mreq; 65638414Smckusick if ((siz+RPC_REPLYSIZ) > MHLEN) 65738414Smckusick NFSMCLGET(mreq, M_WAIT); 65838414Smckusick p = mtod(mreq, u_long *); 65938414Smckusick mreq->m_len = 6*NFSX_UNSIGNED; 66038414Smckusick bpos = ((caddr_t)p)+mreq->m_len; 66138414Smckusick *p++ = retxid; 66238414Smckusick *p++ = rpc_reply; 66338414Smckusick if (err == ERPCMISMATCH) { 66438414Smckusick *p++ = rpc_msgdenied; 66538414Smckusick *p++ = rpc_mismatch; 66638414Smckusick *p++ = txdr_unsigned(2); 66738414Smckusick *p = txdr_unsigned(2); 66838414Smckusick } else { 66938414Smckusick *p++ = rpc_msgaccepted; 67038414Smckusick *p++ = 0; 67138414Smckusick *p++ = 0; 67238414Smckusick switch (err) { 67338414Smckusick case EPROGUNAVAIL: 67438414Smckusick *p = txdr_unsigned(RPC_PROGUNAVAIL); 67538414Smckusick break; 67638414Smckusick case EPROGMISMATCH: 67738414Smckusick *p = txdr_unsigned(RPC_PROGMISMATCH); 67838414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 67938414Smckusick *p++ = txdr_unsigned(2); 68038414Smckusick *p = txdr_unsigned(2); /* someday 3 */ 68138414Smckusick break; 68238414Smckusick case EPROCUNAVAIL: 68338414Smckusick *p = txdr_unsigned(RPC_PROCUNAVAIL); 68438414Smckusick break; 68538414Smckusick default: 68638414Smckusick *p = 0; 68738414Smckusick if (err != VNOVAL) { 68838414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED); 68938414Smckusick *p = txdr_unsigned(err); 69038414Smckusick } 69138414Smckusick break; 69238414Smckusick }; 69338414Smckusick } 69438414Smckusick *mrq = mreq; 69538414Smckusick *mbp = mb; 69638414Smckusick *bposp = bpos; 69738414Smckusick if (err != 0 && err != VNOVAL) 69838414Smckusick nfsstats.srvrpc_errs++; 69938414Smckusick return (0); 70038414Smckusick } 70138414Smckusick 70238414Smckusick /* 70338414Smckusick * Nfs timer routine 70438414Smckusick * Scan the nfsreq list and retranmit any requests that have timed out 70538414Smckusick * To avoid retransmission attempts on STREAM sockets (in the future) make 70638414Smckusick * sure to set the r_retry field to 0. 70738414Smckusick */ 70838414Smckusick nfs_timer() 70938414Smckusick { 71038414Smckusick register struct nfsreq *rep; 71138414Smckusick register struct mbuf *m; 71238414Smckusick register struct socket *so; 71339494Smckusick int s; 71438414Smckusick 71538414Smckusick s = splnet(); 71638414Smckusick rep = nfsreqh.r_next; 71739344Smckusick while (rep && rep != &nfsreqh) { 71838414Smckusick if (rep->r_timer > 0) 71938414Smckusick rep->r_timer--; 72038414Smckusick else if (rep->r_mrep == NULL && rep->r_retry > 0) { 72138414Smckusick so = rep->r_mntp->nm_so; 72238414Smckusick if ((so->so_state & SS_CANTSENDMORE) == 0 && 72338414Smckusick !so->so_error && 72438414Smckusick sbspace(&so->so_snd) >= rep->r_msiz) { 72538414Smckusick m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT); 72638414Smckusick if (m != NULL) { 72738414Smckusick nfsstats.rpcretries++; 72838425Smckusick rep->r_timeout <<= 2; /* x4 backoff */ 72938425Smckusick if (rep->r_timeout > NFS_MAXTIMEO) 73038425Smckusick rep->r_timeout = NFS_MAXTIMEO; 73138414Smckusick rep->r_timer = rep->r_timeout; 73238414Smckusick if (rep->r_retry != VNOVAL) 73338414Smckusick rep->r_retry--; 73438414Smckusick #ifdef MGETHDR 73538414Smckusick m->m_pkthdr.len = rep->r_msiz; 73638414Smckusick #endif 73738414Smckusick (*so->so_proto->pr_usrreq)(so, PRU_SEND, 73838414Smckusick m, (caddr_t)0, (struct mbuf *)0, 73938414Smckusick (struct mbuf *)0); 74038414Smckusick } 74138414Smckusick } 74238414Smckusick } 74338414Smckusick rep = rep->r_next; 74438414Smckusick } 74538414Smckusick splx(s); 74638425Smckusick timeout(nfs_timer, (caddr_t)0, hz/10); 74738414Smckusick } 74838414Smckusick 74938414Smckusick /* 75038414Smckusick * nfs_sbwait() is simply sbwait() but at a negative priority so that it 75138414Smckusick * can not be interrupted by a signal. 75238414Smckusick */ 75338414Smckusick nfs_sbwait(sb) 75438414Smckusick struct sockbuf *sb; 75538414Smckusick { 75638414Smckusick sb->sb_flags |= SB_WAIT; 75739344Smckusick sleep((caddr_t)&sb->sb_cc, PZERO-2); 75838414Smckusick } 759