1*38414Smckusick /* 2*38414Smckusick * Copyright (c) 1989 The Regents of the University of California. 3*38414Smckusick * All rights reserved. 4*38414Smckusick * 5*38414Smckusick * This code is derived from software contributed to Berkeley by 6*38414Smckusick * Rick Macklem at The University of Guelph. 7*38414Smckusick * 8*38414Smckusick * Redistribution and use in source and binary forms are permitted 9*38414Smckusick * provided that the above copyright notice and this paragraph are 10*38414Smckusick * duplicated in all such forms and that any documentation, 11*38414Smckusick * advertising materials, and other materials related to such 12*38414Smckusick * distribution and use acknowledge that the software was developed 13*38414Smckusick * by the University of California, Berkeley. The name of the 14*38414Smckusick * University may not be used to endorse or promote products derived 15*38414Smckusick * from this software without specific prior written permission. 16*38414Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17*38414Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*38414Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19*38414Smckusick * 20*38414Smckusick * @(#)nfs_socket.c 7.1 (Berkeley) 07/05/89 21*38414Smckusick */ 22*38414Smckusick 23*38414Smckusick /* 24*38414Smckusick * Socket operations for use by nfs (similar to uipc_socket.c, but never 25*38414Smckusick * with copies to/from a uio vector) 26*38414Smckusick * NB: For now, they only work for UDP datagram sockets. 27*38414Smckusick * (Use on stream sockets would require some record boundary mark in the 28*38414Smckusick * stream such as Sun's RM (Section 3.2 of the Sun RPC Message Protocol 29*38414Smckusick * manual, in Networking on the Sun Workstation, Part #800-1324-03 30*38414Smckusick * and different versions of send, receive and reply that do not assume 31*38414Smckusick * an atomic protocol 32*38414Smckusick */ 33*38414Smckusick 34*38414Smckusick #include "types.h" 35*38414Smckusick #include "param.h" 36*38414Smckusick #include "uio.h" 37*38414Smckusick #include "user.h" 38*38414Smckusick #include "mount.h" 39*38414Smckusick #include "kernel.h" 40*38414Smckusick #include "malloc.h" 41*38414Smckusick #include "mbuf.h" 42*38414Smckusick #include "vnode.h" 43*38414Smckusick #include "domain.h" 44*38414Smckusick #include "protosw.h" 45*38414Smckusick #include "socket.h" 46*38414Smckusick #include "socketvar.h" 47*38414Smckusick #include "netinet/in.h" 48*38414Smckusick #include "rpcv2.h" 49*38414Smckusick #include "nfsv2.h" 50*38414Smckusick #include "nfs.h" 51*38414Smckusick #include "xdr_subs.h" 52*38414Smckusick #include "nfsm_subs.h" 53*38414Smckusick #include "nfsmount.h" 54*38414Smckusick 55*38414Smckusick #define TRUE 1 56*38414Smckusick 57*38414Smckusick /* set lock on sockbuf sb, sleep at neg prio */ 58*38414Smckusick #define nfs_sblock(sb) { \ 59*38414Smckusick while ((sb)->sb_flags & SB_LOCK) { \ 60*38414Smckusick (sb)->sb_flags |= SB_WANT; \ 61*38414Smckusick sleep((caddr_t)&(sb)->sb_flags, PZERO-1); \ 62*38414Smckusick } \ 63*38414Smckusick (sb)->sb_flags |= SB_LOCK; \ 64*38414Smckusick } 65*38414Smckusick 66*38414Smckusick /* 67*38414Smckusick * External data, mostly RPC constants in XDR form 68*38414Smckusick */ 69*38414Smckusick extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, 70*38414Smckusick rpc_msgaccepted, rpc_call; 71*38414Smckusick extern u_long nfs_prog, nfs_vers; 72*38414Smckusick int nfsrv_null(), 73*38414Smckusick nfsrv_getattr(), 74*38414Smckusick nfsrv_setattr(), 75*38414Smckusick nfsrv_lookup(), 76*38414Smckusick nfsrv_readlink(), 77*38414Smckusick nfsrv_read(), 78*38414Smckusick nfsrv_write(), 79*38414Smckusick nfsrv_create(), 80*38414Smckusick nfsrv_remove(), 81*38414Smckusick nfsrv_rename(), 82*38414Smckusick nfsrv_link(), 83*38414Smckusick nfsrv_symlink(), 84*38414Smckusick nfsrv_mkdir(), 85*38414Smckusick nfsrv_rmdir(), 86*38414Smckusick nfsrv_readdir(), 87*38414Smckusick nfsrv_statfs(), 88*38414Smckusick nfsrv_noop(); 89*38414Smckusick 90*38414Smckusick int (*nfsrv_procs[NFS_NPROCS])() = { 91*38414Smckusick nfsrv_null, 92*38414Smckusick nfsrv_getattr, 93*38414Smckusick nfsrv_setattr, 94*38414Smckusick nfsrv_noop, 95*38414Smckusick nfsrv_lookup, 96*38414Smckusick nfsrv_readlink, 97*38414Smckusick nfsrv_read, 98*38414Smckusick nfsrv_noop, 99*38414Smckusick nfsrv_write, 100*38414Smckusick nfsrv_create, 101*38414Smckusick nfsrv_remove, 102*38414Smckusick nfsrv_rename, 103*38414Smckusick nfsrv_link, 104*38414Smckusick nfsrv_symlink, 105*38414Smckusick nfsrv_mkdir, 106*38414Smckusick nfsrv_rmdir, 107*38414Smckusick nfsrv_readdir, 108*38414Smckusick nfsrv_statfs, 109*38414Smckusick }; 110*38414Smckusick 111*38414Smckusick 112*38414Smckusick /* 113*38414Smckusick * This is a stripped down version of sosend() specific to 114*38414Smckusick * udp/ip and uses the mbuf list provdied 115*38414Smckusick */ 116*38414Smckusick nfs_udpsend(so, nam, top, flags, siz) 117*38414Smckusick register struct socket *so; 118*38414Smckusick struct mbuf *nam; 119*38414Smckusick struct mbuf *top; 120*38414Smckusick int flags; 121*38414Smckusick int siz; 122*38414Smckusick { 123*38414Smckusick register int space; 124*38414Smckusick int error = 0, s, dontroute, first = 1; 125*38414Smckusick 126*38414Smckusick dontroute = 127*38414Smckusick (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 128*38414Smckusick (so->so_proto->pr_flags & PR_ATOMIC); 129*38414Smckusick #define snderr(errno) { error = errno; splx(s); goto release; } 130*38414Smckusick 131*38414Smckusick #ifdef MGETHDR 132*38414Smckusick top->m_pkthdr.len = siz; 133*38414Smckusick #endif 134*38414Smckusick restart: 135*38414Smckusick nfs_sblock(&so->so_snd); 136*38414Smckusick s = splnet(); 137*38414Smckusick if (so->so_state & SS_CANTSENDMORE) 138*38414Smckusick snderr(EPIPE); 139*38414Smckusick if (so->so_error) 140*38414Smckusick snderr(so->so_error); 141*38414Smckusick space = sbspace(&so->so_snd); 142*38414Smckusick if (space < siz) { 143*38414Smckusick sbunlock(&so->so_snd); 144*38414Smckusick nfs_sbwait(&so->so_snd); 145*38414Smckusick splx(s); 146*38414Smckusick goto restart; 147*38414Smckusick } 148*38414Smckusick splx(s); 149*38414Smckusick if (dontroute) 150*38414Smckusick so->so_options |= SO_DONTROUTE; 151*38414Smckusick s = splnet(); /* XXX */ 152*38414Smckusick error = (*so->so_proto->pr_usrreq)(so, 153*38414Smckusick PRU_SEND, 154*38414Smckusick top, (caddr_t)nam, (struct mbuf *)0, (struct mbuf *)0); 155*38414Smckusick splx(s); 156*38414Smckusick if (dontroute) 157*38414Smckusick so->so_options &= ~SO_DONTROUTE; 158*38414Smckusick top = (struct mbuf *)0; 159*38414Smckusick 160*38414Smckusick release: 161*38414Smckusick sbunlock(&so->so_snd); 162*38414Smckusick if (top) 163*38414Smckusick m_freem(top); 164*38414Smckusick return (error); 165*38414Smckusick } 166*38414Smckusick 167*38414Smckusick /* 168*38414Smckusick * This is a stripped down udp specific version of soreceive() 169*38414Smckusick */ 170*38414Smckusick nfs_udpreceive(so, aname, mp) 171*38414Smckusick register struct socket *so; 172*38414Smckusick struct mbuf **aname; 173*38414Smckusick struct mbuf **mp; 174*38414Smckusick { 175*38414Smckusick register struct mbuf *m; 176*38414Smckusick int s, error = 0; 177*38414Smckusick struct protosw *pr = so->so_proto; 178*38414Smckusick struct mbuf *nextrecord; 179*38414Smckusick 180*38414Smckusick if (aname) 181*38414Smckusick *aname = 0; 182*38414Smckusick 183*38414Smckusick restart: 184*38414Smckusick sblock(&so->so_rcv); 185*38414Smckusick s = splnet(); 186*38414Smckusick 187*38414Smckusick if (so->so_rcv.sb_cc == 0) { 188*38414Smckusick if (so->so_error) { 189*38414Smckusick error = so->so_error; 190*38414Smckusick so->so_error = 0; 191*38414Smckusick goto release; 192*38414Smckusick } 193*38414Smckusick if (so->so_state & SS_CANTRCVMORE) 194*38414Smckusick goto release; 195*38414Smckusick sbunlock(&so->so_rcv); 196*38414Smckusick sbwait(&so->so_rcv); 197*38414Smckusick splx(s); 198*38414Smckusick goto restart; 199*38414Smckusick } 200*38414Smckusick m = so->so_rcv.sb_mb; 201*38414Smckusick if (m == 0) 202*38414Smckusick panic("nfs_receive 1"); 203*38414Smckusick nextrecord = m->m_nextpkt; 204*38414Smckusick if (m->m_type != MT_SONAME) 205*38414Smckusick panic("nfs_receive 1a"); 206*38414Smckusick sbfree(&so->so_rcv, m); 207*38414Smckusick if (aname) { 208*38414Smckusick *aname = m; 209*38414Smckusick so->so_rcv.sb_mb = m->m_next; 210*38414Smckusick m->m_next = 0; 211*38414Smckusick m = so->so_rcv.sb_mb; 212*38414Smckusick } else { 213*38414Smckusick MFREE(m, so->so_rcv.sb_mb); 214*38414Smckusick m = so->so_rcv.sb_mb; 215*38414Smckusick } 216*38414Smckusick if (m && m->m_type == MT_RIGHTS) 217*38414Smckusick panic("nfs_receive 2"); 218*38414Smckusick if (m && m->m_type == MT_CONTROL) { 219*38414Smckusick sbfree(&so->so_rcv, m); 220*38414Smckusick MFREE(m, so->so_rcv.sb_mb); 221*38414Smckusick m = so->so_rcv.sb_mb; 222*38414Smckusick } 223*38414Smckusick *mp = m; 224*38414Smckusick while (m) { 225*38414Smckusick if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 226*38414Smckusick panic("nfs_receive 3"); 227*38414Smckusick sbfree(&so->so_rcv, m); 228*38414Smckusick m = so->so_rcv.sb_mb = m->m_next; 229*38414Smckusick } 230*38414Smckusick so->so_rcv.sb_mb = nextrecord; 231*38414Smckusick so->so_state &= ~SS_RCVATMARK; /* Necessary ?? */ 232*38414Smckusick release: 233*38414Smckusick sbunlock(&so->so_rcv); 234*38414Smckusick splx(s); 235*38414Smckusick return (error); 236*38414Smckusick } 237*38414Smckusick 238*38414Smckusick struct nfsreq nfsreqh = { 239*38414Smckusick (struct nfsreq *)0, 240*38414Smckusick (struct nfsreq *)0, 241*38414Smckusick (struct mbuf *)0, 242*38414Smckusick (struct mbuf *)0, 243*38414Smckusick (struct nfsmount *)0, 244*38414Smckusick 0, 0, 0, 0, 0, 245*38414Smckusick }; 246*38414Smckusick 247*38414Smckusick struct rpc_replyhead { 248*38414Smckusick u_long r_xid; 249*38414Smckusick u_long r_rep; 250*38414Smckusick }; 251*38414Smckusick 252*38414Smckusick /* 253*38414Smckusick * Implement receipt of reply on a socket. 254*38414Smckusick * We depend on the way that records are added to the sockbuf 255*38414Smckusick * by sbappend*. In particular, each record (mbufs linked through m_next) 256*38414Smckusick * must begin with an address, followed by optional MT_CONTROL mbuf 257*38414Smckusick * and then zero or more mbufs of data. 258*38414Smckusick * Although the sockbuf is locked, new data may still be appended, 259*38414Smckusick * and thus we must maintain consistency of the sockbuf during that time. 260*38414Smckusick * We must search through the list of received datagrams matching them 261*38414Smckusick * with outstanding requests using the xid, until ours is found. 262*38414Smckusick */ 263*38414Smckusick nfs_udpreply(so, mntp, repl, myrep) 264*38414Smckusick register struct socket *so; 265*38414Smckusick struct nfsmount *mntp; 266*38414Smckusick struct nfsreq *repl, *myrep; 267*38414Smckusick { 268*38414Smckusick register struct mbuf *m; 269*38414Smckusick register struct nfsreq *rep; 270*38414Smckusick register int error = 0, s; 271*38414Smckusick struct protosw *pr = so->so_proto; 272*38414Smckusick struct mbuf *nextrecord; 273*38414Smckusick struct sockaddr_in *sad, *sad2; 274*38414Smckusick struct rpc_replyhead replyh; 275*38414Smckusick struct mbuf *mp; 276*38414Smckusick char *cp; 277*38414Smckusick int cnt, xfer; 278*38414Smckusick int found; 279*38414Smckusick 280*38414Smckusick restart: 281*38414Smckusick /* Already received, bye bye */ 282*38414Smckusick if (myrep->r_mrep != NULL) 283*38414Smckusick return (0); 284*38414Smckusick /* If a soft mount and we have run out of retries */ 285*38414Smckusick if (myrep->r_retry == 0 && myrep->r_timer == 0) 286*38414Smckusick return (ETIMEDOUT); 287*38414Smckusick nfs_sblock(&so->so_rcv); 288*38414Smckusick s = splnet(); 289*38414Smckusick 290*38414Smckusick if (so->so_rcv.sb_cc == 0) { 291*38414Smckusick if (so->so_error) { 292*38414Smckusick error = so->so_error; 293*38414Smckusick so->so_error = 0; 294*38414Smckusick goto release; 295*38414Smckusick } 296*38414Smckusick if (so->so_state & SS_CANTRCVMORE) 297*38414Smckusick goto release; 298*38414Smckusick sbunlock(&so->so_rcv); 299*38414Smckusick nfs_sbwait(&so->so_rcv); 300*38414Smckusick splx(s); 301*38414Smckusick goto restart; 302*38414Smckusick } 303*38414Smckusick m = so->so_rcv.sb_mb; 304*38414Smckusick if (m == 0) 305*38414Smckusick panic("nfs_soreply 1"); 306*38414Smckusick nextrecord = m->m_nextpkt; 307*38414Smckusick 308*38414Smckusick /* 309*38414Smckusick * Take off the address, check for rights and ditch any control 310*38414Smckusick * mbufs. 311*38414Smckusick */ 312*38414Smckusick if (m->m_type != MT_SONAME) 313*38414Smckusick panic("nfs reply SONAME"); 314*38414Smckusick sad = mtod(m, struct sockaddr_in *); 315*38414Smckusick sad2 = mtod(mntp->nm_sockaddr, struct sockaddr_in *); 316*38414Smckusick found = 0; 317*38414Smckusick if (sad->sin_addr.s_addr != sad2->sin_addr.s_addr) 318*38414Smckusick goto dropit; 319*38414Smckusick sbfree(&so->so_rcv, m); 320*38414Smckusick MFREE(m, so->so_rcv.sb_mb); 321*38414Smckusick m = so->so_rcv.sb_mb; 322*38414Smckusick if (m && m->m_type == MT_RIGHTS) 323*38414Smckusick panic("nfs reply RIGHTS"); 324*38414Smckusick if (m && m->m_type == MT_CONTROL) { 325*38414Smckusick sbfree(&so->so_rcv, m); 326*38414Smckusick MFREE(m, so->so_rcv.sb_mb); 327*38414Smckusick m = so->so_rcv.sb_mb; 328*38414Smckusick } 329*38414Smckusick if (m) 330*38414Smckusick m->m_nextpkt = nextrecord; 331*38414Smckusick else { 332*38414Smckusick sbunlock(&so->so_rcv); 333*38414Smckusick splx(s); 334*38414Smckusick goto restart; 335*38414Smckusick } 336*38414Smckusick 337*38414Smckusick /* 338*38414Smckusick * Get the xid and check that it is an rpc reply 339*38414Smckusick */ 340*38414Smckusick mp = m; 341*38414Smckusick if (m->m_len >= 2*NFSX_UNSIGNED) 342*38414Smckusick bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED); 343*38414Smckusick else { 344*38414Smckusick cnt = 2*NFSX_UNSIGNED; 345*38414Smckusick cp = (caddr_t)&replyh; 346*38414Smckusick while (mp && cnt > 0) { 347*38414Smckusick if (mp->m_len > 0) { 348*38414Smckusick xfer = (mp->m_len >= cnt) ? cnt : mp->m_len; 349*38414Smckusick bcopy(mtod(mp, caddr_t), cp, xfer); 350*38414Smckusick cnt -= xfer; 351*38414Smckusick cp += xfer; 352*38414Smckusick } 353*38414Smckusick if (cnt > 0) 354*38414Smckusick mp = mp->m_next; 355*38414Smckusick } 356*38414Smckusick } 357*38414Smckusick if (replyh.r_rep != rpc_reply || mp == NULL) 358*38414Smckusick goto dropit; 359*38414Smckusick /* 360*38414Smckusick * Loop through the request list to match up the reply 361*38414Smckusick * Iff no match, just drop the datagram 362*38414Smckusick */ 363*38414Smckusick rep = repl; 364*38414Smckusick while (!found && rep) { 365*38414Smckusick if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid) { 366*38414Smckusick /* Found it.. */ 367*38414Smckusick rep->r_mrep = m; 368*38414Smckusick while (m) { 369*38414Smckusick if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 370*38414Smckusick panic("nfs_soreply 3"); 371*38414Smckusick sbfree(&so->so_rcv, m); 372*38414Smckusick m = so->so_rcv.sb_mb = m->m_next; 373*38414Smckusick } 374*38414Smckusick so->so_rcv.sb_mb = nextrecord; 375*38414Smckusick if (rep == myrep) 376*38414Smckusick goto release; 377*38414Smckusick found++; 378*38414Smckusick } 379*38414Smckusick rep = rep->r_next; 380*38414Smckusick } 381*38414Smckusick /* Iff not matched to request, drop it */ 382*38414Smckusick dropit: 383*38414Smckusick if (!found) 384*38414Smckusick sbdroprecord(&so->so_rcv); 385*38414Smckusick sbunlock(&so->so_rcv); 386*38414Smckusick splx(s); 387*38414Smckusick goto restart; 388*38414Smckusick release: 389*38414Smckusick sbunlock(&so->so_rcv); 390*38414Smckusick splx(s); 391*38414Smckusick return (error); 392*38414Smckusick } 393*38414Smckusick 394*38414Smckusick /* 395*38414Smckusick * nfs_request - goes something like this 396*38414Smckusick * - fill in request struct 397*38414Smckusick * - links it into list 398*38414Smckusick * - calls nfs_sosend() for first transmit 399*38414Smckusick * - calls nfs_soreceive() to get reply 400*38414Smckusick * - break down rpc header and return with nfs reply pointed to 401*38414Smckusick * by mrep or error 402*38414Smckusick * nb: always frees up mreq mbuf list 403*38414Smckusick */ 404*38414Smckusick nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp) 405*38414Smckusick struct vnode *vp; 406*38414Smckusick struct mbuf *mreq; 407*38414Smckusick u_long xid; 408*38414Smckusick struct mount *mp; 409*38414Smckusick struct mbuf **mrp; 410*38414Smckusick struct mbuf **mdp; 411*38414Smckusick caddr_t *dposp; 412*38414Smckusick { 413*38414Smckusick register struct mbuf *m, *mrep; 414*38414Smckusick register struct nfsreq *rep; 415*38414Smckusick register u_long *p; 416*38414Smckusick register int len; 417*38414Smckusick struct nfsmount *mntp; 418*38414Smckusick struct mbuf *md; 419*38414Smckusick caddr_t dpos; 420*38414Smckusick char *cp2; 421*38414Smckusick int t1; 422*38414Smckusick int s; 423*38414Smckusick int error; 424*38414Smckusick 425*38414Smckusick mntp = vfs_to_nfs(mp); 426*38414Smckusick m = mreq; 427*38414Smckusick MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); 428*38414Smckusick rep->r_xid = xid; 429*38414Smckusick rep->r_mntp = mntp; 430*38414Smckusick rep->r_vp = vp; 431*38414Smckusick if (mntp->nm_flag & NFSMNT_SOFT) 432*38414Smckusick rep->r_retry = mntp->nm_retrans; 433*38414Smckusick else 434*38414Smckusick rep->r_retry = VNOVAL; 435*38414Smckusick rep->r_mrep = NULL; 436*38414Smckusick rep->r_mreq = m; 437*38414Smckusick rep->r_timer = rep->r_timeout = mntp->nm_timeo; 438*38414Smckusick len = 0; 439*38414Smckusick while (m) { 440*38414Smckusick len += m->m_len; 441*38414Smckusick m = m->m_next; 442*38414Smckusick } 443*38414Smckusick rep->r_msiz = len; 444*38414Smckusick m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT); 445*38414Smckusick 446*38414Smckusick /* Chain it into list of outstanding requests */ 447*38414Smckusick s = splnet(); 448*38414Smckusick rep->r_next = nfsreqh.r_next; 449*38414Smckusick if (rep->r_next != NULL) 450*38414Smckusick rep->r_next->r_prev = rep; 451*38414Smckusick nfsreqh.r_next = rep; 452*38414Smckusick rep->r_prev = &nfsreqh; 453*38414Smckusick splx(s); 454*38414Smckusick 455*38414Smckusick /* 456*38414Smckusick * Iff the NFSMCOPY above succeeded, send it off... 457*38414Smckusick * otherwise the timer will retransmit later 458*38414Smckusick */ 459*38414Smckusick if (m != NULL) 460*38414Smckusick error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len); 461*38414Smckusick error = nfs_udpreply(mntp->nm_so, mntp, nfsreqh.r_next, rep); 462*38414Smckusick 463*38414Smckusick s = splnet(); 464*38414Smckusick rep->r_prev->r_next = rep->r_next; 465*38414Smckusick if (rep->r_next != NULL) 466*38414Smckusick rep->r_next->r_prev = rep->r_prev; 467*38414Smckusick splx(s); 468*38414Smckusick m_freem(rep->r_mreq); 469*38414Smckusick mrep = md = rep->r_mrep; 470*38414Smckusick FREE((caddr_t)rep, M_NFSREQ); 471*38414Smckusick if (error) 472*38414Smckusick return (error); 473*38414Smckusick 474*38414Smckusick /* 475*38414Smckusick * break down the rpc header and check if ok 476*38414Smckusick */ 477*38414Smckusick dpos = mtod(md, caddr_t); 478*38414Smckusick nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED); 479*38414Smckusick p += 2; 480*38414Smckusick if (*p++ == rpc_msgdenied) { 481*38414Smckusick if (*p == rpc_mismatch) 482*38414Smckusick error = EOPNOTSUPP; 483*38414Smckusick else 484*38414Smckusick error = EACCES; 485*38414Smckusick m_freem(mrep); 486*38414Smckusick return (error); 487*38414Smckusick } 488*38414Smckusick /* 489*38414Smckusick * skip over the auth_verf, someday we may want to cache auth_short's 490*38414Smckusick * for nfs_reqhead(), but for now just dump it 491*38414Smckusick */ 492*38414Smckusick if (*++p != 0) { 493*38414Smckusick len = nfsm_rndup(fxdr_unsigned(long, *p)); 494*38414Smckusick nfsm_adv(len); 495*38414Smckusick } 496*38414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 497*38414Smckusick /* 0 == ok */ 498*38414Smckusick if (*p == 0) { 499*38414Smckusick nfsm_disect(p, u_long *, NFSX_UNSIGNED); 500*38414Smckusick if (*p != 0) { 501*38414Smckusick error = fxdr_unsigned(int, *p); 502*38414Smckusick m_freem(mrep); 503*38414Smckusick return (error); 504*38414Smckusick } 505*38414Smckusick *mrp = mrep; 506*38414Smckusick *mdp = md; 507*38414Smckusick *dposp = dpos; 508*38414Smckusick return (0); 509*38414Smckusick } 510*38414Smckusick m_freem(mrep); 511*38414Smckusick return (EPROTONOSUPPORT); 512*38414Smckusick nfsmout: 513*38414Smckusick return (error); 514*38414Smckusick } 515*38414Smckusick 516*38414Smckusick /* 517*38414Smckusick * Get a request for the server main loop 518*38414Smckusick * - receive a request via. nfs_soreceive() 519*38414Smckusick * - verify it 520*38414Smckusick * - fill in the cred struct. 521*38414Smckusick */ 522*38414Smckusick nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr) 523*38414Smckusick struct socket *so; 524*38414Smckusick u_long prog; 525*38414Smckusick u_long vers; 526*38414Smckusick int maxproc; 527*38414Smckusick struct mbuf **nam; 528*38414Smckusick struct mbuf **mrp; 529*38414Smckusick struct mbuf **mdp; 530*38414Smckusick caddr_t *dposp; 531*38414Smckusick u_long *retxid; 532*38414Smckusick u_long *proc; 533*38414Smckusick register struct ucred *cr; 534*38414Smckusick { 535*38414Smckusick register int i; 536*38414Smckusick register struct mbuf *m; 537*38414Smckusick nfsm_vars; 538*38414Smckusick int len, len2; 539*38414Smckusick 540*38414Smckusick if (error = nfs_udpreceive(so, nam, &mrep)) 541*38414Smckusick return (error); 542*38414Smckusick md = mrep; 543*38414Smckusick dpos = mtod(mrep, caddr_t); 544*38414Smckusick nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED); 545*38414Smckusick *retxid = *p++; 546*38414Smckusick if (*p++ != rpc_call) { 547*38414Smckusick m_freem(mrep); 548*38414Smckusick return (ERPCMISMATCH); 549*38414Smckusick } 550*38414Smckusick if (*p++ != rpc_vers) { 551*38414Smckusick m_freem(mrep); 552*38414Smckusick return (ERPCMISMATCH); 553*38414Smckusick } 554*38414Smckusick if (*p++ != prog) { 555*38414Smckusick m_freem(mrep); 556*38414Smckusick return (EPROGUNAVAIL); 557*38414Smckusick } 558*38414Smckusick if (*p++ != vers) { 559*38414Smckusick m_freem(mrep); 560*38414Smckusick return (EPROGMISMATCH); 561*38414Smckusick } 562*38414Smckusick *proc = fxdr_unsigned(u_long, *p++); 563*38414Smckusick if (*proc == NFSPROC_NULL) { 564*38414Smckusick *mrp = mrep; 565*38414Smckusick return (0); 566*38414Smckusick } 567*38414Smckusick if (*proc > maxproc || *p++ != rpc_auth_unix) { 568*38414Smckusick m_freem(mrep); 569*38414Smckusick return (EPROCUNAVAIL); 570*38414Smckusick } 571*38414Smckusick len = fxdr_unsigned(int, *p++); 572*38414Smckusick len2 = fxdr_unsigned(int, *++p); 573*38414Smckusick nfsm_adv(nfsm_rndup(len2)); 574*38414Smckusick nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED); 575*38414Smckusick cr->cr_uid = fxdr_unsigned(uid_t, *p++); 576*38414Smckusick cr->cr_gid = fxdr_unsigned(gid_t, *p++); 577*38414Smckusick len2 = fxdr_unsigned(int, *p); 578*38414Smckusick if (len2 > 10) { 579*38414Smckusick m_freem(mrep); 580*38414Smckusick return (EBADRPC); 581*38414Smckusick } 582*38414Smckusick nfsm_disect(p, u_long *, (len2+2)*NFSX_UNSIGNED); 583*38414Smckusick for (i = 1; i <= len2; i++) 584*38414Smckusick cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++); 585*38414Smckusick cr->cr_ngroups = len2+1; 586*38414Smckusick /* 587*38414Smckusick * Do we have any use for the verifier. 588*38414Smckusick * According to the "Remote Procedure Call Protocol Spec." it 589*38414Smckusick * should be AUTH_NULL, but some clients make it AUTH_UNIX? 590*38414Smckusick * For now, just skip over it 591*38414Smckusick */ 592*38414Smckusick len2 = fxdr_unsigned(int, *++p); 593*38414Smckusick if (len2 > 0) 594*38414Smckusick nfsm_adv(nfsm_rndup(len2)); 595*38414Smckusick *mrp = mrep; 596*38414Smckusick *mdp = md; 597*38414Smckusick *dposp = dpos; 598*38414Smckusick return (0); 599*38414Smckusick nfsmout: 600*38414Smckusick return (error); 601*38414Smckusick } 602*38414Smckusick 603*38414Smckusick /* 604*38414Smckusick * Generate the rpc reply header 605*38414Smckusick * siz arg. is used to decide if adding a cluster is worthwhile 606*38414Smckusick */ 607*38414Smckusick nfs_rephead(siz, retxid, err, mrq, mbp, bposp) 608*38414Smckusick int siz; 609*38414Smckusick u_long retxid; 610*38414Smckusick int err; 611*38414Smckusick struct mbuf **mrq; 612*38414Smckusick struct mbuf **mbp; 613*38414Smckusick caddr_t *bposp; 614*38414Smckusick { 615*38414Smckusick nfsm_vars; 616*38414Smckusick 617*38414Smckusick NFSMGETHDR(mreq); 618*38414Smckusick mb = mreq; 619*38414Smckusick if ((siz+RPC_REPLYSIZ) > MHLEN) 620*38414Smckusick NFSMCLGET(mreq, M_WAIT); 621*38414Smckusick p = mtod(mreq, u_long *); 622*38414Smckusick mreq->m_len = 6*NFSX_UNSIGNED; 623*38414Smckusick bpos = ((caddr_t)p)+mreq->m_len; 624*38414Smckusick *p++ = retxid; 625*38414Smckusick *p++ = rpc_reply; 626*38414Smckusick if (err == ERPCMISMATCH) { 627*38414Smckusick *p++ = rpc_msgdenied; 628*38414Smckusick *p++ = rpc_mismatch; 629*38414Smckusick *p++ = txdr_unsigned(2); 630*38414Smckusick *p = txdr_unsigned(2); 631*38414Smckusick } else { 632*38414Smckusick *p++ = rpc_msgaccepted; 633*38414Smckusick *p++ = 0; 634*38414Smckusick *p++ = 0; 635*38414Smckusick switch (err) { 636*38414Smckusick case EPROGUNAVAIL: 637*38414Smckusick *p = txdr_unsigned(RPC_PROGUNAVAIL); 638*38414Smckusick break; 639*38414Smckusick case EPROGMISMATCH: 640*38414Smckusick *p = txdr_unsigned(RPC_PROGMISMATCH); 641*38414Smckusick nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); 642*38414Smckusick *p++ = txdr_unsigned(2); 643*38414Smckusick *p = txdr_unsigned(2); /* someday 3 */ 644*38414Smckusick break; 645*38414Smckusick case EPROCUNAVAIL: 646*38414Smckusick *p = txdr_unsigned(RPC_PROCUNAVAIL); 647*38414Smckusick break; 648*38414Smckusick default: 649*38414Smckusick *p = 0; 650*38414Smckusick if (err != VNOVAL) { 651*38414Smckusick nfsm_build(p, u_long *, NFSX_UNSIGNED); 652*38414Smckusick *p = txdr_unsigned(err); 653*38414Smckusick } 654*38414Smckusick break; 655*38414Smckusick }; 656*38414Smckusick } 657*38414Smckusick *mrq = mreq; 658*38414Smckusick *mbp = mb; 659*38414Smckusick *bposp = bpos; 660*38414Smckusick if (err != 0 && err != VNOVAL) 661*38414Smckusick nfsstats.srvrpc_errs++; 662*38414Smckusick return (0); 663*38414Smckusick } 664*38414Smckusick 665*38414Smckusick /* 666*38414Smckusick * Nfs timer routine 667*38414Smckusick * Scan the nfsreq list and retranmit any requests that have timed out 668*38414Smckusick * To avoid retransmission attempts on STREAM sockets (in the future) make 669*38414Smckusick * sure to set the r_retry field to 0. 670*38414Smckusick */ 671*38414Smckusick nfs_timer() 672*38414Smckusick { 673*38414Smckusick register struct nfsreq *rep; 674*38414Smckusick register struct mbuf *m; 675*38414Smckusick register struct socket *so; 676*38414Smckusick int s, len; 677*38414Smckusick 678*38414Smckusick s = splnet(); 679*38414Smckusick rep = nfsreqh.r_next; 680*38414Smckusick while (rep != NULL) { 681*38414Smckusick if (rep->r_timer > 0) 682*38414Smckusick rep->r_timer--; 683*38414Smckusick else if (rep->r_mrep == NULL && rep->r_retry > 0) { 684*38414Smckusick so = rep->r_mntp->nm_so; 685*38414Smckusick if ((so->so_state & SS_CANTSENDMORE) == 0 && 686*38414Smckusick !so->so_error && 687*38414Smckusick sbspace(&so->so_snd) >= rep->r_msiz) { 688*38414Smckusick m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT); 689*38414Smckusick if (m != NULL) { 690*38414Smckusick nfsstats.rpcretries++; 691*38414Smckusick rep->r_timer = rep->r_timeout; 692*38414Smckusick if (rep->r_retry != VNOVAL) 693*38414Smckusick rep->r_retry--; 694*38414Smckusick #ifdef MGETHDR 695*38414Smckusick m->m_pkthdr.len = rep->r_msiz; 696*38414Smckusick #endif 697*38414Smckusick (*so->so_proto->pr_usrreq)(so, PRU_SEND, 698*38414Smckusick m, (caddr_t)0, (struct mbuf *)0, 699*38414Smckusick (struct mbuf *)0); 700*38414Smckusick } 701*38414Smckusick } 702*38414Smckusick } 703*38414Smckusick rep = rep->r_next; 704*38414Smckusick } 705*38414Smckusick splx(s); 706*38414Smckusick timeout(nfs_timer, (caddr_t)0, hz); 707*38414Smckusick } 708*38414Smckusick 709*38414Smckusick /* 710*38414Smckusick * nfs_sbwait() is simply sbwait() but at a negative priority so that it 711*38414Smckusick * can not be interrupted by a signal. 712*38414Smckusick */ 713*38414Smckusick nfs_sbwait(sb) 714*38414Smckusick struct sockbuf *sb; 715*38414Smckusick { 716*38414Smckusick sb->sb_flags |= SB_WAIT; 717*38414Smckusick sleep((caddr_t)&sb->sb_cc, PZERO-1); 718*38414Smckusick } 719