xref: /plan9/sys/src/cmd/unix/9pfreebsd/freebsd-3.2.il-kernel.patch (revision 144145943e440fe30c4e4512a0856f5e3d5ca4be)
1diff -N -c -r /usr/src/sys/9fs/9auth.c ./9fs/9auth.c
2*** /usr/src/sys/9fs/9auth.c	Wed Dec 31 19:00:00 1969
3--- ./9fs/9auth.c	Mon May 22 17:11:29 2000
4***************
5*** 0 ****
6--- 1,238 ----
7+ #include <sys/param.h>
8+ #include <sys/systm.h>
9+ #include <sys/socket.h>
10+ #include <sys/socketvar.h>
11+ #include <sys/protosw.h>
12+ #include <sys/malloc.h>
13+ #include <sys/mbuf.h>
14+ #include <sys/uio.h>
15+
16+ #include <9fs/9p.h>
17+ #include <9fs/9auth.h>
18+
19+ #define	N2HCHAR(x)		x = *p++
20+ #define	N2HSHORT(x)	x = (p[0] | (p[1]<<8)); p += 2
21+ #define	N2HLONG(x)		x = (p[0] | (p[1]<<8) |\
22+ 				(p[2]<<16) | (p[3]<<24)); p += 4
23+ #define	N2HQUAD(x)	x = (u_int64_t)(p[0] | (p[1]<<8) |\
24+ 					(p[2]<<16) | (p[3]<<24)) |\
25+ 				((u_int64_t)(p[4] | (p[5]<<8) |\
26+ 					(p[6]<<16) | (p[7]<<24)) << 32); p += 8
27+ #define	N2HSTRING(x,n)	bcopy(p, x, n); p += n
28+
29+ #define	H2NCHAR(x)	*p++ = x
30+ #define	H2NSHORT(x)	p[0]=x; p[1]=x>>8; p += 2
31+ #define	H2NLONG(x)		p[0]=x; p[1]=x>>8; p[2]=x>>16; p[3]=x>>24; p += 4
32+ #define	H2NQUAD(x)	p[0]=x;	p[1]=x>>8;\
33+ 			p[2]=x>>16;	p[3]=x>>24;\
34+ 			p[4]=x>>32;	p[5]=x>>40;\
35+ 			p[6]=x>>48;	p[7]=x>>56;\
36+ 			p += 8
37+ #define	H2NSTRING(x,n)	bcopy(x, p, n); p += n
38+
39+ static int u9auth_send __P((struct socket *so, struct mbuf *top, struct proc *p));
40+ static int u9auth_recv __P((struct socket *so, struct mbuf **mp, struct proc *p));
41+
42+ static int u9auth_count = 0;
43+
44+ static int u9auth_tr2m(struct u9auth_ticketreq *f, char *ap)
45+ {
46+ 	int n;
47+ 	u_char *p;
48+
49+ 	p = (u_char*)ap;
50+         H2NCHAR(f->type);
51+ 	H2NSTRING(f->authid, U9FS_NAMELEN);
52+ 	H2NSTRING(f->authdom, U9FS_DOMLEN);
53+ 	H2NSTRING(f->chal, U9FS_CHALLEN);
54+ 	H2NSTRING(f->hostid, U9FS_NAMELEN);
55+ 	H2NSTRING(f->uid, U9FS_NAMELEN);
56+ 	n = p - (u_char*)ap;
57+ 	return n;
58+ }
59+
60+ static struct mbuf * u9auth_m_tr2m(struct u9auth_ticketreq * tktq)
61+ {
62+   register struct mbuf *m;
63+   char * ap;
64+   int sz = 141;
65+
66+   MGETHDR(m, M_WAIT, MT_DATA);
67+   if( sz > MHLEN )
68+     MCLGET(m, M_WAIT);
69+   m->m_len = 0;
70+
71+   if ( M_TRAILINGSPACE(m) < sz )
72+     panic("u9auth_m_tr2m");
73+
74+   ap = mtod(m, char *);
75+   m->m_len = u9auth_tr2m(tktq, ap);
76+   m->m_pkthdr.len = m->m_len;
77+
78+   return (m);
79+ }
80+
81+ static int
82+ u9auth_send(so, top, p)
83+ 	register struct socket *so;
84+ 	register struct mbuf *top;
85+ 	register struct proc *p;
86+
87+ {
88+   int error, soflags, flags;
89+
90+   soflags = so->so_proto->pr_flags;
91+   if (so->so_type == SOCK_SEQPACKET)
92+     flags = MSG_EOR;
93+   else
94+     flags = 0;
95+
96+   error = so->so_proto->pr_usrreqs->pru_sosend(so, 0, 0, top, 0, flags, p);
97+
98+   return (error);
99+ }
100+
101+ static int
102+ u9auth_recv(so, mp, p)
103+      register struct socket * so;
104+      register struct mbuf **mp;
105+      struct proc *p;
106+ {
107+   struct uio auio;
108+   u_int32_t len;
109+   int error = 0, sotype, rcvflg;
110+
111+   *mp = 0;
112+   sotype = so->so_type;
113+
114+   /*
115+    * For reliable protocols, lock against other senders/receivers
116+    * in case a reconnect is necessary.
117+    * For SOCK_STREAM, first get the Record Mark to find out how much
118+    * more there is to get.
119+    * We must lock the socket against other receivers
120+    * until we have an entire rpc request/reply.
121+    */
122+   if (sotype == SOCK_SEQPACKET ) {
123+     if( (so->so_state & SS_ISCONNECTED) == 0 )
124+       return (EACCES);
125+ 		auio.uio_resid = len = 1000000;
126+ 		auio.uio_procp = p;
127+ 		do {
128+ 			rcvflg = 0;
129+ 			error =  so->so_proto->pr_usrreqs->pru_soreceive
130+ 				(so, 0, &auio, mp,
131+ 				(struct mbuf **)0, &rcvflg);
132+ 		} while (error == EWOULDBLOCK);
133+ 		len -= auio.uio_resid;
134+   }
135+   if (error) {
136+     m_freem(*mp);
137+     *mp = 0;
138+   }
139+   return (error);
140+ }
141+
142+ static void
143+ u9auth_m2t(char *ap, struct u9auth_ticket *f, char *key)
144+ {
145+ 	u_char *p;
146+
147+ 	if(key)
148+ 		decrypt9(key, ap, U9AUTH_TICKETLEN);
149+ 	p = (u_char*)ap;
150+ 	N2HCHAR(f->num);
151+ 	N2HSTRING(f->chal, U9FS_CHALLEN);
152+ 	N2HSTRING(f->cuid, U9FS_NAMELEN);
153+ 	f->cuid[U9FS_NAMELEN-1] = 0;
154+ 	N2HSTRING(f->suid, U9FS_NAMELEN);
155+ 	f->suid[U9FS_NAMELEN-1] = 0;
156+ 	N2HSTRING(f->key, U9AUTH_DESKEYLEN);
157+ };
158+
159+ static int
160+ u9auth_a2m(struct u9auth_authenticator *f, char *ap, char *key)
161+ {
162+ 	int n;
163+ 	u_char *p;
164+
165+ 	p = (u_char*)ap;
166+ 	H2NCHAR(f->num);
167+ 	H2NSTRING(f->chal, U9FS_CHALLEN);
168+ 	H2NLONG(f->id);
169+ 	n = p - (u_char*)ap;
170+ 	if(key)
171+ 		encrypt9(key, ap, n);
172+ 	return n;
173+ }
174+
175+ void u9auth_genchal (char * chal)
176+ {
177+   u_long * lp = (u_long *)chal;
178+
179+   *lp++ = random();
180+   *lp = random();
181+ }
182+
183+ int u9auth_gettickets (struct socket * so, struct u9fsreq * rep,
184+ 			   char * user, char * ckey, char * ts, char * authc,
185+ 		       struct proc *p)
186+ {
187+   char * cp;
188+   struct u9auth_ticketreq tktq;
189+   struct u9auth_ticket tc;
190+   struct u9auth_authenticator auth;
191+   struct mbuf * m;
192+   int error, len;
193+
194+   bzero(&tktq, sizeof(tktq));
195+   tktq.type = AuthTreq;
196+   bcopy(rep->r_authid, tktq.authid, U9FS_NAMELEN);
197+   bcopy(rep->r_authdom, tktq.authdom, U9FS_DOMLEN);
198+   bcopy(rep->r_chal, tktq.chal, U9FS_CHALLEN);
199+   strncpy(tktq.hostid, user, U9FS_NAMELEN);
200+   strncpy(tktq.uid, user, U9FS_NAMELEN);
201+
202+   m = u9auth_m_tr2m(&tktq);
203+   error = u9auth_send(so, m, p);
204+   if( error )
205+     goto bad;
206+   error = u9auth_recv(so, &m, p);
207+   if( error )
208+     goto bad;
209+
210+   len = U9AUTH_TICKETLEN+1;
211+   if( m->m_len < len && (m = m_pullup(m, len)) == 0 )
212+     goto bad;
213+
214+   cp = mtod(m, char *);
215+   switch( cp[0] ) {
216+   case AuthOK:
217+     u9auth_m2t(&cp[1], & tc, ckey);
218+     bzero(&auth, sizeof(auth));
219+     auth.num = AuthAc;
220+     bcopy(tc.chal, auth.chal, sizeof(auth.chal));
221+     auth.id = u9auth_count++;
222+
223+     m->m_len -= len;
224+     m->m_data += len;
225+
226+     len = U9AUTH_TICKETLEN;
227+     if( m->m_len < len && (m = m_pullup(m, len)) == 0 )
228+       goto bad;
229+     cp = mtod(m, char *);
230+     bcopy(cp, ts, len);
231+     break;
232+   case AuthErr:
233+   case AuthOKvar:
234+     m_freem(m);
235+     goto bad;
236+     break;
237+   }
238+
239+   u9auth_a2m(&auth, authc, tc.key);
240+   return 0;
241+  bad:
242+   return error;
243+ }
244+
245diff -N -c -r /usr/src/sys/9fs/9auth.h ./9fs/9auth.h
246*** /usr/src/sys/9fs/9auth.h	Wed Dec 31 19:00:00 1969
247--- ./9fs/9auth.h	Thu Nov 11 15:00:29 1999
248***************
249*** 0 ****
250--- 1,129 ----
251+ #ifndef P9AUTH_H
252+ #define P9AUTH_H
253+
254+ #define U9AUTH_DOMLEN		48		/* length of an authentication domain name */
255+ #define U9AUTH_DESKEYLEN	7		/* length of a des key for encrypt/decrypt */
256+ #define U9AUTH_CHALLEN	8		/* length of a challenge */
257+ #define U9AUTH_NETCHLEN	16		/* max network challenge length	*/
258+ #define U9AUTH_CONFIGLEN	14
259+ #define U9AUTH_SECRETLEN	32		/* max length of a secret */
260+ #define U9AUTH_APOPCHLEN	256
261+ #define U9AUTH_MD5LEN		16
262+ #define U9AUTH_KEYDBOFF	8		/* length of random data at the start of key file */
263+ #define U9AUTH_OKEYDBLEN	U9FSNAMELEN+U9AUTH_DESKEYLEN+4+2,	/* length of an entry in old key file */
264+ #define U9AUTH_KEYDBLEN	OKEYDBLENSECRETLEN,	/* length of an entry in key file */
265+
266+ /* encryption numberings (anti-replay) */
267+ enum
268+ {
269+ 	AuthTreq=1,	/* ticket request */
270+ 	AuthChal=2,	/* challenge box request */
271+ 	AuthPass=3,	/* change password */
272+ 	AuthOK=4,	/* fixed length reply follows */
273+ 	AuthErr=5,	/* error follows */
274+ 	AuthMod=6,	/* modify user */
275+ 	AuthApop=7,	/* apop authentication for pop3 */
276+ 	AuthOKvar=9,	/* variable length reply follows */
277+ 	AuthChap=10,	/* chap authentication for ppp */
278+ 	AuthMSchap=11,	/* MS chap authentication for ppp */
279+
280+
281+ 	AuthTs=64,	/* ticket encrypted with server's key */
282+ 	AuthTc,		/* ticket encrypted with client's key */
283+ 	AuthAs,		/* server generated authenticator */
284+ 	AuthAc,		/* client generated authenticator */
285+ 	AuthTp,		/* ticket encrypted with clien's key for password change */
286+ };
287+
288+ struct u9auth_ticketreq
289+ {
290+ 	char	type;
291+ 	char	authid[U9FS_NAMELEN];	/* server's encryption id */
292+ 	char	authdom[U9AUTH_DOMLEN];	/* server's authentication domain */
293+ 	char	chal[U9AUTH_CHALLEN];		/* challenge from server */
294+ 	char	hostid[U9FS_NAMELEN];	/* host's encryption id */
295+ 	char	uid[U9FS_NAMELEN];		/* uid of requesting user on host */
296+ };
297+ #define	U9AUTH_TICKREQLEN	(3*U9FS_NAMELEN+U9AUTH_CHALLEN+U9AUTH_DOMLEN+1)
298+
299+ struct u9auth_ticket
300+ {
301+ 	char	num;			/* replay protection */
302+ 	char	chal[U9AUTH_CHALLEN];		/* server challenge */
303+ 	char	cuid[U9FS_NAMELEN];		/* uid on client */
304+ 	char	suid[U9FS_NAMELEN];		/* uid on server */
305+ 	char	key[U9AUTH_DESKEYLEN];		/* nonce DES key */
306+ };
307+ #define	U9AUTH_TICKETLEN	(U9AUTH_CHALLEN+2*U9FS_NAMELEN+U9AUTH_DESKEYLEN+1)
308+
309+ struct u9auth_authenticator
310+ {
311+ 	char	num;			/* replay protection */
312+ 	char	chal[U9AUTH_CHALLEN];
313+ 	u_long	id;			/* authenticator id, ++'d with each auth */
314+ };
315+ #define	U9AUTH_AUTHENTLEN	(U9AUTH_CHALLEN+4+1)
316+
317+ struct u9auth_passwordreq
318+ {
319+ 	char	num;
320+ 	char	old[U9FS_NAMELEN];
321+ 	char	new[U9FS_NAMELEN];
322+ 	char	changesecret;
323+ 	char	secret[U9AUTH_SECRETLEN];	/* new secret */
324+ };
325+ #define	U9AUTH_PASSREQLEN	(2*U9FS_NAMELEN+1+1+U9AUTH_SECRETLEN)
326+
327+ struct u9auth_nvrsafe
328+ {
329+ 	char	machkey[U9AUTH_DESKEYLEN];
330+ 	u_char	machsum;
331+ 	char	authkey[U9AUTH_DESKEYLEN];
332+ 	u_char	authsum;
333+ 	char	config[U9AUTH_CONFIGLEN];
334+ 	u_char	configsum;
335+ 	char	authid[U9FS_NAMELEN];
336+ 	u_char	authidsum;
337+ 	char	authdom[U9AUTH_DOMLEN];
338+ 	u_char	authdomsum;
339+ };
340+
341+ struct u9auth_chalstate
342+ {
343+ 	int	afd;			/* /dev/authenticate */
344+ 	int	asfd;			/* authdial() */
345+ 	char	chal[U9AUTH_NETCHLEN];		/* challenge/response */
346+ };
347+
348+ struct u9auth_apopchalstate
349+ {
350+ 	int	afd;			/* /dev/authenticate */
351+ 	int	asfd;			/* authdial() */
352+ 	char	chal[U9AUTH_APOPCHLEN];	/* challenge/response */
353+ };
354+
355+ struct	u9auth_chapreply
356+ {
357+ 	u_char	id;
358+ 	char	uid[U9FS_NAMELEN];
359+ 	char	resp[U9AUTH_MD5LEN];
360+ };
361+
362+ struct	u9auth_mSchapreply
363+ {
364+ 	char	uid[U9FS_NAMELEN];
365+ 	char	LMresp[24];		/* Lan Manager response */
366+ 	char	NTresp[24];		/* NT response */
367+ };
368+
369+ #ifdef KERNEL
370+ void u9auth_genchal __P((char *));
371+ int  u9auth_gettickets __P((struct socket * so, struct u9fsreq * rep,
372+ 			   char * user, char * ckey, char * ts, char * authc,
373+ 			    struct proc * p));
374+ int encrypt9 __P((void *key, void * vbuf, int n));
375+ int decrypt9 __P((void *key, void * vbuf, int n));
376+
377+ #endif
378+
379+ #endif
380diff -N -c -r /usr/src/sys/9fs/9crypt.c ./9fs/9crypt.c
381*** /usr/src/sys/9fs/9crypt.c	Wed Dec 31 19:00:00 1969
382--- ./9fs/9crypt.c	Thu Nov 11 12:23:02 1999
383***************
384*** 0 ****
385--- 1,416 ----
386+ /*
387+  *	Data Encryption Standard
388+  *	D.P.Mitchell  83/06/08.
389+  *
390+  *	block_cipher(key, block, decrypting)
391+  */
392+ #include <sys/param.h>
393+ #include <sys/systm.h>
394+ #include <sys/socket.h>
395+ #include <sys/socketvar.h>
396+
397+ typedef unsigned char uchar;
398+ typedef unsigned long ulong;
399+ #define NAMELEN 28      /* length of path element, including '\0' */
400+ #include <9fs/9p.h>
401+ #include <9fs/9auth.h>
402+
403+ static	long	ip_low(char [8]);
404+ static	long	ip_high(char [8]);
405+ static	void	fp(long, long, char[8]);
406+ static	void	key_setup(char[U9AUTH_DESKEYLEN], char[128]);
407+ static	void	block_cipher(char[128], char[8], int);
408+
409+ /*
410+  * destructively encrypt the buffer, which
411+  * must be at least 8 characters long.
412+  */
413+ int
414+ encrypt9(void *key, void *vbuf, int n)
415+ {
416+ 	char ekey[128], *buf;
417+ 	int i, r;
418+
419+ 	if(n < 8)
420+ 		return 0;
421+ 	key_setup(key, ekey);
422+ 	buf = vbuf;
423+ 	n--;
424+ 	r = n % 7;
425+ 	n /= 7;
426+ 	for(i = 0; i < n; i++){
427+ 		block_cipher(ekey, buf, 0);
428+ 		buf += 7;
429+ 	}
430+ 	if(r)
431+ 		block_cipher(ekey, buf - 7 + r, 0);
432+ 	return 1;
433+ }
434+
435+ /*
436+  * destructively decrypt the buffer, which
437+  * must be at least 8 characters long.
438+  */
439+ int
440+ decrypt9(void *key, void *vbuf, int n)
441+ {
442+ 	char ekey[128], *buf;
443+ 	int i, r;
444+
445+ 	if(n < 8)
446+ 		return 0;
447+ 	key_setup(key, ekey);
448+ 	buf = vbuf;
449+ 	n--;
450+ 	r = n % 7;
451+ 	n /= 7;
452+ 	buf += n * 7;
453+ 	if(r)
454+ 		block_cipher(ekey, buf - 7 + r, 1);
455+ 	for(i = 0; i < n; i++){
456+ 		buf -= 7;
457+ 		block_cipher(ekey, buf, 1);
458+ 	}
459+ 	return 1;
460+ }
461+
462+ /*
463+  *	Tables for Combined S and P Boxes
464+  */
465+
466+ static long  s0p[] = {
467+ 0x00410100,0x00010000,0x40400000,0x40410100,0x00400000,0x40010100,0x40010000,0x40400000,
468+ 0x40010100,0x00410100,0x00410000,0x40000100,0x40400100,0x00400000,0x00000000,0x40010000,
469+ 0x00010000,0x40000000,0x00400100,0x00010100,0x40410100,0x00410000,0x40000100,0x00400100,
470+ 0x40000000,0x00000100,0x00010100,0x40410000,0x00000100,0x40400100,0x40410000,0x00000000,
471+ 0x00000000,0x40410100,0x00400100,0x40010000,0x00410100,0x00010000,0x40000100,0x00400100,
472+ 0x40410000,0x00000100,0x00010100,0x40400000,0x40010100,0x40000000,0x40400000,0x00410000,
473+ 0x40410100,0x00010100,0x00410000,0x40400100,0x00400000,0x40000100,0x40010000,0x00000000,
474+ 0x00010000,0x00400000,0x40400100,0x00410100,0x40000000,0x40410000,0x00000100,0x40010100,
475+ };
476+
477+ static long  s1p[] = {
478+ 0x08021002,0x00000000,0x00021000,0x08020000,0x08000002,0x00001002,0x08001000,0x00021000,
479+ 0x00001000,0x08020002,0x00000002,0x08001000,0x00020002,0x08021000,0x08020000,0x00000002,
480+ 0x00020000,0x08001002,0x08020002,0x00001000,0x00021002,0x08000000,0x00000000,0x00020002,
481+ 0x08001002,0x00021002,0x08021000,0x08000002,0x08000000,0x00020000,0x00001002,0x08021002,
482+ 0x00020002,0x08021000,0x08001000,0x00021002,0x08021002,0x00020002,0x08000002,0x00000000,
483+ 0x08000000,0x00001002,0x00020000,0x08020002,0x00001000,0x08000000,0x00021002,0x08001002,
484+ 0x08021000,0x00001000,0x00000000,0x08000002,0x00000002,0x08021002,0x00021000,0x08020000,
485+ 0x08020002,0x00020000,0x00001002,0x08001000,0x08001002,0x00000002,0x08020000,0x00021000,
486+ };
487+
488+ static long  s2p[] = {
489+ 0x20800000,0x00808020,0x00000020,0x20800020,0x20008000,0x00800000,0x20800020,0x00008020,
490+ 0x00800020,0x00008000,0x00808000,0x20000000,0x20808020,0x20000020,0x20000000,0x20808000,
491+ 0x00000000,0x20008000,0x00808020,0x00000020,0x20000020,0x20808020,0x00008000,0x20800000,
492+ 0x20808000,0x00800020,0x20008020,0x00808000,0x00008020,0x00000000,0x00800000,0x20008020,
493+ 0x00808020,0x00000020,0x20000000,0x00008000,0x20000020,0x20008000,0x00808000,0x20800020,
494+ 0x00000000,0x00808020,0x00008020,0x20808000,0x20008000,0x00800000,0x20808020,0x20000000,
495+ 0x20008020,0x20800000,0x00800000,0x20808020,0x00008000,0x00800020,0x20800020,0x00008020,
496+ 0x00800020,0x00000000,0x20808000,0x20000020,0x20800000,0x20008020,0x00000020,0x00808000,
497+ };
498+
499+ static long  s3p[] = {
500+ 0x00080201,0x02000200,0x00000001,0x02080201,0x00000000,0x02080000,0x02000201,0x00080001,
501+ 0x02080200,0x02000001,0x02000000,0x00000201,0x02000001,0x00080201,0x00080000,0x02000000,
502+ 0x02080001,0x00080200,0x00000200,0x00000001,0x00080200,0x02000201,0x02080000,0x00000200,
503+ 0x00000201,0x00000000,0x00080001,0x02080200,0x02000200,0x02080001,0x02080201,0x00080000,
504+ 0x02080001,0x00000201,0x00080000,0x02000001,0x00080200,0x02000200,0x00000001,0x02080000,
505+ 0x02000201,0x00000000,0x00000200,0x00080001,0x00000000,0x02080001,0x02080200,0x00000200,
506+ 0x02000000,0x02080201,0x00080201,0x00080000,0x02080201,0x00000001,0x02000200,0x00080201,
507+ 0x00080001,0x00080200,0x02080000,0x02000201,0x00000201,0x02000000,0x02000001,0x02080200,
508+ };
509+
510+ static long  s4p[] = {
511+ 0x01000000,0x00002000,0x00000080,0x01002084,0x01002004,0x01000080,0x00002084,0x01002000,
512+ 0x00002000,0x00000004,0x01000004,0x00002080,0x01000084,0x01002004,0x01002080,0x00000000,
513+ 0x00002080,0x01000000,0x00002004,0x00000084,0x01000080,0x00002084,0x00000000,0x01000004,
514+ 0x00000004,0x01000084,0x01002084,0x00002004,0x01002000,0x00000080,0x00000084,0x01002080,
515+ 0x01002080,0x01000084,0x00002004,0x01002000,0x00002000,0x00000004,0x01000004,0x01000080,
516+ 0x01000000,0x00002080,0x01002084,0x00000000,0x00002084,0x01000000,0x00000080,0x00002004,
517+ 0x01000084,0x00000080,0x00000000,0x01002084,0x01002004,0x01002080,0x00000084,0x00002000,
518+ 0x00002080,0x01002004,0x01000080,0x00000084,0x00000004,0x00002084,0x01002000,0x01000004,
519+ };
520+
521+ static long  s5p[] = {
522+ 0x10000008,0x00040008,0x00000000,0x10040400,0x00040008,0x00000400,0x10000408,0x00040000,
523+ 0x00000408,0x10040408,0x00040400,0x10000000,0x10000400,0x10000008,0x10040000,0x00040408,
524+ 0x00040000,0x10000408,0x10040008,0x00000000,0x00000400,0x00000008,0x10040400,0x10040008,
525+ 0x10040408,0x10040000,0x10000000,0x00000408,0x00000008,0x00040400,0x00040408,0x10000400,
526+ 0x00000408,0x10000000,0x10000400,0x00040408,0x10040400,0x00040008,0x00000000,0x10000400,
527+ 0x10000000,0x00000400,0x10040008,0x00040000,0x00040008,0x10040408,0x00040400,0x00000008,
528+ 0x10040408,0x00040400,0x00040000,0x10000408,0x10000008,0x10040000,0x00040408,0x00000000,
529+ 0x00000400,0x10000008,0x10000408,0x10040400,0x10040000,0x00000408,0x00000008,0x10040008,
530+ };
531+
532+ static long  s6p[] = {
533+ 0x00000800,0x00000040,0x00200040,0x80200000,0x80200840,0x80000800,0x00000840,0x00000000,
534+ 0x00200000,0x80200040,0x80000040,0x00200800,0x80000000,0x00200840,0x00200800,0x80000040,
535+ 0x80200040,0x00000800,0x80000800,0x80200840,0x00000000,0x00200040,0x80200000,0x00000840,
536+ 0x80200800,0x80000840,0x00200840,0x80000000,0x80000840,0x80200800,0x00000040,0x00200000,
537+ 0x80000840,0x00200800,0x80200800,0x80000040,0x00000800,0x00000040,0x00200000,0x80200800,
538+ 0x80200040,0x80000840,0x00000840,0x00000000,0x00000040,0x80200000,0x80000000,0x00200040,
539+ 0x00000000,0x80200040,0x00200040,0x00000840,0x80000040,0x00000800,0x80200840,0x00200000,
540+ 0x00200840,0x80000000,0x80000800,0x80200840,0x80200000,0x00200840,0x00200800,0x80000800,
541+ };
542+
543+ static long  s7p[] = {
544+ 0x04100010,0x04104000,0x00004010,0x00000000,0x04004000,0x00100010,0x04100000,0x04104010,
545+ 0x00000010,0x04000000,0x00104000,0x00004010,0x00104010,0x04004010,0x04000010,0x04100000,
546+ 0x00004000,0x00104010,0x00100010,0x04004000,0x04104010,0x04000010,0x00000000,0x00104000,
547+ 0x04000000,0x00100000,0x04004010,0x04100010,0x00100000,0x00004000,0x04104000,0x00000010,
548+ 0x00100000,0x00004000,0x04000010,0x04104010,0x00004010,0x04000000,0x00000000,0x00104000,
549+ 0x04100010,0x04004010,0x04004000,0x00100010,0x04104000,0x00000010,0x00100010,0x04004000,
550+ 0x04104010,0x00100000,0x04100000,0x04000010,0x00104000,0x00004010,0x04004010,0x04100000,
551+ 0x00000010,0x04104000,0x00104010,0x00000000,0x04000000,0x04100010,0x00004000,0x00104010,
552+ };
553+
554+ /*
555+  *	DES electronic codebook encryption of one block
556+  */
557+ static void
558+ block_cipher(char expanded_key[128], char text[8], int decrypting)
559+ {
560+ 	char *key;
561+ 	long crypto, temp, right, left;
562+ 	int i, key_offset;
563+
564+ 	key = expanded_key;
565+ 	left = ip_low(text);
566+ 	right = ip_high(text);
567+ 	if (decrypting) {
568+ 		key_offset = 16;
569+ 		key = key + 128 - 8;
570+ 	} else
571+ 		key_offset = 0;
572+ 	for (i = 0; i < 16; i++) {
573+ 		temp = (right << 1) | ((right >> 31) & 1);
574+ 		crypto  = s0p[(temp         & 0x3f) ^ *key++];
575+ 		crypto |= s1p[((temp >>  4) & 0x3f) ^ *key++];
576+ 		crypto |= s2p[((temp >>  8) & 0x3f) ^ *key++];
577+ 		crypto |= s3p[((temp >> 12) & 0x3f) ^ *key++];
578+ 		crypto |= s4p[((temp >> 16) & 0x3f) ^ *key++];
579+ 		crypto |= s5p[((temp >> 20) & 0x3f) ^ *key++];
580+ 		crypto |= s6p[((temp >> 24) & 0x3f) ^ *key++];
581+ 		temp = ((right & 1) << 5) | ((right >> 27) & 0x1f);
582+ 		crypto |= s7p[temp ^ *key++];
583+ 		temp = left;
584+ 		left = right;
585+ 		right = temp ^ crypto;
586+ 		key -= key_offset;
587+ 	}
588+ 	/*
589+ 	 *	standard final permutation (IPI)
590+ 	 *	left and right are reversed here
591+ 	 */
592+ 	fp(right, left, text);
593+ }
594+
595+ /*
596+  *	Initial Permutation
597+  */
598+ static long iptab[] = {
599+ 	0x00000000, 0x00008000, 0x00000000, 0x00008000,
600+ 	0x00000080, 0x00008080, 0x00000080, 0x00008080
601+ };
602+
603+ static long
604+ ip_low(char block[8])
605+ {
606+ 	int i;
607+ 	long l;
608+
609+ 	l = 0;
610+ 	for(i = 0; i < 8; i++){
611+ 		l |= iptab[(block[i] >> 4) & 7] >> i;
612+ 		l |= iptab[block[i] & 7] << (16 - i);
613+ 	}
614+ 	return l;
615+ }
616+
617+ static long
618+ ip_high(char block[8])
619+ {
620+ 	int i;
621+ 	long l;
622+
623+ 	l = 0;
624+ 	for(i = 0; i < 8; i++){
625+ 		l |= iptab[(block[i] >> 5) & 7] >> i;
626+ 		l |= iptab[(block[i] >> 1) & 7] << (16 - i);
627+ 	}
628+ 	return l;
629+ }
630+
631+ /*
632+  *	Final Permutation
633+  */
634+ static unsigned long	fptab[] = {
635+ 0x00000000,0x80000000,0x00800000,0x80800000,0x00008000,0x80008000,0x00808000,0x80808000,
636+ 0x00000080,0x80000080,0x00800080,0x80800080,0x00008080,0x80008080,0x00808080,0x80808080,
637+ };
638+
639+ static void
640+ fp(long left, long right, char text[8])
641+ {
642+ 	unsigned long ta[2], t, v[2];
643+ 	int i, j, sh;
644+
645+ 	ta[0] = right;
646+ 	ta[1] = left;
647+ 	v[0] = v[1] = 0;
648+ 	for(i = 0; i < 2; i++){
649+ 		t = ta[i];
650+ 		sh = i;
651+ 		for(j = 0; j < 4; j++){
652+ 			v[1] |= fptab[t & 0xf] >> sh;
653+ 			t >>= 4;
654+ 			v[0] |= fptab[t & 0xf] >> sh;
655+ 			t >>= 4;
656+ 			sh += 2;
657+ 		}
658+ 	}
659+ 	for(i = 0; i < 2; i++)
660+ 		for(j = 0; j < 4; j++){
661+ 			*text++ = v[i];
662+ 			v[i] >>= 8;
663+ 		}
664+ }
665+
666+ /*
667+  *	Key set-up
668+  */
669+ static uchar keyexpand[][15][2] = {
670+ 	{   3,  2,   9,  8,  18,  8,  27, 32,  33,  2,  42, 16,  48,  8,  65, 16,
671+ 	   74,  2,  80,  2,  89,  4,  99, 16, 104,  4, 122, 32,   0,  0, },
672+ 	{   1,  4,   8,  1,  18,  4,  25, 32,  34, 32,  41,  8,  50,  8,  59, 32,
673+ 	   64, 16,  75,  4,  90,  1,  97, 16, 106,  2, 112,  2, 123,  1, },
674+ 	{   2,  1,  19,  8,  35,  1,  40,  1,  50,  4,  57, 32,  75,  2,  80, 32,
675+ 	   89,  1,  96, 16, 107,  4, 120,  8,   0,  0,   0,  0,   0,  0, },
676+ 	{   4, 32,  20,  2,  31,  4,  37, 32,  47,  1,  54,  1,  63,  2,  68,  1,
677+ 	   78,  4,  84,  8, 101, 16, 108,  4, 119, 16, 126,  8,   0,  0, },
678+ 	{   5,  4,  15,  4,  21, 32,  31,  1,  38,  1,  47,  2,  53,  2,  68,  8,
679+ 	   85, 16,  92,  4, 103, 16, 108, 32, 118, 32, 124,  2,   0,  0, },
680+ 	{  15,  2,  21,  2,  39,  8,  46, 16,  55, 32,  61,  1,  71, 16,  76, 32,
681+ 	   86, 32,  93,  4, 102,  2, 108, 16, 117,  8, 126,  1,   0,  0, },
682+ 	{  14, 16,  23, 32,  29,  1,  38,  8,  52,  2,  63,  4,  70,  2,  76, 16,
683+ 	   85,  8, 100,  1, 110,  4, 116,  8, 127,  8,   0,  0,   0,  0, },
684+ 	{   1,  8,   8, 32,  17,  1,  24, 16,  35,  4,  50,  1,  57, 16,  67,  8,
685+ 	   83,  1,  88,  1,  98,  4, 105, 32, 114, 32, 123,  2,   0,  0, },
686+ 	{   0,  1,  11, 16,  16,  4,  35,  2,  40, 32,  49,  1,  56, 16,  65,  2,
687+ 	   74, 16,  80,  8,  99,  8, 115,  1, 121,  4,   0,  0,   0,  0, },
688+ 	{   9, 16,  18,  2,  24,  2,  33,  4,  43, 16,  48,  4,  66, 32,  73,  8,
689+ 	   82,  8,  91, 32,  97,  2, 106, 16, 112,  8, 122,  1,   0,  0, },
690+ 	{  14, 32,  21,  4,  30,  2,  36, 16,  45,  8,  60,  1,  69,  2,  87,  8,
691+ 	   94, 16, 103, 32, 109,  1, 118,  8, 124, 32,   0,  0,   0,  0, },
692+ 	{   7,  4,  14,  2,  20, 16,  29,  8,  44,  1,  54,  4,  60,  8,  71,  8,
693+ 	   78, 16,  87, 32,  93,  1, 102,  8, 116,  2, 125,  4,   0,  0, },
694+ 	{   7,  2,  12,  1,  22,  4,  28,  8,  45, 16,  52,  4,  63, 16,  70,  8,
695+ 	   84,  2,  95,  4, 101, 32, 111,  1, 118,  1,   0,  0,   0,  0, },
696+ 	{   6, 16,  13, 16,  20,  4,  31, 16,  36, 32,  46, 32,  53,  4,  62,  2,
697+ 	   69, 32,  79,  1,  86,  1,  95,  2, 101,  2, 119,  8,   0,  0, },
698+ 	{   0, 32,  10,  8,  19, 32,  25,  2,  34, 16,  40,  8,  59,  8,  66,  2,
699+ 	   72,  2,  81,  4,  91, 16,  96,  4, 115,  2, 121,  8,   0,  0, },
700+ 	{   3, 16,  10,  4,  17, 32,  26, 32,  33,  8,  42,  8,  51, 32,  57,  2,
701+ 	   67,  4,  82,  1,  89, 16,  98,  2, 104,  2, 113,  4, 120,  1, },
702+ 	{   1, 16,  11,  8,  27,  1,  32,  1,  42,  4,  49, 32,  58, 32,  67,  2,
703+ 	   72, 32,  81,  1,  88, 16,  99,  4, 114,  1,   0,  0,   0,  0, },
704+ 	{   6, 32,  12,  2,  23,  4,  29, 32,  39,  1,  46,  1,  55,  2,  61,  2,
705+ 	   70,  4,  76,  8,  93, 16, 100,  4, 111, 16, 116, 32,   0,  0, },
706+ 	{   6,  2,  13, 32,  23,  1,  30,  1,  39,  2,  45,  2,  63,  8,  77, 16,
707+ 	   84,  4,  95, 16, 100, 32, 110, 32, 117,  4, 127,  4,   0,  0, },
708+ 	{   4,  1,  13,  2,  31,  8,  38, 16,  47, 32,  53,  1,  62,  8,  68, 32,
709+ 	   78, 32,  85,  4,  94,  2, 100, 16, 109,  8, 127,  2,   0,  0, },
710+ 	{   5, 16,  15, 32,  21,  1,  30,  8,  44,  2,  55,  4,  61, 32,  68, 16,
711+ 	   77,  8,  92,  1, 102,  4, 108,  8, 126, 16,   0,  0,   0,  0, },
712+ 	{   2,  8,   9,  1,  16, 16,  27,  4,  42,  1,  49, 16,  58,  2,  75,  1,
713+ 	   80,  1,  90,  4,  97, 32, 106, 32, 113,  8, 120, 32,   0,  0, },
714+ 	{   2,  4,   8,  4,  27,  2,  32, 32,  41,  1,  48, 16,  59,  4,  66, 16,
715+ 	   72,  8,  91,  8, 107,  1, 112,  1, 123, 16,   0,  0,   0,  0, },
716+ 	{   3,  8,  10,  2,  16,  2,  25,  4,  35, 16,  40,  4,  59,  2,  65,  8,
717+ 	   74,  8,  83, 32,  89,  2,  98, 16, 104,  8, 121, 16,   0,  0, },
718+ 	{   4,  2,  13,  4,  22,  2,  28, 16,  37,  8,  52,  1,  62,  4,  79,  8,
719+ 	   86, 16,  95, 32, 101,  1, 110,  8, 126, 32,   0,  0,   0,  0, },
720+ 	{   5, 32,  12, 16,  21,  8,  36,  1,  46,  4,  52,  8,  70, 16,  79, 32,
721+ 	   85,  1,  94,  8, 108,  2, 119,  4, 126,  2,   0,  0,   0,  0, },
722+ 	{   5,  2,  14,  4,  20,  8,  37, 16,  44,  4,  55, 16,  60, 32,  76,  2,
723+ 	   87,  4,  93, 32, 103,  1, 110,  1, 119,  2, 124,  1,   0,  0, },
724+ 	{   7, 32,  12,  4,  23, 16,  28, 32,  38, 32,  45,  4,  54,  2,  60, 16,
725+ 	   71,  1,  78,  1,  87,  2,  93,  2, 111,  8, 118, 16, 125, 16, },
726+ 	{   1,  1,  11, 32,  17,  2,  26, 16,  32,  8,  51,  8,  64,  2,  73,  4,
727+ 	   83, 16,  88,  4, 107,  2, 112, 32, 122,  8,   0,  0,   0,  0, },
728+ 	{   0,  4,   9, 32,  18, 32,  25,  8,  34,  8,  43, 32,  49,  2,  58, 16,
729+ 	   74,  1,  81, 16,  90,  2,  96,  2, 105,  4, 115, 16, 122,  4, },
730+ 	{   2,  2,  19,  1,  24,  1,  34,  4,  41, 32,  50, 32,  57,  8,  64, 32,
731+ 	   73,  1,  80, 16,  91,  4, 106,  1, 113, 16, 123,  8,   0,  0, },
732+ 	{   3,  4,  10, 16,  16,  8,  35,  8,  51,  1,  56,  1,  67, 16,  72,  4,
733+ 	   91,  2,  96, 32, 105,  1, 112, 16, 121,  2,   0,  0,   0,  0, },
734+ 	{   4, 16,  15,  1,  22,  1,  31,  2,  37,  2,  55,  8,  62, 16,  69, 16,
735+ 	   76,  4,  87, 16,  92, 32, 102, 32, 109,  4, 118,  2, 125, 32, },
736+ 	{   6,  4,  23,  8,  30, 16,  39, 32,  45,  1,  54,  8,  70, 32,  77,  4,
737+ 	   86,  2,  92, 16, 101,  8, 116,  1, 125,  2,   0,  0,   0,  0, },
738+ 	{   4,  4,  13,  1,  22,  8,  36,  2,  47,  4,  53, 32,  63,  1,  69,  8,
739+ 	   84,  1,  94,  4, 100,  8, 117, 16, 127, 32,   0,  0,   0,  0, },
740+ 	{   3, 32,   8, 16,  19,  4,  34,  1,  41, 16,  50,  2,  56,  2,  67,  1,
741+ 	   72,  1,  82,  4,  89, 32,  98, 32, 105,  8, 114,  8, 121,  1, },
742+ 	{   1, 32,  19,  2,  24, 32,  33,  1,  40, 16,  51,  4,  64,  8,  83,  8,
743+ 	   99,  1, 104,  1, 114,  4, 120,  4,   0,  0,   0,  0,   0,  0, },
744+ 	{   8,  2,  17,  4,  27, 16,  32,  4,  51,  2,  56, 32,  66,  8,  75, 32,
745+ 	   81,  2,  90, 16,  96,  8, 115,  8, 122,  2,   0,  0,   0,  0, },
746+ 	{   2, 16,  18,  1,  25, 16,  34,  2,  40,  2,  49,  4,  59, 16,  66,  4,
747+ 	   73, 32,  82, 32,  89,  8,  98,  8, 107, 32, 113,  2, 123,  4, },
748+ 	{   7,  1,  13,  8,  28,  1,  38,  4,  44,  8,  61, 16,  71, 32,  77,  1,
749+ 	   86,  8, 100,  2, 111,  4, 117, 32, 124, 16,   0,  0,   0,  0, },
750+ 	{  12,  8,  29, 16,  36,  4,  47, 16,  52, 32,  62, 32,  68,  2,  79,  4,
751+ 	   85, 32,  95,  1, 102,  1, 111,  2, 117,  2, 126,  4,   0,  0, },
752+ 	{   5,  1,  15, 16,  20, 32,  30, 32,  37,  4,  46,  2,  52, 16,  61,  8,
753+ 	   70,  1,  79,  2,  85,  2, 103,  8, 110, 16, 119, 32, 124,  4, },
754+ 	{   0, 16,   9,  2,  18, 16,  24,  8,  43,  8,  59,  1,  65,  4,  75, 16,
755+ 	   80,  4,  99,  2, 104, 32, 113,  1, 123, 32,   0,  0,   0,  0, },
756+ 	{  10, 32,  17,  8,  26,  8,  35, 32,  41,  2,  50, 16,  56,  8,  66,  1,
757+ 	   73, 16,  82,  2,  88,  2,  97,  4, 107, 16, 112,  4, 121, 32, },
758+ 	{   0,  2,  11,  1,  16,  1,  26,  4,  33, 32,  42, 32,  49,  8,  58,  8,
759+ 	   65,  1,  72, 16,  83,  4,  98,  1, 105, 16, 114,  2,   0,  0, },
760+ 	{   8,  8,  27,  8,  43,  1,  48,  1,  58,  4,  64,  4,  83,  2,  88, 32,
761+ 	   97,  1, 104, 16, 115,  4, 122, 16,   0,  0,   0,  0,   0,  0, },
762+ 	{   5,  8,  14,  1,  23,  2,  29,  2,  47,  8,  54, 16,  63, 32,  68,  4,
763+ 	   79, 16,  84, 32,  94, 32, 101,  4, 110,  2, 116, 16, 127,  1, },
764+ 	{   4,  8,  15,  8,  22, 16,  31, 32,  37,  1,  46,  8,  60,  2,  69,  4,
765+ 	   78,  2,  84, 16,  93,  8, 108,  1, 118,  4,   0,  0,   0,  0, },
766+ 	{   7, 16,  14,  8,  28,  2,  39,  4,  45, 32,  55,  1,  62,  1,  76,  1,
767+ 	   86,  4,  92,  8, 109, 16, 116,  4, 125,  1,   0,  0,   0,  0, },
768+ 	{   1,  2,  11,  4,  26,  1,  33, 16,  42,  2,  48,  2,  57,  4,  64,  1,
769+ 	   74,  4,  81, 32,  90, 32,  97,  8, 106,  8, 115, 32, 120, 16, },
770+ 	{   2, 32,  11,  2,  16, 32,  25,  1,  32, 16,  43,  4,  58,  1,  75,  8,
771+ 	   91,  1,  96,  1, 106,  4, 113, 32,   0,  0,   0,  0,   0,  0, },
772+ 	{   3,  1,   9,  4,  19, 16,  24,  4,  43,  2,  48, 32,  57,  1,  67, 32,
773+ 	   73,  2,  82, 16,  88,  8, 107,  8, 120,  2,   0,  0,   0,  0, },
774+ 	{   0,  8,  10,  1,  17, 16,  26,  2,  32,  2,  41,  4,  51, 16,  56,  4,
775+ 	   65, 32,  74, 32,  81,  8,  90,  8,  99, 32, 105,  2, 114, 16, },
776+ 	{   6,  1,  20,  1,  30,  4,  36,  8,  53, 16,  60,  4,  69,  1,  78,  8,
777+ 	   92,  2, 103,  4, 109, 32, 119,  1, 125,  8,   0,  0,   0,  0, },
778+ 	{   7,  8,  21, 16,  28,  4,  39, 16,  44, 32,  54, 32,  61,  4,  71,  4,
779+ 	   77, 32,  87,  1,  94,  1, 103,  2, 109,  2, 124,  8,   0,  0, },
780+ 	{   6,  8,  12, 32,  22, 32,  29,  4,  38,  2,  44, 16,  53,  8,  71,  2,
781+ 	   77,  2,  95,  8, 102, 16, 111, 32, 117,  1, 127, 16,   0,  0, }
782+ };
783+
784+ static void
785+ key_setup(char key[U9AUTH_DESKEYLEN], char *ek)
786+ {
787+ 	int i, j, k, mask;
788+ 	uchar (*x)[2];
789+
790+ 	bzero(ek, 128);
791+ 	x = keyexpand[0];
792+ 	for(i = 0; i < 7; i++){
793+ 		k = key[i];
794+ 		for(mask = 0x80; mask; mask >>= 1){
795+ 			if(k & mask)
796+ 				for(j = 0; j < 15; j++)
797+ 					ek[x[j][0]] |= x[j][1];
798+ 			x += 15;
799+ 		}
800+ 	}
801+ }
802diff -N -c -r /usr/src/sys/9fs/9fs.h ./9fs/9fs.h
803*** /usr/src/sys/9fs/9fs.h	Wed Dec 31 19:00:00 1969
804--- ./9fs/9fs.h	Mon May 22 11:31:29 2000
805***************
806*** 0 ****
807--- 1,294 ----
808+ /*
809+  * Copyright (c) 1989, 1993, 1995
810+  *	The Regents of the University of California.  All rights reserved.
811+  *
812+  * This code is derived from software contributed to Berkeley by
813+  * Rick Macklem at The University of Guelph.
814+  *
815+  * Redistribution and use in source and binary forms, with or without
816+  * modification, are permitted provided that the following conditions
817+  * are met:
818+  * 1. Redistributions of source code must retain the above copyright
819+  *    notice, this list of conditions and the following disclaimer.
820+  * 2. Redistributions in binary form must reproduce the above copyright
821+  *    notice, this list of conditions and the following disclaimer in the
822+  *    documentation and/or other materials provided with the distribution.
823+  * 3. All advertising materials mentioning features or use of this software
824+  *    must display the following acknowledgement:
825+  *	This product includes software developed by the University of
826+  *	California, Berkeley and its contributors.
827+  * 4. Neither the name of the University nor the names of its contributors
828+  *    may be used to endorse or promote products derived from this software
829+  *    without specific prior written permission.
830+  *
831+  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
832+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
833+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
834+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
835+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
836+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
837+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
838+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
839+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
840+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
841+  * SUCH DAMAGE.
842+  *
843+  *	@(#)nfs.h	8.4 (Berkeley) 5/1/95
844+  * $Id: nfs.h,v 1.44 1998/09/07 05:42:15 bde Exp $
845+  */
846+
847+ #ifndef _9FS_H_
848+ #define _9FS_H_
849+
850+ #ifdef KERNEL
851+ #include "opt_u9fs.h"
852+ #endif
853+
854+ #define U9FS_FABLKSIZE   512
855+ #define U9FS_PORT        17008
856+
857+ /*
858+  * The set of signals the interrupt an I/O in progress for U9FSMNT_INT mounts.
859+  * What should be in this set is open to debate, but I believe that since
860+  * I/O system calls on ufs are never interrupted by signals the set should
861+  * be minimal. My reasoning is that many current programs that use signals
862+  * such as SIGALRM will not expect file I/O system calls to be interrupted
863+  * by them and break.
864+  */
865+ #define	U9FSINT_SIGMASK	(sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
866+ 			 sigmask(SIGHUP)|sigmask(SIGQUIT))
867+
868+ /*
869+  * U9FS mount option flags
870+  */
871+ #define	U9FSMNT_SOFT		0x00000001  /* soft mount (hard is default) */
872+ #define	U9FSMNT_MAXGRPS		0x00000020  /* set maximum grouplist size */
873+ #define	U9FSMNT_INT		0x00000040  /* allow interrupts on hard mount */
874+ #define	U9FSMNT_KERB		0x00000400  /* Use Kerberos authentication */
875+ #define	U9FSMNT_READAHEAD	0x00002000  /* set read ahead */
876+
877+ #define U9FSSTA_HASWRITEVERF	0x00040000  /* Has write verifier for V3 */
878+ #define U9FSSTA_GOTPATHCONF	0x00080000  /* Got the V3 pathconf info */
879+ #define U9FSSTA_GOTFSINFO	0x00100000  /* Got the V3 fsinfo */
880+ #define	U9FSSTA_MNTD		0x00200000  /* Mnt server for mnt point */
881+ #define	U9FSSTA_DISMINPROG	0x00400000  /* Dismount in progress */
882+ #define	U9FSSTA_DISMNT		0x00800000  /* Dismounted */
883+ #define	U9FSSTA_SNDLOCK		0x01000000  /* Send socket lock */
884+ #define	U9FSSTA_WANTSND		0x02000000  /* Want above */
885+ #define	U9FSSTA_RCVLOCK		0x04000000  /* Rcv socket lock */
886+ #define	U9FSSTA_WANTRCV		0x08000000  /* Want above */
887+ #define	U9FSSTA_WAITAUTH		0x10000000  /* Wait for authentication */
888+ #define	U9FSSTA_HASAUTH		0x20000000  /* Has authenticator */
889+ #define	U9FSSTA_WANTAUTH		0x40000000  /* Wants an authenticator */
890+ #define	U9FSSTA_AUTHERR		0x80000000  /* Authentication error */
891+
892+ #define	U9FSNOHASH(fhsum) (&u9fsnodehashtbl[(fhsum) % u9fsnodehash])
893+
894+ /*
895+  * Arguments to mount 9FS
896+  */
897+ #define U9FS_ARGSVERSION	1	/* change when nfs_args changes */
898+ struct u9fs_args {
899+ 	int		version;	/* args structure version number */
900+ 	struct sockaddr	*addr;		/* file server address */
901+ 	int		addrlen;	/* length of address */
902+ 	int		sotype;		/* Socket type */
903+ 	int		proto;		/* and Protocol */
904+ 	int		fhsize;		/* Size, in bytes, of fh */
905+ 	int		flags;		/* flags */
906+ 	int		wsize;		/* write size in bytes */
907+ 	int		rsize;		/* read size in bytes */
908+ 	int		readdirsize;	/* readdir size in bytes */
909+ 	char		*hostname;	/* server's name */
910+
911+         struct sockaddr * authaddr;
912+         int             authaddrlen;
913+         int             authsotype;
914+         int             authsoproto;
915+
916+         int             nusers;
917+         char            user[U9FS_NAMELEN];
918+         char            key[U9AUTH_DESKEYLEN];
919+         struct p9user {
920+ 	  uid_t p9_uid;
921+ 	  char p9_name[U9FS_NAMELEN];
922+ 	} * users;
923+ };
924+
925+ #define U9FS_USER_HASHSIZE 512
926+
927+ struct u9fsuser {
928+   LIST_ENTRY(u9fsuser) u_hash;
929+   uid_t                u_uid;
930+   char                 u_name[U9FS_NAMELEN];
931+   char                 u_ckey[U9AUTH_DESKEYLEN];  /* user key */
932+   char                 u_skey[U9AUTH_DESKEYLEN];  /* session key */
933+ };
934+
935+ /*
936+  * The u9fsnode is the u9fs equivalent to ufs's inode. Any similarity
937+  * is purely coincidental.
938+  * There is a unique u9fsnode allocated for each active file,
939+  * each current directory, each mounted-on file, text file, and the root.
940+  * An u9fsnode is 'named' by its file handle. (nget/u9fs_node.c)
941+  * If this structure exceeds 256 bytes (it is currently 256 using 4.4BSD-Lite
942+  * type definitions), file handles of > 32 bytes should probably be split out
943+  * into a separate MALLOC()'d data structure. (Reduce the size of u9fsfh_t by
944+  * changing the definition in u9fsproto.h of U9FS_SMALLFH.)
945+  * NB: Hopefully the current order of the fields is such that everything will
946+  *     be well aligned and, therefore, tightly packed.
947+  */
948+ struct u9fsnode {
949+ 	LIST_ENTRY(u9fsnode)	n_hash;		/* Hash chain */
950+ 	u_quad_t		n_size;		/* Current size of file */
951+ 	struct vattr		n_vattr;	/* Vnode attribute cache */
952+ 	time_t			n_attrstamp;	/* Attr. cache timestamp */
953+ 	u_int32_t		n_mode;		/* ACCESS mode cache */
954+ 	uid_t			n_modeuid;	/* credentials having mode */
955+ 	time_t			n_modestamp;	/* mode cache timestamp */
956+ 	time_t			n_mtime;	/* Prev modify time. */
957+ 	time_t			n_ctime;	/* Prev create time. */
958+         struct u9fs_qid         n_qid;
959+ 	u_short			n_fid;		/* U9FS FID */
960+         u_short                 n_rdfid;
961+         u_short                 n_wrfid;
962+ 	struct vnode		*n_vnode;	/* associated vnode */
963+ 	struct lockf		*n_lockf;	/* Locking record of file */
964+ 	int			n_error;	/* Save write error value */
965+         struct u9fsdir          n_dir;
966+ 	short			n_flag;		/* Flag for locking.. */
967+         int                     n_opens;        /* number of opens */
968+ };
969+
970+ #define n_atim		n_un1.nf_atim
971+ #define n_mtim		n_un2.nf_mtim
972+ #define n_sillyrename	n_un3.nf_silly
973+ #define n_cookieverf	n_un1.nd_cookieverf
974+ #define n_direofoffset	n_un2.nd_direof
975+ #define n_cookies	n_un3.nd_cook
976+
977+ /*
978+  * Flags for n_flag
979+  */
980+ #define	NFLUSHWANT	0x0001	/* Want wakeup from a flush in prog. */
981+ #define	NFLUSHINPROG	0x0002	/* Avoid multiple calls to vinvalbuf() */
982+ #define	NMODIFIED	0x0004	/* Might have a modified buffer in bio */
983+ #define	NWRITEERR	0x0008	/* Flag write errors so close will know */
984+ #define	NQU9FSNONCACHE	0x0020	/* Non-cachable lease */
985+ #define	NQU9FSWRITE	0x0040	/* Write lease */
986+ #define	NQU9FSEVICTED	0x0080	/* Has been evicted */
987+ #define	NACC		0x0100	/* Special file accessed */
988+ #define	NUPD		0x0200	/* Special file updated */
989+ #define	NCHG		0x0400	/* Special file times changed */
990+ #define NLOCKED		0x0800  /* node is locked */
991+ #define NWANTED		0x0100  /* someone wants to lock */
992+
993+ /*
994+  * Convert between u9fsnode pointers and vnode pointers
995+  */
996+ #define VTOU9FS(vp)	((struct u9fsnode *)(vp)->v_data)
997+ #define U9FSTOV(np)	((struct vnode *)(np)->n_vnode)
998+
999+ /*
1000+  * Mount structure.
1001+  * One allocated on every U9FS mount.
1002+  * Holds U9FS specific information for mount.
1003+  */
1004+ struct	u9fsmount {
1005+ 	int	nm_flag;		/* Flags for soft/hard... */
1006+ 	int	nm_state;		/* Internal state flags */
1007+ 	struct	mount *nm_mountp;	/* Vfs structure for this filesystem */
1008+ 	int	nm_numgrps;		/* Max. size of groupslist */
1009+         u9fsfh_t nm_fh;                /* qid.path */
1010+ 	u_short	nm_fid;	                /* fid of root dir */
1011+ 	struct	socket *nm_so;		/* Rpc socket */
1012+ 	int	nm_sotype;		/* Type of socket */
1013+ 	int	nm_soproto;		/* and protocol */
1014+ 	int	nm_soflags;		/* pr_flags for socket protocol */
1015+ 	struct	sockaddr *nm_nam;	/* Addr of server */
1016+ 	int	nm_sent;		/* Request send count */
1017+ 	int	nm_cwnd;		/* Request send window */
1018+ 	int	nm_rsize;		/* Max size of read rpc */
1019+ 	int	nm_wsize;		/* Max size of write rpc */
1020+ 	int	nm_readdirsize;		/* Size of a readdir rpc */
1021+
1022+   struct lock   nm_lock;                /* lock for tag/fid freelist */
1023+   bitstr_t * nm_tags;
1024+   bitstr_t * nm_fids;
1025+   TAILQ_HEAD(u9fs_reqq, u9fsreq) nm_reqq;
1026+
1027+         uid_t   nm_authuid;             /* Uid for authenticator */
1028+ #if 0
1029+ 	struct vnode *nm_inprog;	/* Vnode in prog by nqu9fs_clientd() */
1030+ 	uid_t	nm_authuid;		/* Uid for authenticator */
1031+ 	int	nm_authtype;		/* Authenticator type */
1032+ 	int	nm_authlen;		/* and length */
1033+ 	char	*nm_authstr;		/* Authenticator string */
1034+ 	char	*nm_verfstr;		/* and the verifier */
1035+ 	int	nm_verflen;
1036+ 	u_char	nm_verf[U9FSX_V3WRITEVERF]; /* V3 write verifier */
1037+ 	U9FSKERBKEY_T nm_key;		/* and the session key */
1038+ 	int	nm_numuids;		/* Number of u9fsuid mappings */
1039+ 	TAILQ_HEAD(, u9fsuid) nm_uidlruhead; /* Lists of u9fsuid mappings */
1040+ 	LIST_HEAD(, u9fsuid) nm_uidhashtbl[U9FS_MUIDHASHSIZ];
1041+ 	TAILQ_HEAD(, buf) nm_bufq;	/* async io buffer queue */
1042+ 	short	nm_bufqlen;		/* number of buffers in queue */
1043+ 	short	nm_bufqwant;		/* process wants to add to the queue */
1044+ 	int	nm_bufqiods;		/* number of iods processing queue */
1045+ #endif
1046+ 	u_int64_t nm_maxfilesize;	/* maximum file size */
1047+ };
1048+
1049+ #ifdef KERNEL
1050+
1051+ #ifdef MALLOC_DECLARE
1052+ MALLOC_DECLARE(M_U9FSHASH);
1053+ MALLOC_DECLARE(M_U9FSBITS);
1054+
1055+ extern        vop_t   **u9fs_vnodeop_p;
1056+
1057+ /* u9fs_node.c */
1058+ void     u9fs_nhinit __P((void));
1059+ int u9fs_nget __P((struct mount *mntp, u9fsfh_t fh, struct u9fsnode **npp, struct proc * p));
1060+
1061+ /* u9fs_subr.c */
1062+ void u9fs_id_init __P((bitstr_t ** bits));
1063+ u_short u9fs_id_new __P((bitstr_t * bits));
1064+ void u9fs_id_free __P((bitstr_t * bits, u_short v));
1065+ void u9fs_uhinit __P((void));
1066+ uid_t u9fs_name2uid __P((char * name));
1067+ struct u9fsuser *  u9fs_finduser __P((uid_t uid));
1068+ void  u9fs_hashuser __P((uid_t uid, char *name));
1069+ int u9fs_mbuftouio __P((struct mbuf *m, struct uio *uiop, int siz));
1070+ int u9fs_uiotombuf __P((struct uio *uiop, struct mbuf **mq, int siz));
1071+
1072+ /* u9fs_vnopes.c */
1073+ int u9fs_readdirrpc __P((struct vnode *, struct uio *, struct ucred *));
1074+ int u9fs_readrpc __P((struct vnode *vp, struct uio *uiop, struct ucred *cred));
1075+ int u9fs_writerpc __P((struct vnode *vp, struct uio *uiop, struct ucred *cred));
1076+
1077+ /* u9fs_bio.c */
1078+ int u9fs_bioread __P((struct vnode *, struct uio *, int, struct ucred *,int));
1079+ int u9fs_biowrite __P((struct vnode *, struct uio *, int ioflag, struct ucred *));
1080+ int u9fs_doio __P((struct buf *, struct ucred *, struct proc *));
1081+ int	u9fs_vinvalbuf __P((struct vnode *, int, struct ucred *, struct proc *, int));
1082+
1083+
1084+ /* u9fs_socket.c */
1085+ int u9fs_sigintr __P((struct u9fsmount *nmp, struct proc *p));
1086+ void     u9fs_disconnect __P((struct socket *));
1087+ int      u9fs_connect __P((struct socket ** sop, struct sockaddr * saddr, int sotype, int soproto, struct proc * p));
1088+ int      u9fs_connect_9fs __P((struct u9fsmount *));
1089+ int      u9fs_connect_9auth __P((struct u9fsmount *, struct u9fs_args *, struct socket **));
1090+ int u9fs_request __P((struct u9fsreq * req, struct u9fsreq * rep, int relm));
1091+
1092+ #endif
1093+
1094+ /*
1095+  * Convert mount ptr to u9fsmount ptr.
1096+  */
1097+ #define VFSTOU9FS(mp)	((struct u9fsmount *)((mp)->mnt_data))
1098+
1099+ #endif	/* KERNEL */
1100+
1101+ #endif
1102diff -N -c -r /usr/src/sys/9fs/9fs_bio.c ./9fs/9fs_bio.c
1103*** /usr/src/sys/9fs/9fs_bio.c	Wed Dec 31 19:00:00 1969
1104--- ./9fs/9fs_bio.c	Fri Nov 26 12:28:50 1999
1105***************
1106*** 0 ****
1107--- 1,550 ----
1108+ #include <sys/param.h>
1109+ #include <sys/sockio.h>
1110+ #include <sys/proc.h>
1111+ #include <sys/vnode.h>
1112+ #include <sys/kernel.h>
1113+ #include <sys/sysctl.h>
1114+ #include <sys/malloc.h>
1115+ #include <sys/mount.h>
1116+ #include <sys/mbuf.h>
1117+ #include <sys/socket.h>
1118+ #include <sys/socketvar.h>
1119+ #include <sys/systm.h>
1120+ #include <sys/protosw.h>
1121+ #include <sys/syslog.h>
1122+
1123+ #include <netinet/in.h>
1124+ #include <netinet/tcp.h>
1125+
1126+ #include <vm/vm.h>
1127+ #include <vm/vm_extern.h>
1128+ #include <vm/vm_zone.h>
1129+ #include <vm/vm_prot.h>
1130+ #include <vm/vm_page.h>
1131+ #include <vm/vm_object.h>
1132+ #include <vm/vm_pager.h>
1133+ #include <vm/vnode_pager.h>
1134+
1135+ #include <net/if.h>
1136+ #include <net/route.h>
1137+ #include <netinet/in.h>
1138+
1139+ #include <9fs/bitstring.h>
1140+ #include <9fs/9p.h>
1141+ #include <9fs/9auth.h>
1142+ #include <9fs/9fs.h>
1143+
1144+ static struct buf *u9fs_getcacheblk __P((struct vnode *vp, daddr_t bn, int size, struct proc *p));
1145+ static void u9fs_prot_buf __P((struct buf *bp, int off, int n));
1146+
1147+ /*
1148+  * Vnode op for read using bio
1149+  */
1150+ int
1151+ u9fs_bioread(vp, uio, ioflag, cred, getpages)
1152+ 	register struct vnode *vp;
1153+ 	register struct uio *uio;
1154+ 	int ioflag;
1155+ 	struct ucred *cred;
1156+ 	int getpages;
1157+ {
1158+ 	register struct u9fsnode *np = VTOU9FS(vp);
1159+ 	register int biosize;
1160+ 	off_t diff;
1161+ 	struct buf *bp = 0;
1162+ 	struct proc *p;
1163+ 	struct u9fsmount *nmp = VFSTOU9FS(vp->v_mount);
1164+ 	daddr_t lbn;
1165+ 	int error = 0, n = 0, on = 0, bufsize, not_readin;
1166+
1167+ 	if (uio->uio_resid == 0)
1168+ 		return (0);
1169+ 	if (uio->uio_offset < 0)
1170+ 		return (EINVAL);
1171+ 	p = uio->uio_procp;
1172+ 	if (vp->v_type != VDIR &&
1173+ 	    (uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize)
1174+ 		return (EFBIG);
1175+ 	biosize = vp->v_mount->mnt_stat.f_iosize;
1176+ #if 0
1177+ 	if( np->n_qid.vers ) { /* in cache, check revision */
1178+ 	  error = VOP_GETATTR(vp, &vattr, cred, p);
1179+ 	  if( error )
1180+ 	    return error;
1181+ 	  if( np->n_qid.vers != np->n_dir.dir_qid.vers ) {
1182+ 	    /* content changed */
1183+ 	    u9fs_vinvalbuf(vp, V_SAVE, cred, p, 1);
1184+ 	  }
1185+ 	}
1186+ #endif
1187+ 	do {
1188+ 	    switch (vp->v_type) {
1189+ 	    case VREG:
1190+ 		lbn = uio->uio_offset / biosize;
1191+ 		on = uio->uio_offset & (biosize - 1);
1192+ 		not_readin = 1;
1193+
1194+ #if 0
1195+ 		/*
1196+ 		 * Start the read ahead(s), as required.
1197+ 		 */
1198+ 		if (u9fs_numasync > 0 && nmp->nm_readahead > 0) {
1199+ 		    for (nra = 0; nra < nmp->nm_readahead &&
1200+ 			(off_t)(lbn + 1 + nra) * biosize < np->n_size; nra++) {
1201+ 			rabn = lbn + 1 + nra;
1202+ 			if (!incore(vp, rabn)) {
1203+ 			    rabp = u9fs_getcacheblk(vp, rabn, biosize, p);
1204+ 			    if (!rabp)
1205+ 				return (EINTR);
1206+ 			    if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
1207+ 				rabp->b_flags |= (B_READ | B_ASYNC);
1208+ 				vfs_busy_pages(rabp, 0);
1209+ 				if (u9fs_asyncio(rabp, cred)) {
1210+ 				    rabp->b_flags |= B_INVAL|B_ERROR;
1211+ 				    vfs_unbusy_pages(rabp);
1212+ 				    brelse(rabp);
1213+ 				}
1214+ 			    } else
1215+ 				brelse(rabp);
1216+ 			}
1217+ 		    }
1218+ 		}
1219+ #endif
1220+
1221+ 		/*
1222+ 		 * If the block is in the cache and has the required data
1223+ 		 * in a valid region, just copy it out.
1224+ 		 * Otherwise, get the block and write back/read in,
1225+ 		 * as required.
1226+ 		 */
1227+ again:
1228+ 		bufsize = biosize;
1229+ 		if ((off_t)(lbn + 1) * biosize > np->n_size &&
1230+ 		    (off_t)(lbn + 1) * biosize - np->n_size < biosize) {
1231+ 			bufsize = np->n_size - (off_t)lbn * biosize;
1232+ 			bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
1233+ 		}
1234+ 		bp = u9fs_getcacheblk(vp, lbn, bufsize, p);
1235+ 		if (!bp)
1236+ 			return (EINTR);
1237+ 		/*
1238+ 		 * If we are being called from u9fs_getpages, we must
1239+ 		 * make sure the buffer is a vmio buffer.  The vp will
1240+ 		 * already be setup for vmio but there may be some old
1241+ 		 * non-vmio buffers attached to it.
1242+ 		 */
1243+ 		if (getpages && !(bp->b_flags & B_VMIO)) {
1244+ #ifdef DIAGNOSTIC
1245+ 			printf("u9fs_bioread: non vmio buf found, discarding\n");
1246+ #endif
1247+ 			bp->b_flags |= B_NOCACHE;
1248+ 			if (bp->b_dirtyend > 0) {
1249+ 				if ((bp->b_flags & B_DELWRI) == 0)
1250+ 					panic("u9fsbioread");
1251+ 				if (VOP_BWRITE(bp) == EINTR)
1252+ 					return (EINTR);
1253+ 			} else
1254+ 				brelse(bp);
1255+ 			goto again;
1256+ 		}
1257+ 		if ((bp->b_flags & B_CACHE) == 0) {
1258+ 		    bp->b_flags |= B_READ;
1259+ 		    bp->b_flags &= ~(B_DONE | B_ERROR | B_INVAL);
1260+ 		    not_readin = 0;
1261+ 		    vfs_busy_pages(bp, 0);
1262+ 		    error = u9fs_doio(bp, cred, p);
1263+ 		    if (error) {
1264+ 			brelse(bp);
1265+ 			return (error);
1266+ 		    }
1267+ 		    np->n_qid.vers = np->n_dir.dir_qid.vers;
1268+ 		}
1269+ 		if (bufsize > on) {
1270+ 			n = min((unsigned)(bufsize - on), uio->uio_resid);
1271+ 		} else {
1272+ 			n = 0;
1273+ 		}
1274+ 		diff = np->n_size - uio->uio_offset;
1275+ 		if (diff < n)
1276+ 			n = diff;
1277+ 		if (not_readin && n > 0) {
1278+ 			if (on < bp->b_validoff || (on + n) > bp->b_validend) {
1279+ 				bp->b_flags |= B_NOCACHE;
1280+ 				if (bp->b_dirtyend > 0) {
1281+ 				    if ((bp->b_flags & B_DELWRI) == 0)
1282+ 					panic("u9fsbioread");
1283+ 				    if (VOP_BWRITE(bp) == EINTR)
1284+ 					return (EINTR);
1285+ 				} else
1286+ 				    brelse(bp);
1287+ 				goto again;
1288+ 			}
1289+ 		}
1290+ 		vp->v_lastr = lbn;
1291+ 		diff = (on >= bp->b_validend) ? 0 : (bp->b_validend - on);
1292+ 		if (diff < n)
1293+ 			n = diff;
1294+ 		break;
1295+ 	    case VDIR:
1296+ 	        biosize = nmp->nm_readdirsize;
1297+ 		lbn = (uoff_t)uio->uio_offset / biosize;
1298+ 		on = uio->uio_offset % biosize;
1299+ 		bp = u9fs_getcacheblk(vp, lbn, biosize, p);
1300+ 		if (!bp)
1301+ 		    return (EINTR);
1302+ 		if ((bp->b_flags & B_CACHE) == 0) {
1303+ 		    bp->b_flags |= B_READ;
1304+ 		    vfs_busy_pages(bp, 0);
1305+ 		    error = u9fs_doio(bp, cred, p);
1306+ 		    if (error) {
1307+ 			    brelse(bp);
1308+ 		    }
1309+ 		    if (error)
1310+ 			    return (error);
1311+ 		    np->n_qid.vers = np->n_dir.dir_qid.vers;
1312+ 		}
1313+
1314+ 		/*
1315+ 		 * Make sure we use a signed variant of min() since
1316+ 		 * the second term may be negative.
1317+ 		 */
1318+ 		n = lmin(uio->uio_resid, biosize - bp->b_resid - on);
1319+ 		break;
1320+ 	    default:
1321+ 		printf(" u9fs_bioread: type %x unexpected\n",vp->v_type);
1322+ 		break;
1323+ 	    };
1324+
1325+ 	    if (n > 0) {
1326+ 		    error = uiomove(bp->b_data + on, (int)n, uio);
1327+ 	    }
1328+ 	    brelse(bp);
1329+ 	} while (error == 0 && uio->uio_resid > 0 && n > 0);
1330+ 	return (error);
1331+ }
1332+
1333+ /*
1334+  * Vnode op for write using bio
1335+  */
1336+ int
1337+ u9fs_biowrite(vp, uio, ioflag, cred)
1338+      register struct vnode *vp;
1339+      register struct uio *uio;
1340+      register int  ioflag;
1341+      register struct ucred *cred;
1342+ {
1343+   register int biosize;
1344+   struct proc *p = uio->uio_procp;
1345+   struct u9fsnode *np = VTOU9FS(vp);
1346+   struct buf *bp;
1347+   struct vattr vattr;
1348+   struct u9fsmount *nmp = VFSTOU9FS(vp->v_mount);
1349+   daddr_t lbn;
1350+   int bufsize;
1351+   int n, on, error = 0;
1352+
1353+   if (ioflag & (IO_APPEND | IO_SYNC)) {
1354+     if (ioflag & IO_APPEND) {
1355+       error = VOP_GETATTR(vp, &vattr, cred, p);
1356+       if (error)
1357+ 	return (error);
1358+       uio->uio_offset = np->n_size;
1359+     }
1360+   }
1361+   if (uio->uio_offset < 0)
1362+     return (EINVAL);
1363+   if ((uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize)
1364+     return (EFBIG);
1365+   if (uio->uio_resid == 0)
1366+     return (0);
1367+
1368+ 	/*
1369+ 	 * I use nm_rsize, not nm_wsize so that all buffer cache blocks
1370+ 	 * will be the same size within a filesystem. nfs_writerpc will
1371+ 	 * still use nm_wsize when sizing the rpc's.
1372+ 	 */
1373+ 	biosize = vp->v_mount->mnt_stat.f_iosize;
1374+ 	do {
1375+ 		lbn = uio->uio_offset / biosize;
1376+ 		on = uio->uio_offset & (biosize-1);
1377+ 		n = min((unsigned)(biosize - on), uio->uio_resid);
1378+ 		if (uio->uio_offset + n > np->n_size) {
1379+ 			np->n_size = uio->uio_offset + n;
1380+ 			vnode_pager_setsize(vp, np->n_size);
1381+ 		}
1382+ 		bufsize = biosize;
1383+ 		if ((off_t)(lbn + 1) * biosize > np->n_size) {
1384+ 			bufsize = np->n_size - (off_t)lbn * biosize;
1385+ 			bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
1386+ 		}
1387+ 		bp = u9fs_getcacheblk(vp, lbn, bufsize, p);
1388+ 		if (!bp)
1389+ 			return (EINTR);
1390+ 		if (bp->b_wcred == NOCRED) {
1391+ 			crhold(cred);
1392+ 			bp->b_wcred = cred;
1393+ 		}
1394+
1395+ 		error = uiomove((char *)bp->b_data + on, n, uio);
1396+ 		if (error) {
1397+ 			bp->b_flags |= B_ERROR;
1398+ 			brelse(bp);
1399+ 			return (error);
1400+ 		}
1401+
1402+ 		/*
1403+ 		 * This will keep the buffer and mmaped regions more coherent.
1404+ 		 */
1405+ 		u9fs_prot_buf(bp, on, n);
1406+ 		bp->b_dirtyoff = on;
1407+ 		bp->b_dirtyend = on + n;
1408+
1409+ 		if (bp->b_validend == 0 || bp->b_validend < bp->b_dirtyoff ||
1410+ 		    bp->b_validoff > bp->b_dirtyend) {
1411+ 		  /* XXX: destroys our read cache if not overlapping */
1412+ 		  /* two choice: none implemented
1413+ 		     1> keep the bigger(smaller) piece
1414+ 		     2> read the missing segment
1415+ 		  */
1416+ 			bp->b_validoff = bp->b_dirtyoff;
1417+ 			bp->b_validend = bp->b_dirtyend;
1418+ 		} else {
1419+ 			bp->b_validoff = min(bp->b_validoff, bp->b_dirtyoff);
1420+ 			bp->b_validend = max(bp->b_validend, bp->b_dirtyend);
1421+ 		}
1422+
1423+ 		error = bwrite(bp);
1424+ 		if( error ) {
1425+ 		  bp->b_flags |= B_ERROR;
1426+ 		  /* brelse(bp); */
1427+ 		  return error;
1428+ 		}
1429+ 	} while (uio->uio_resid > 0 && n > 0);
1430+ 	return 0;
1431+ }
1432+
1433+ /*
1434+  * Do an I/O operation to/from a cache block. This may be called
1435+  * synchronously or from an u9fsiod.
1436+  */
1437+ int
1438+ u9fs_doio(bp, cr, p)
1439+ 	register struct buf *bp;
1440+ 	struct ucred *cr;
1441+ 	struct proc *p;
1442+ {
1443+ 	register struct uio *uiop;
1444+ 	register struct vnode *vp;
1445+ 	struct u9fsnode *np;
1446+ 	struct u9fsmount *nmp;
1447+ 	int error = 0, diff, len;
1448+ 	struct uio uio;
1449+ 	struct iovec io;
1450+
1451+ 	vp = bp->b_vp;
1452+ 	np = VTOU9FS(vp);
1453+ 	nmp = VFSTOU9FS(vp->v_mount);
1454+ 	uiop = &uio;
1455+ 	uiop->uio_iov = &io;
1456+ 	uiop->uio_iovcnt = 1;
1457+ 	uiop->uio_segflg = UIO_SYSSPACE;
1458+ 	uiop->uio_procp = p;
1459+
1460+ 	if (bp->b_flags & B_READ ) {
1461+ 	    io.iov_len = uiop->uio_resid = bp->b_bcount;
1462+ 	    io.iov_base = bp->b_data;
1463+ 	    uiop->uio_rw = UIO_READ;
1464+ 	    switch (vp->v_type) {
1465+ 	    case VREG:
1466+ 		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
1467+ 		error = u9fs_readrpc(vp, uiop, cr);
1468+ 		if (!error) {
1469+ 		    bp->b_validoff = 0;
1470+ 		    if (uiop->uio_resid) {
1471+ 			/*
1472+ 			 * If len > 0, there is a hole in the file and
1473+ 			 * no writes after the hole have been pushed to
1474+ 			 * the server yet.
1475+ 			 * Just zero fill the rest of the valid area.
1476+ 			 */
1477+ 			diff = bp->b_bcount - uiop->uio_resid;
1478+ 			len = np->n_size - (((u_quad_t)bp->b_blkno) * DEV_BSIZE
1479+ 				+ diff);
1480+ 			if (len > 0) {
1481+ 			    len = min(len, uiop->uio_resid);
1482+ 			    bzero((char *)bp->b_data + diff, len);
1483+ 			    bp->b_validend = diff + len;
1484+ 			} else
1485+ 			    bp->b_validend = diff;
1486+ 		    } else
1487+ 			bp->b_validend = bp->b_bcount;
1488+ 		}
1489+ 		break;
1490+ 	    case VDIR:
1491+ 		uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * nmp->nm_readdirsize;
1492+ 		error = u9fs_readdirrpc(vp, uiop, cr);
1493+ 		if (error == 0 && uiop->uio_resid == bp->b_bcount)
1494+ 		  bp->b_flags |= B_INVAL;
1495+ 		break;
1496+ 	    default:
1497+ 		printf("u9fs_doio:  type %x unexpected\n",vp->v_type);
1498+ 		break;
1499+ 	    };
1500+ 	    if (error) {
1501+ 		bp->b_flags |= B_ERROR;
1502+ 		bp->b_error = error;
1503+ 	    }
1504+ 	} else {
1505+ 	    if ((off_t)bp->b_blkno * DEV_BSIZE + bp->b_dirtyend > np->n_size)
1506+ 		bp->b_dirtyend = np->n_size - (off_t)bp->b_blkno * DEV_BSIZE;
1507+
1508+ 	    if (bp->b_dirtyend > bp->b_dirtyoff) {
1509+ 		io.iov_len = uiop->uio_resid = bp->b_dirtyend
1510+ 		    - bp->b_dirtyoff;
1511+ 		uiop->uio_offset = (off_t)bp->b_blkno * DEV_BSIZE
1512+ 		    + bp->b_dirtyoff;
1513+ 		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
1514+ 		uiop->uio_rw = UIO_WRITE;
1515+ 		bp->b_flags |= B_WRITEINPROG;
1516+ 		error = u9fs_writerpc(vp, uiop, cr);
1517+ 		bp->b_flags &= ~B_WRITEINPROG;
1518+
1519+ 		if (error) {
1520+ 		  bp->b_flags |= B_ERROR;
1521+ 		  bp->b_error = np->n_error = error;
1522+ 		  np->n_flag |= NWRITEERR;
1523+ 		}
1524+ 		bp->b_dirtyoff = bp->b_dirtyend = 0;
1525+ 	    } else {
1526+ 		bp->b_resid = 0;
1527+ 		biodone(bp);
1528+ 		return (0);
1529+ 	    }
1530+ 	}
1531+ 	bp->b_resid = uiop->uio_resid;
1532+ 	biodone(bp);
1533+ 	return error;
1534+ }
1535+
1536+ /*
1537+  * Get an u9fs cache block.
1538+  * Allocate a new one if the block isn't currently in the cache
1539+  * and return the block marked busy. If the calling process is
1540+  * interrupted by a signal for an interruptible mount point, return
1541+  * NULL.
1542+  */
1543+ static struct buf *
1544+ u9fs_getcacheblk(vp, bn, size, p)
1545+ 	struct vnode *vp;
1546+ 	daddr_t bn;
1547+ 	int size;
1548+ 	struct proc *p;
1549+ {
1550+ 	register struct buf *bp;
1551+ 	struct mount *mp;
1552+ 	struct u9fsmount *nmp;
1553+
1554+ 	mp = vp->v_mount;
1555+ 	nmp = VFSTOU9FS(mp);
1556+
1557+ 	if (nmp->nm_flag & U9FSMNT_INT) {
1558+ 		bp = getblk(vp, bn, size, PCATCH, 0);
1559+ 		while (bp == (struct buf *)0) {
1560+ 			if (u9fs_sigintr(nmp, p))
1561+ 				return ((struct buf *)0);
1562+ 			bp = getblk(vp, bn, size, 0, 2 * hz);
1563+ 		}
1564+ 	} else
1565+ 		bp = getblk(vp, bn, size, 0, 0);
1566+
1567+ 	if (vp->v_type == VREG) {
1568+ 		int biosize;
1569+ 		biosize = mp->mnt_stat.f_iosize;
1570+ 		bp->b_blkno = bn * (biosize / DEV_BSIZE);
1571+ 	}
1572+
1573+ 	return (bp);
1574+ }
1575+
1576+ static void
1577+ u9fs_prot_buf(bp, off, n)
1578+ 	struct buf *bp;
1579+ 	int off;
1580+ 	int n;
1581+ {
1582+ 	int pindex, boff, end;
1583+
1584+ 	if ((bp->b_flags & B_VMIO) == 0)
1585+ 		return;
1586+
1587+ 	end = round_page(off + n);
1588+ 	for (boff = trunc_page(off); boff < end; boff += PAGE_SIZE) {
1589+ 		pindex = boff >> PAGE_SHIFT;
1590+ 		vm_page_protect(bp->b_pages[pindex], VM_PROT_NONE);
1591+ 	}
1592+ }
1593+
1594+ /*
1595+  * Flush and invalidate all dirty buffers. If another process is already
1596+  * doing the flush, just wait for completion.
1597+  */
1598+ int
1599+ u9fs_vinvalbuf(vp, flags, cred, p, intrflg)
1600+ 	struct vnode *vp;
1601+ 	int flags;
1602+ 	struct ucred *cred;
1603+ 	struct proc *p;
1604+ 	int intrflg;
1605+ {
1606+ 	register struct u9fsnode *np = VTOU9FS(vp);
1607+ 	struct u9fsmount *nmp = VFSTOU9FS(vp->v_mount);
1608+ 	int error = 0, slpflag, slptimeo;
1609+
1610+ 	if (vp->v_flag & VXLOCK) {
1611+ 		return (0);
1612+ 	}
1613+
1614+ 	if ((nmp->nm_flag & U9FSMNT_INT) == 0)
1615+ 		intrflg = 0;
1616+ 	if (intrflg) {
1617+ 		slpflag = PCATCH;
1618+ 		slptimeo = 2 * hz;
1619+ 	} else {
1620+ 		slpflag = 0;
1621+ 		slptimeo = 0;
1622+ 	}
1623+ 	/*
1624+ 	 * First wait for any other process doing a flush to complete.
1625+ 	 */
1626+ 	while (np->n_flag & NFLUSHINPROG) {
1627+ 		np->n_flag |= NFLUSHWANT;
1628+ 		error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "u9fsvinval",
1629+ 			slptimeo);
1630+ 		if (error && intrflg && u9fs_sigintr(nmp, p))
1631+ 			return (EINTR);
1632+ 	}
1633+
1634+ 	/*
1635+ 	 * Now, flush as required.
1636+ 	 */
1637+ 	np->n_flag |= NFLUSHINPROG;
1638+ 	error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
1639+ 	while (error) {
1640+ 		if (intrflg && u9fs_sigintr(nmp, p)) {
1641+ 			np->n_flag &= ~NFLUSHINPROG;
1642+ 			if (np->n_flag & NFLUSHWANT) {
1643+ 				np->n_flag &= ~NFLUSHWANT;
1644+ 				wakeup((caddr_t)&np->n_flag);
1645+ 			}
1646+ 			return (EINTR);
1647+ 		}
1648+ 		error = vinvalbuf(vp, flags, cred, p, 0, slptimeo);
1649+ 	}
1650+ 	np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
1651+ 	if (np->n_flag & NFLUSHWANT) {
1652+ 		np->n_flag &= ~NFLUSHWANT;
1653+ 		wakeup((caddr_t)&np->n_flag);
1654+ 	}
1655+ 	return (0);
1656+ }
1657+
1658diff -N -c -r /usr/src/sys/9fs/9fs_node.c ./9fs/9fs_node.c
1659*** /usr/src/sys/9fs/9fs_node.c	Wed Dec 31 19:00:00 1969
1660--- ./9fs/9fs_node.c	Thu Nov 25 15:36:49 1999
1661***************
1662*** 0 ****
1663--- 1,132 ----
1664+ #include <sys/param.h>
1665+ #include <sys/sockio.h>
1666+ #include <sys/proc.h>
1667+ #include <sys/vnode.h>
1668+ #include <sys/kernel.h>
1669+ #include <sys/sysctl.h>
1670+ #include <sys/malloc.h>
1671+ #include <sys/mount.h>
1672+ #include <sys/mbuf.h>
1673+ #include <sys/socket.h>
1674+ #include <sys/socketvar.h>
1675+ #include <sys/systm.h>
1676+ #include <sys/protosw.h>
1677+ #include <sys/syslog.h>
1678+
1679+ #include <netinet/in.h>
1680+ #include <netinet/tcp.h>
1681+
1682+ #include <vm/vm.h>
1683+ #include <vm/vm_extern.h>
1684+ #include <vm/vm_zone.h>
1685+
1686+ #include <net/if.h>
1687+ #include <net/route.h>
1688+ #include <netinet/in.h>
1689+
1690+ #include <9fs/bitstring.h>
1691+ #include <9fs/9p.h>
1692+ #include <9fs/9auth.h>
1693+ #include <9fs/9fs.h>
1694+
1695+ vm_zone_t u9fsnode_zone;
1696+ static LIST_HEAD(u9fsnodehashhead, u9fsnode) *u9fsnodehashtbl;
1697+ static u_long u9fsnodehash;
1698+ MALLOC_DEFINE(M_U9FSHASH, "U9FS hash", "U9FS hash tables");
1699+
1700+ /*
1701+  * Initialize hash links for u9fsnodes
1702+  * and build u9fsnode free list.
1703+  */
1704+ void
1705+ u9fs_nhinit()
1706+ {
1707+   u9fsnode_zone = zinit("U9FSNODE", sizeof(struct u9fsnode), 0, 0, 1);
1708+   u9fsnodehashtbl = phashinit(desiredvnodes, M_U9FSHASH, &u9fsnodehash);
1709+ }
1710+
1711+ /*
1712+  * Look up a vnode/u9fsnode by file handle.
1713+  * Callers must check for mount points!!
1714+  * In all cases, a pointer to a
1715+  * u9fsnode structure is returned.
1716+  */
1717+ static int u9fs_node_hash_lock;
1718+
1719+ int
1720+ u9fs_nget(mntp, fh, npp, p)
1721+      struct mount *mntp;
1722+      register u9fsfh_t fh;
1723+      struct u9fsnode **npp;
1724+      struct proc * p;
1725+ {
1726+   struct u9fsnode *np;
1727+   struct u9fsnodehashhead *nhpp;
1728+   register struct vnode *vp;
1729+   struct vnode *nvp;
1730+   int error;
1731+
1732+   nhpp = U9FSNOHASH(fh);
1733+ loop:
1734+   for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
1735+     if (mntp != U9FSTOV(np)->v_mount || fh != np->n_qid.path )
1736+       continue;
1737+     vp = U9FSTOV(np);
1738+     if (vget(vp, LK_EXCLUSIVE, p))
1739+       goto loop;
1740+     *npp = np;
1741+     return(0);
1742+   }
1743+   /*
1744+    * Obtain a lock to prevent a race condition if the getnewvnode()
1745+    * or MALLOC() below happens to block.
1746+    */
1747+   if (u9fs_node_hash_lock) {
1748+     while (u9fs_node_hash_lock) {
1749+       u9fs_node_hash_lock = -1;
1750+       tsleep(&u9fs_node_hash_lock, PVM, "u9fsngt", 0);
1751+     }
1752+     goto loop;
1753+   }
1754+   u9fs_node_hash_lock = 1;
1755+
1756+   /*
1757+    * allocate before getnewvnode since doing so afterward
1758+    * might cause a bogus v_data pointer to get dereferenced
1759+    * elsewhere if zalloc should block.
1760+    */
1761+   np = zalloc(u9fsnode_zone);
1762+
1763+   error = getnewvnode(VT_U9FS, mntp, u9fs_vnodeop_p, &nvp);
1764+   if (error) {
1765+     if (u9fs_node_hash_lock < 0)
1766+       wakeup(&u9fs_node_hash_lock);
1767+     u9fs_node_hash_lock = 0;
1768+     *npp = 0;
1769+     zfree(u9fsnode_zone, np);
1770+     return (error);
1771+   }
1772+   vp = nvp;
1773+   bzero((caddr_t)np, sizeof *np);
1774+   vp->v_data = np;
1775+   np->n_vnode = vp;
1776+   /*
1777+    * Insert the u9fsnode in the hash queue for its new file handle
1778+    */
1779+   LIST_INSERT_HEAD(nhpp, np, n_hash);
1780+   np->n_qid.path = fh;
1781+   np->n_qid.vers = 0; /* not in cache yet */
1782+   np->n_fid = 0; /* should be set by the caller */
1783+   *npp = np;
1784+
1785+   if (u9fs_node_hash_lock < 0)
1786+     wakeup(&u9fs_node_hash_lock);
1787+   u9fs_node_hash_lock = 0;
1788+
1789+   /*
1790+    * Lock the new u9fsnode.
1791+    */
1792+   vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1793+
1794+   return (0);
1795+ }
1796diff -N -c -r /usr/src/sys/9fs/9fs_socket.c ./9fs/9fs_socket.c
1797*** /usr/src/sys/9fs/9fs_socket.c	Wed Dec 31 19:00:00 1969
1798--- ./9fs/9fs_socket.c	Thu Nov 25 15:48:46 1999
1799***************
1800*** 0 ****
1801--- 1,503 ----
1802+ #include <sys/param.h>
1803+ #include <sys/sockio.h>
1804+ #include <sys/proc.h>
1805+ #include <sys/vnode.h>
1806+ #include <sys/kernel.h>
1807+ #include <sys/sysctl.h>
1808+ #include <sys/malloc.h>
1809+ #include <sys/mount.h>
1810+ #include <sys/mbuf.h>
1811+ #include <sys/socket.h>
1812+ #include <sys/socketvar.h>
1813+ #include <sys/systm.h>
1814+ #include <sys/protosw.h>
1815+ #include <sys/syslog.h>
1816+
1817+ #include <netinet/in.h>
1818+ #include <netinet/tcp.h>
1819+
1820+ #include <vm/vm.h>
1821+ #include <vm/vm_extern.h>
1822+ #include <vm/vm_zone.h>
1823+
1824+ #include <net/if.h>
1825+ #include <net/route.h>
1826+ #include <netinet/in.h>
1827+
1828+ #include <9fs/bitstring.h>
1829+ #include <9fs/9p.h>
1830+ #include <9fs/9auth.h>
1831+ #include <9fs/9fs.h>
1832+
1833+ static int u9fs_reply __P((struct u9fsreq * req));
1834+ static int u9fs_send __P((struct socket * so, struct mbuf * mreq, struct u9fsreq * req));
1835+ static int u9fs_receive __P((struct socket * so, struct mbuf **mrep, struct u9fsreq * req));
1836+
1837+ static int u9fs_sndlock __P((int *flagp, int *statep, struct u9fsreq *rep));
1838+ static void u9fs_sndunlock __P((int *flagp, int *statep));
1839+ static int u9fs_rcvlock __P((struct u9fsreq *req));
1840+ static void u9fs_rcvunlock __P((int *flagp, int *statep));
1841+
1842+ int
1843+ u9fs_connect(struct socket ** sop, struct sockaddr * saddr, int sotype, int soproto, struct proc * p)
1844+ {
1845+   register struct socket * so;
1846+   int error, s;
1847+
1848+   *sop = 0;
1849+   error = socreate(saddr->sa_family, sop, sotype, soproto, p);
1850+   if( error )
1851+     return error;
1852+   so = *sop;
1853+   error = soconnect(so, saddr, p);
1854+   if( error )
1855+     return error;
1856+
1857+   /*
1858+    * Wait for the connection to complete. Cribbed from the
1859+    * connect system call but with the wait timing out so
1860+    * that interruptible mounts don't hang here for a long time.
1861+    */
1862+   s = splnet();
1863+   while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
1864+     (void) tsleep((caddr_t)&so->so_timeo, PSOCK,
1865+ 		  "u9fscon", 2 * hz);
1866+
1867+   if (so->so_error) {
1868+     error = so->so_error;
1869+     so->so_error = 0;
1870+     splx(s);
1871+     return error;
1872+   }
1873+   splx(s);
1874+
1875+   return (0);
1876+ }
1877+
1878+ int u9fs_connect_9auth(struct u9fsmount * nmp, struct u9fs_args * argp, struct socket ** sop)
1879+ {
1880+   int error;
1881+   struct proc * p = & proc0;
1882+   struct sockaddr *nam;
1883+
1884+   error = getsockaddr(&nam, (caddr_t)argp->authaddr, argp->authaddrlen);
1885+   if( error )
1886+     return error;
1887+   error = u9fs_connect(sop, nam, argp->authsotype,
1888+ 		       argp->authsoproto, p);
1889+   if( error == 0 )
1890+     return 0;
1891+
1892+   u9fs_disconnect(*sop);
1893+   *sop = 0;
1894+   return error;
1895+ }
1896+
1897+ /*
1898+  * Initialize sockets and congestion for a new U9FS connection.
1899+  * We do not free the sockaddr if error.
1900+  */
1901+ int
1902+ u9fs_connect_9fs(nmp)
1903+      register struct u9fsmount *nmp;
1904+ {
1905+   register struct socket *so;
1906+   int error, rcvreserve, sndreserve;
1907+   struct proc *p = &proc0; /* only used for socreate and sobind */
1908+
1909+   error = u9fs_connect(&nmp->nm_so, nmp->nm_nam, nmp->nm_sotype,
1910+ 		       nmp->nm_soproto, p);
1911+   if (error)
1912+     goto bad;
1913+   so = nmp->nm_so;
1914+   nmp->nm_soflags = so->so_proto->pr_flags;
1915+
1916+   if (nmp->nm_flag & (U9FSMNT_SOFT | U9FSMNT_INT)) {
1917+     so->so_rcv.sb_timeo = (5 * hz);
1918+     so->so_snd.sb_timeo = (5 * hz);
1919+   } else {
1920+     so->so_rcv.sb_timeo = 0;
1921+     so->so_snd.sb_timeo = 0;
1922+   }
1923+
1924+   /* XXX: i dont understand this, only one outstanding request? */
1925+   if (nmp->nm_sotype == SOCK_SEQPACKET) {
1926+     sndreserve = (nmp->nm_wsize) * 2;
1927+     rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize)) * 2;
1928+   } else {
1929+     if (nmp->nm_sotype != SOCK_STREAM)
1930+       panic("u9fscon sotype");
1931+     if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
1932+       struct sockopt sopt;
1933+       int val;
1934+
1935+       bzero(&sopt, sizeof sopt);
1936+       sopt.sopt_level = SOL_SOCKET;
1937+       sopt.sopt_name = SO_KEEPALIVE;
1938+       sopt.sopt_val = &val;
1939+       sopt.sopt_valsize = sizeof val;
1940+       val = 1;
1941+       sosetopt(so, &sopt);
1942+     }
1943+     if (so->so_proto->pr_protocol == IPPROTO_TCP) {
1944+       struct sockopt sopt;
1945+       int val;
1946+
1947+       bzero(&sopt, sizeof sopt);
1948+       sopt.sopt_level = IPPROTO_TCP;
1949+       sopt.sopt_name = TCP_NODELAY;
1950+       sopt.sopt_val = &val;
1951+       sopt.sopt_valsize = sizeof val;
1952+       val = 1;
1953+       sosetopt(so, &sopt);
1954+     }
1955+     sndreserve = (nmp->nm_wsize) * 2;
1956+     rcvreserve = (nmp->nm_rsize) * 2;
1957+   }
1958+   error = soreserve(so, sndreserve, rcvreserve);
1959+   if (error)
1960+     goto bad;
1961+   so->so_rcv.sb_flags |= SB_NOINTR;
1962+   so->so_snd.sb_flags |= SB_NOINTR;
1963+
1964+   /* Initialize other non-zero congestion variables */
1965+   nmp->nm_sent = 0;
1966+   return (0);
1967+
1968+ bad:
1969+   u9fs_disconnect(nmp->nm_so);
1970+   nmp->nm_so = 0;
1971+   return (error);
1972+ }
1973+
1974+ /*
1975+  * U9FS disconnect. Clean up and unlink.
1976+  */
1977+ void
1978+ u9fs_disconnect(struct socket * so)
1979+ {
1980+     soshutdown(so, 2);
1981+     soclose(so);
1982+ }
1983+
1984+ /*
1985+  * Lock a socket against others.
1986+  * Necessary for STREAM sockets to ensure you get an entire rpc request/reply
1987+  * and also to avoid race conditions between the processes with u9fs requests
1988+  * in progress when a reconnect is necessary.
1989+  */
1990+ static int
1991+ u9fs_sndlock(flagp, statep, rep)
1992+ 	register int *flagp;
1993+ 	register int *statep;
1994+ 	struct u9fsreq *rep;
1995+ {
1996+ 	struct proc *p;
1997+ 	int slpflag = 0, slptimeo = 0;
1998+
1999+ 	if (rep) {
2000+ 		p = rep->r_procp;
2001+ 		if (rep->r_nmp->nm_flag & U9FSMNT_INT)
2002+ 			slpflag = PCATCH;
2003+ 	} else
2004+ 		p = (struct proc *)0;
2005+ 	while (*statep & U9FSSTA_SNDLOCK) {
2006+ 		if (u9fs_sigintr(rep->r_nmp, p))
2007+ 			return (EINTR);
2008+ 		*statep |= U9FSSTA_WANTSND;
2009+ 		(void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1),
2010+ 			"u9fsndlck", slptimeo);
2011+ 		if (slpflag == PCATCH) {
2012+ 			slpflag = 0;
2013+ 			slptimeo = 2 * hz;
2014+ 		}
2015+ 	}
2016+ 	*statep |= U9FSSTA_SNDLOCK;
2017+ 	return (0);
2018+ }
2019+
2020+
2021+ /*
2022+  * Unlock the stream socket for others.
2023+  */
2024+ static void
2025+ u9fs_sndunlock(flagp, statep)
2026+ 	register int *flagp;
2027+ 	register int *statep;
2028+ {
2029+
2030+ 	if ((*statep & U9FSSTA_SNDLOCK) == 0)
2031+ 		panic("u9fs sndunlock");
2032+ 	*statep &= ~U9FSSTA_SNDLOCK;
2033+ 	if (*statep & U9FSSTA_WANTSND) {
2034+ 		*statep &= ~U9FSSTA_WANTSND;
2035+ 		wakeup((caddr_t)flagp);
2036+ 	}
2037+ }
2038+
2039+ /*
2040+  * Test for a termination condition pending on the process.
2041+  * This is used for U9FSMNT_INT mounts.
2042+  */
2043+ int
2044+ u9fs_sigintr(nmp, p)
2045+ 	struct u9fsmount *nmp;
2046+ 	struct proc * p;
2047+ {
2048+ 	if (!(nmp->nm_flag & U9FSMNT_INT))
2049+ 		return (0);
2050+ 	if (p && p->p_siglist &&
2051+ 	    (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) &
2052+ 	    U9FSINT_SIGMASK))
2053+ 		return (EINTR);
2054+ 	return (0);
2055+ }
2056+
2057+ /*
2058+  * This is the u9fs send routine. For connection based socket types, it
2059+  * must be called with an u9fs_sndlock() on the socket.
2060+  * "rep == NULL" indicates that it has been called from a server.
2061+  * For the client side:
2062+  * - return EINTR if the RPC is terminated, 0 otherwise
2063+  * - set R_MUSTRESEND if the send fails for any reason
2064+  * - do any cleanup required by recoverable socket errors (?)
2065+  * For the server side:
2066+  * - return EINTR or ERESTART if interrupted by a signal
2067+  * - return EPIPE if a connection is lost for connection based sockets (TCP...)
2068+  * - do any cleanup required by recoverable socket errors (?)
2069+  */
2070+ static int
2071+ u9fs_send(so, top, req)
2072+ 	register struct socket *so;
2073+ 	register struct mbuf *top;
2074+ 	struct u9fsreq *req;
2075+ {
2076+   int error, soflags, flags;
2077+
2078+   soflags = so->so_proto->pr_flags;
2079+   if (so->so_type == SOCK_SEQPACKET)
2080+     flags = MSG_EOR;
2081+   else
2082+     flags = 0;
2083+
2084+   error = so->so_proto->pr_usrreqs->pru_sosend(so, 0, 0, top, 0,
2085+ 					       flags, req->r_procp);
2086+   if (error)
2087+     log(LOG_INFO, "u9fs send error %d for server %s\n",error,
2088+ 	  req->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
2089+
2090+   return (error);
2091+ }
2092+
2093+ static int
2094+ u9fs_receive(so, mrep, req)
2095+      register struct socket * so;
2096+      struct mbuf **mrep;
2097+      struct u9fsreq * req;
2098+ {
2099+   struct uio auio;
2100+   u_int32_t len;
2101+   int error = 0, sotype, rcvflg;
2102+
2103+   /*
2104+    * Set up arguments for soreceive()
2105+    */
2106+   *mrep = (struct mbuf *)0;
2107+   sotype = req->r_nmp->nm_sotype;
2108+
2109+   /*
2110+    * For reliable protocols, lock against other senders/receivers
2111+    * in case a reconnect is necessary.
2112+    * For SOCK_STREAM, first get the Record Mark to find out how much
2113+    * more there is to get.
2114+    * We must lock the socket against other receivers
2115+    * until we have an entire rpc request/reply.
2116+    */
2117+   if (sotype == SOCK_SEQPACKET ) {
2118+     if( (so->so_state & SS_ISCONNECTED) == 0 )
2119+       return (EACCES);
2120+ 		auio.uio_resid = len = 1000000;
2121+ 		auio.uio_procp = req->r_procp;
2122+ 		do {
2123+ 			rcvflg = 0;
2124+ 			error =  so->so_proto->pr_usrreqs->pru_soreceive
2125+ 				(so, 0, &auio, mrep,
2126+ 				(struct mbuf **)0, &rcvflg);
2127+ 		} while (error == EWOULDBLOCK);
2128+ 		len -= auio.uio_resid;
2129+   }
2130+   if (error) {
2131+     m_freem(*mrep);
2132+     *mrep = (struct mbuf *)0;
2133+   }
2134+   return (error);
2135+ }
2136+
2137+ static int
2138+ u9fs_rcvlock(req)
2139+ 	register struct u9fsreq *req;
2140+ {
2141+ 	register int *flagp = &req->r_nmp->nm_flag;
2142+ 	register int *statep = &req->r_nmp->nm_state;
2143+ 	int slpflag, slptimeo = 0;
2144+
2145+ 	if (*flagp & U9FSMNT_INT)
2146+ 		slpflag = PCATCH;
2147+ 	else
2148+ 		slpflag = 0;
2149+ 	while (*statep & U9FSSTA_RCVLOCK) {
2150+ 		if (u9fs_sigintr(req->r_nmp, req->r_procp))
2151+ 			return (EINTR);
2152+ 		*statep |= U9FSSTA_WANTRCV;
2153+ 		(void) tsleep((caddr_t)flagp, slpflag | (PZERO - 1), "u9fsrcvlk",
2154+ 			slptimeo);
2155+ 		/*
2156+ 		 * If our reply was recieved while we were sleeping,
2157+ 		 * then just return without taking the lock to avoid a
2158+ 		 * situation where a single iod could 'capture' the
2159+ 		 * recieve lock.
2160+ 		 */
2161+ 		if (req->r_mrep != NULL)
2162+ 			return (EALREADY);
2163+ 		if (slpflag == PCATCH) {
2164+ 			slpflag = 0;
2165+ 			slptimeo = 2 * hz;
2166+ 		}
2167+ 	}
2168+ 	*statep |= U9FSSTA_RCVLOCK;
2169+ 	return (0);
2170+ }
2171+
2172+ /*
2173+  * Unlock the stream socket for others.
2174+  */
2175+ static void
2176+ u9fs_rcvunlock(flagp, statep)
2177+ 	register int *flagp;
2178+ 	register int *statep;
2179+ {
2180+
2181+ 	if ((*statep & U9FSSTA_RCVLOCK) == 0)
2182+ 		panic("u9fs rcvunlock");
2183+ 	*statep &= ~U9FSSTA_RCVLOCK;
2184+ 	if (*statep & U9FSSTA_WANTRCV) {
2185+ 		*statep &= ~U9FSSTA_WANTRCV;
2186+ 		wakeup((caddr_t)flagp);
2187+ 	}
2188+ }
2189+
2190+ /*
2191+  * Implement receipt of reply on a socket.
2192+  * We must search through the list of received datagrams matching them
2193+  * with outstanding requests using the xid, until ours is found.
2194+  */
2195+ /* ARGSUSED */
2196+ static
2197+ int u9fs_reply(struct u9fsreq * req)
2198+ {
2199+   int error;
2200+   struct mbuf * mrep;
2201+   register struct u9fsmount *nmp = req->r_nmp;
2202+   u_short tag;
2203+   struct u9fsreq * qp;
2204+
2205+   /*
2206+    * Loop around until we get our own reply
2207+    */
2208+   for (;;) {
2209+     /*
2210+      * Lock against other receivers so that I don't get stuck in
2211+      * sbwait() after someone else has received my reply for me.
2212+      * Also necessary for connection based protocols to avoid
2213+      * race conditions during a reconnect.
2214+      * If u9fs_rcvlock() returns EALREADY, that means that
2215+      * the reply has already been recieved by another
2216+      * process and we can return immediately.  In this
2217+      * case, the lock is not taken to avoid races with
2218+      * other processes.
2219+      */
2220+     error = u9fs_rcvlock(req);
2221+     if (error == EALREADY)
2222+       return (0);
2223+     if (error)
2224+       return (error);
2225+     /*
2226+      * Get the next Rpc reply off the socket
2227+      */
2228+     error = u9fs_receive(nmp->nm_so, &mrep, req);
2229+     u9fs_rcvunlock(&nmp->nm_flag, &nmp->nm_state);
2230+     if (error)
2231+       return (error);
2232+
2233+     /* extract the tag */
2234+     tag = u9p_m_tag(&mrep);
2235+
2236+     /*
2237+      * Loop through the request list to match up the reply
2238+      * Iff no match, just drop the datagram
2239+      */
2240+     for (qp = nmp->nm_reqq.tqh_first; qp != 0; qp = qp->r_chain.tqe_next) {
2241+       if ( qp->r_mrep == 0 && qp->r_tag == tag )
2242+ 	break;
2243+     }
2244+     if( qp == 0 ) {
2245+       m_freem(mrep);
2246+       continue;
2247+     }
2248+
2249+     if( u9p_m_m2s(&mrep, qp->r_rep) ) { /* freed by m2s */
2250+       continue;
2251+     }
2252+
2253+     qp->r_mrep = mrep;  /* should not be freed until the reply is read */
2254+
2255+     if( qp == req )
2256+       return 0;
2257+   }
2258+ }
2259+
2260+ int u9fs_request(struct u9fsreq * req, struct u9fsreq * rep, int relm)
2261+ {
2262+   struct mbuf * mreq;
2263+   int error,s;
2264+   struct u9fsmount * nmp;
2265+
2266+   req->r_rep = rep;
2267+   req->r_mrep = 0;
2268+   nmp = req->r_nmp;
2269+   req->r_tag = u9fs_id_new(nmp->nm_tags);
2270+
2271+   mreq = u9p_m_s2m(req);
2272+
2273+   /*
2274+    * Chain request into list of outstanding requests. Be sure
2275+    * to put it LAST so timer finds oldest requests first.
2276+    */
2277+   s = splsoftclock();
2278+   TAILQ_INSERT_TAIL(&nmp->nm_reqq, req, r_chain);
2279+   splx(s);
2280+
2281+   error = u9fs_send(nmp->nm_so, mreq, req);
2282+
2283+   if( !error )
2284+     error = u9fs_reply(req);
2285+
2286+   /*
2287+    * RPC done, unlink the request.
2288+    */
2289+   s = splsoftclock();
2290+   TAILQ_REMOVE(&nmp->nm_reqq, req, r_chain);
2291+   splx(s);
2292+
2293+   u9fs_id_free(nmp->nm_tags, req->r_tag);
2294+
2295+   if( !error && relm ) {
2296+ 	m_freem(req->r_mrep);
2297+ 	req->r_mrep = 0;
2298+   }
2299+   if( rep->r_type == Rerror )
2300+       error = EACCES;
2301+
2302+   return error;
2303+ }
2304+
2305diff -N -c -r /usr/src/sys/9fs/9fs_subr.c ./9fs/9fs_subr.c
2306*** /usr/src/sys/9fs/9fs_subr.c	Wed Dec 31 19:00:00 1969
2307--- ./9fs/9fs_subr.c	Fri Nov 26 12:28:17 1999
2308***************
2309*** 0 ****
2310--- 1,240 ----
2311+ #include <sys/param.h>
2312+ #include <sys/sockio.h>
2313+ #include <sys/proc.h>
2314+ #include <sys/vnode.h>
2315+ #include <sys/kernel.h>
2316+ #include <sys/sysctl.h>
2317+ #include <sys/malloc.h>
2318+ #include <sys/mount.h>
2319+ #include <sys/mbuf.h>
2320+ #include <sys/socket.h>
2321+ #include <sys/socketvar.h>
2322+ #include <sys/systm.h>
2323+ #include <sys/protosw.h>
2324+ #include <sys/syslog.h>
2325+
2326+ #include <netinet/in.h>
2327+ #include <netinet/tcp.h>
2328+
2329+ #include <vm/vm.h>
2330+ #include <vm/vm_extern.h>
2331+ #include <vm/vm_zone.h>
2332+
2333+ #include <net/if.h>
2334+ #include <net/route.h>
2335+ #include <netinet/in.h>
2336+
2337+ #include <9fs/bitstring.h>
2338+ #include <9fs/9p.h>
2339+ #include <9fs/9auth.h>
2340+ #include <9fs/9fs.h>
2341+
2342+ vm_zone_t u9fsuser_zone;
2343+ LIST_HEAD(u9fsuserhashhead, u9fsuser) * u9fsuidhashtbl, * u9fsunamehashtbl;
2344+ u_long u9fsuidhash;
2345+ u_long u9fsunamehash;
2346+ MALLOC_DEFINE(M_U9FSBITS, "U9FS bits", "U9FS tag/fid maps");
2347+
2348+ static int   u9fs_hashname __P((char * name));
2349+
2350+ void u9fs_uhinit()
2351+ {
2352+   u9fsuser_zone = zinit("U9FSUSER", sizeof(struct u9fsuser), 0, 0, 1);
2353+   u9fsuidhashtbl   = phashinit(U9FS_USER_HASHSIZE, M_U9FSHASH, &u9fsuidhash);
2354+   u9fsunamehashtbl = phashinit(U9FS_USER_HASHSIZE, M_U9FSHASH, &u9fsunamehash);
2355+ }
2356+
2357+ void
2358+ u9fs_id_init(bits)
2359+      bitstr_t ** bits;
2360+ {
2361+   bit_alloc(*bits, 0x10000, M_U9FSBITS, M_WAITOK);
2362+   bit_nset(*bits, 1, 0xffff);  /* we dont use zero */
2363+ }
2364+
2365+ u_short
2366+ u9fs_id_new(bits)
2367+      bitstr_t * bits;
2368+ {
2369+   int v;
2370+
2371+   bit_ffs(bits, 0x10000, &v);
2372+   if( v < 0 )
2373+     panic("no more u9fs bits!");
2374+
2375+   bit_clear(bits, v);
2376+   return ((u_short)v);
2377+ }
2378+
2379+ void
2380+ u9fs_id_free(bits, v)
2381+      bitstr_t * bits;
2382+      u_short v;
2383+ {
2384+   bit_set(bits, v);
2385+ }
2386+
2387+
2388+ static int u9fs_hashname(char * cp)
2389+ {
2390+   int h = 0;
2391+
2392+   cp[U9FS_NAMELEN-1] = 0;
2393+   do
2394+     h += *cp;
2395+   while ( *cp++ );
2396+
2397+   return h;
2398+ }
2399+
2400+ void u9fs_hashuser(uid_t uid, char * name)
2401+ {
2402+   int h;
2403+   struct u9fsuser * u9p, *u9p2;
2404+   struct u9fsuserhashhead * u9hp;
2405+
2406+   if( u9fs_name2uid(name) != 65534 ) /* already hashed by previous mount */
2407+     return;
2408+
2409+   u9p = zalloc(u9fsuser_zone);
2410+   bzero(u9p, sizeof(*u9p));
2411+   u9p->u_uid = uid;
2412+   strncpy(u9p->u_name, name, U9FS_NAMELEN);
2413+   u9hp = & u9fsuidhashtbl[uid % u9fsuidhash];
2414+   LIST_INSERT_HEAD(u9hp, u9p, u_hash);
2415+
2416+   u9p2 = zalloc(u9fsuser_zone);
2417+   bcopy(u9p, u9p2, sizeof(*u9p));
2418+   h = u9fs_hashname(name);
2419+   u9hp = & u9fsunamehashtbl[h%u9fsunamehash];
2420+   LIST_INSERT_HEAD(u9hp, u9p2, u_hash);
2421+ }
2422+
2423+ /* name must be at least U9FS_NAMELEN long! */
2424+ struct u9fsuser * u9fs_finduser(uid_t uid)
2425+ {
2426+   struct u9fsuser * u9p;
2427+   struct u9fsuserhashhead * u9hp;
2428+
2429+   u9hp = & u9fsuidhashtbl[uid % u9fsuidhash];
2430+   LIST_FOREACH(u9p, u9hp, u_hash)
2431+     if( u9p->u_uid == uid )
2432+       break;
2433+
2434+   return u9p;
2435+ }
2436+
2437+ uid_t u9fs_name2uid(char *name)
2438+ {
2439+   struct u9fsuser * u9p;
2440+   struct u9fsuserhashhead * u9hp;
2441+   int h;
2442+
2443+   h = u9fs_hashname(name);
2444+   u9hp = & u9fsunamehashtbl[h%u9fsunamehash];
2445+   LIST_FOREACH(u9p, u9hp, u_hash)
2446+     if( strcmp(u9p->u_name, name) == 0 )
2447+       break;
2448+
2449+   if( u9p )
2450+     return u9p->u_uid;
2451+   else
2452+     return 65534; /* nobody */
2453+ }
2454+
2455+ /*
2456+  * copies a uio scatter/gather list to an mbuf chain.
2457+  */
2458+ int
2459+ u9fs_uiotombuf(uiop, mq, siz)
2460+ 	register struct uio *uiop;
2461+ 	struct mbuf **mq;
2462+ 	int siz;
2463+ {
2464+   register struct mbuf *m;
2465+   struct mbuf * top, **mp;
2466+   int mlen, len, error = 0;
2467+
2468+   mp = & top;
2469+   while(siz) {
2470+     MGET(m, M_WAIT, MT_DATA);
2471+     mlen = MLEN;
2472+     if (siz >= MINCLSIZE) {
2473+       MCLGET(m, M_WAIT);
2474+       if ((m->m_flags & M_EXT))
2475+ 	mlen = MCLBYTES;
2476+     }
2477+     len = min(mlen, siz);
2478+     error = uiomove(mtod(m, caddr_t), (int)len, uiop);
2479+     siz -= len;
2480+     m->m_len = len;
2481+     *mp = m;
2482+     if (error)
2483+       goto release;
2484+     mp = &m->m_next;
2485+   }
2486+   *mq = top;
2487+   return 0;
2488+
2489+  release:
2490+   if( top )
2491+     m_freem(top);
2492+
2493+   return error;
2494+ }
2495+
2496+ /*
2497+  * copies mbuf chain to the uio scatter/gather list
2498+  */
2499+ int
2500+ u9fs_mbuftouio(m, uiop, siz)
2501+      struct mbuf *m;
2502+      register struct uio *uiop;
2503+      int siz;
2504+ {
2505+   register char *mbufcp, *uiocp;
2506+   register int xfer, left, len;
2507+   long uiosiz;
2508+
2509+   mbufcp = mtod(m, char *);
2510+   len = m->m_len;
2511+   while (siz > 0) {
2512+     if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
2513+       return (EFBIG);
2514+     left = uiop->uio_iov->iov_len;
2515+     uiocp = uiop->uio_iov->iov_base;
2516+     if (left > siz)
2517+       left = siz;
2518+     uiosiz = left;
2519+     while (left > 0) {
2520+       while (len == 0) {
2521+ 	m = m->m_next;
2522+ 	if (m == NULL)
2523+ 	  return (EBADRPC);
2524+ 	mbufcp = mtod(m, caddr_t);
2525+ 	len = m->m_len;
2526+       }
2527+       xfer = (left > len) ? len : left;
2528+       if (uiop->uio_segflg == UIO_SYSSPACE)
2529+ 	bcopy(mbufcp, uiocp, xfer);
2530+       else
2531+ 	copyout(mbufcp, uiocp, xfer);
2532+       left -= xfer;
2533+       len -= xfer;
2534+       mbufcp += xfer;
2535+       uiocp += xfer;
2536+       uiop->uio_offset += xfer;
2537+       uiop->uio_resid -= xfer;
2538+     }
2539+     if (uiop->uio_iov->iov_len <= siz) {
2540+       uiop->uio_iovcnt--;
2541+       uiop->uio_iov++;
2542+     } else {
2543+       uiop->uio_iov->iov_base += uiosiz;
2544+       uiop->uio_iov->iov_len -= uiosiz;
2545+     }
2546+     siz -= uiosiz;
2547+   }
2548+   return (0);
2549+ }
2550+
2551diff -N -c -r /usr/src/sys/9fs/9fs_vfsops.c ./9fs/9fs_vfsops.c
2552*** /usr/src/sys/9fs/9fs_vfsops.c	Wed Dec 31 19:00:00 1969
2553--- ./9fs/9fs_vfsops.c	Mon May 22 16:33:47 2000
2554***************
2555*** 0 ****
2556--- 1,639 ----
2557+ /*
2558+  * Copyright (c) 1989, 1993, 1995
2559+  *	The Regents of the University of California.  All rights reserved.
2560+  *
2561+  * This code is derived from software contributed to Berkeley by
2562+  * Rick Macklem at The University of Guelph.
2563+  *
2564+  * Redistribution and use in source and binary forms, with or without
2565+  * modification, are permitted provided that the following conditions
2566+  * are met:
2567+  * 1. Redistributions of source code must retain the above copyright
2568+  *    notice, this list of conditions and the following disclaimer.
2569+  * 2. Redistributions in binary form must reproduce the above copyright
2570+  *    notice, this list of conditions and the following disclaimer in the
2571+  *    documentation and/or other materials provided with the distribution.
2572+  * 3. All advertising materials mentioning features or use of this software
2573+  *    must display the following acknowledgement:
2574+  *	This product includes software developed by the University of
2575+  *	California, Berkeley and its contributors.
2576+  * 4. Neither the name of the University nor the names of its contributors
2577+  *    may be used to endorse or promote products derived from this software
2578+  *    without specific prior written permission.
2579+  *
2580+  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2581+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2582+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2583+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2584+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2585+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2586+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2587+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2588+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2589+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2590+  * SUCH DAMAGE.
2591+  *
2592+  *	@(#)u9fs_vfsops.c	8.12 (Berkeley) 5/20/95
2593+  * $Id: u9fs_vfsops.c,v 1.79 1998/12/04 22:54:54 archie Exp $
2594+  */
2595+
2596+ #include <sys/param.h>
2597+ #include <sys/sockio.h>
2598+ #include <sys/proc.h>
2599+ #include <sys/vnode.h>
2600+ #include <sys/kernel.h>
2601+ #include <sys/sysctl.h>
2602+ #include <sys/malloc.h>
2603+ #include <sys/mount.h>
2604+ #include <sys/mbuf.h>
2605+ #include <sys/socket.h>
2606+ #include <sys/socketvar.h>
2607+ #include <sys/systm.h>
2608+ #include <sys/protosw.h>
2609+ #include <sys/syslog.h>
2610+
2611+ #include <netinet/in.h>
2612+ #include <netinet/tcp.h>
2613+
2614+ #include <vm/vm.h>
2615+ #include <vm/vm_extern.h>
2616+ #include <vm/vm_zone.h>
2617+
2618+ #include <net/if.h>
2619+ #include <net/route.h>
2620+ #include <netinet/in.h>
2621+
2622+ #include <9fs/bitstring.h>
2623+ #include <9fs/9p.h>
2624+ #include <9fs/9auth.h>
2625+ #include <9fs/9fs.h>
2626+
2627+ vm_zone_t u9fsmount_zone;
2628+
2629+ static int	u9fs_mount __P(( struct mount *mp, char *path, caddr_t data,
2630+ 			struct nameidata *ndp, struct proc *p));
2631+ static int	u9fs_start __P(( struct mount *mp, int flags,
2632+ 			struct proc *p));
2633+ static int	u9fs_unmount __P(( struct mount *mp, int mntflags,
2634+ 			struct proc *p));
2635+ static int	u9fs_root __P(( struct mount *mp, struct vnode **vpp));
2636+ static int	u9fs_quotactl __P(( struct mount *mp, int cmds, uid_t uid,
2637+ 			caddr_t arg, struct proc *p));
2638+ static int	u9fs_statfs __P(( struct mount *mp, struct statfs *sbp,
2639+ 			struct proc *p));
2640+ static int	u9fs_sync __P(( struct mount *mp, int waitfor,
2641+ 			struct ucred *cred, struct proc *p));
2642+ static int	u9fs_vptofh __P(( struct vnode *vp, struct fid *fhp));
2643+ static int	u9fs_fhtovp __P((struct mount *mp, struct fid *fhp,
2644+ 			struct sockaddr *nam, struct vnode **vpp,
2645+ 			int *exflagsp, struct ucred **credanonp));
2646+ static int	u9fs_vget __P((struct mount *, ino_t, struct vnode **));
2647+ static int      u9fs_init __P((struct vfsconf *vfsp));
2648+ int             u9fs_uninit __P((struct vfsconf *vfsp));
2649+
2650+ /* */
2651+ static int	mountu9fs __P((struct u9fs_args *,struct mount *,
2652+ 			struct sockaddr *,char *,char *,struct vnode **, struct proc *p));
2653+ static int	u9fs_iosize __P((struct u9fsmount *nmp));
2654+ static void	u9fs_decode_args __P((struct u9fsmount *nmp, struct u9fs_args *argp, struct proc *p));
2655+
2656+ /*
2657+  * u9fs vfs operations.
2658+  */
2659+ static struct vfsops u9fs_vfsops = {
2660+ 	u9fs_mount,
2661+ 	u9fs_start,
2662+ 	u9fs_unmount,
2663+ 	u9fs_root,
2664+ 	u9fs_quotactl,
2665+ 	u9fs_statfs,
2666+ 	u9fs_sync,
2667+ 	u9fs_vget,
2668+ 	u9fs_fhtovp,
2669+ 	u9fs_vptofh,
2670+ 	u9fs_init,
2671+ 	u9fs_uninit,
2672+ 	0
2673+ };
2674+ VFS_SET(u9fs_vfsops, u9fs, VFCF_NETWORK);
2675+
2676+ /*
2677+  * u9fs statfs call
2678+  */
2679+ static int
2680+ u9fs_statfs(mp, sbp, p)
2681+ 	struct mount *mp;
2682+ 	register struct statfs *sbp;
2683+ 	struct proc *p;
2684+ {
2685+   /* we have a worm with infinite storage,
2686+      stat not supported by 9fs */
2687+   return 0;
2688+ }
2689+
2690+ /*
2691+  * Common code for mount and mountroot
2692+  */
2693+ static int
2694+ mountu9fs(argp, mp, nam, pth, hst, vpp, p)
2695+ 	register struct u9fs_args *argp;
2696+ 	register struct mount *mp;
2697+ 	struct sockaddr *nam;
2698+ 	char *pth, *hst;
2699+ 	struct vnode **vpp;
2700+ 	struct proc *p;
2701+ {
2702+   register struct u9fsmount *nmp;
2703+   struct u9fsnode *np;
2704+   int error;
2705+   struct vattr attrs;
2706+   struct u9fsreq req, rep;
2707+   char * mntpoint;
2708+   struct u9fsuser * u9p;
2709+   struct socket * so;
2710+
2711+   if (mp->mnt_flag & MNT_UPDATE) {
2712+ #if 0
2713+     nmp = VFSTONFS(mp);
2714+ <    /* update paths, file handles, etc, here	XXX */
2715+     FREE(nam, M_SONAME);
2716+ #endif
2717+     return (0);
2718+   } else {
2719+     nmp = zalloc(u9fsmount_zone);
2720+     bzero((caddr_t)nmp, sizeof (struct u9fsmount));
2721+ #if 0
2722+     TAILQ_INIT(&nmp->nm_uidlruhead);
2723+     TAILQ_INIT(&nmp->nm_bufq);
2724+ #endif
2725+     mp->mnt_data = (qaddr_t)nmp;
2726+   }
2727+   vfs_getnewfsid(mp);
2728+   nmp->nm_mountp = mp;
2729+
2730+   nmp->nm_maxfilesize = (u_int64_t)0xffffffffffffffffLL;
2731+
2732+   nmp->nm_wsize = U9FS_MAXFDATA;
2733+   nmp->nm_rsize = U9FS_MAXFDATA;
2734+   nmp->nm_readdirsize = U9FS_MAXDDATA;
2735+   bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
2736+   bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
2737+   nmp->nm_nam = nam;
2738+
2739+   mntpoint = index(hst, '/');
2740+   if( mntpoint )
2741+     mntpoint++;
2742+
2743+   /* Set up the sockets and per-host congestion */
2744+   nmp->nm_sotype = argp->sotype;
2745+   nmp->nm_soproto = argp->proto;
2746+
2747+   u9fs_decode_args(nmp, argp, p);
2748+
2749+   lockinit(& nmp->nm_lock, PVFS, "u9fsmount", 0, 0);
2750+   u9fs_id_init(&nmp->nm_tags);
2751+   u9fs_id_init(&nmp->nm_fids);
2752+   TAILQ_INIT(&nmp->nm_reqq);
2753+
2754+   if ((error = u9fs_connect_9fs(nmp)))
2755+     goto bad;
2756+
2757+   /* "Tnop 1", "Tsession 1 0", "Tattach 1 1 none main 0 0", */
2758+   bzero(&req, sizeof(req));
2759+   req.r_nmp = nmp;
2760+   req.r_procp = p;
2761+
2762+   req.r_type = Tnop;
2763+   error = u9fs_request(& req, & rep, 1);
2764+   if( error )
2765+     return error;
2766+
2767+   req.r_type = Tsession;
2768+   /* bzero(req.r_chal, sizeof(req.r_chal)); */
2769+   u9auth_genchal(req.r_chal);
2770+   error = u9fs_request(& req, & rep, 1);
2771+   if( error )
2772+     return error;
2773+
2774+   if( argp->authaddr ) {
2775+     /* get tickets from the auth server */
2776+     error = u9fs_connect_9auth(nmp, argp, & so);
2777+     if( error )
2778+       goto bad;
2779+     u9p = u9fs_finduser(u9fs_name2uid(argp->user));
2780+     error = u9auth_gettickets(so, & rep, argp->user, u9p->u_ckey,
2781+ 			      req.r_ticket, req.r_auth, p);
2782+     u9fs_disconnect(so);
2783+     if( error )
2784+       goto bad;
2785+   }
2786+
2787+   req.r_type = Tattach;
2788+   req.r_fid = u9fs_id_new(nmp->nm_fids);
2789+   strcpy(req.r_uname, argp->user);
2790+   strcpy(req.r_aname, mntpoint);
2791+   error = u9fs_request(& req, & rep, 1);
2792+   if( error )
2793+     return error;
2794+   nmp->nm_fh = rep.r_qid.path;
2795+   nmp->nm_fid = req.r_fid;
2796+   /* XXX: we should have checked our challenge to the server! */
2797+
2798+   /*
2799+    * This is silly, but it has to be set so that vinifod() works.
2800+    * We do not want to do an u9fs_statfs() here since we can get
2801+    * stuck on a dead server and we are holding a lock on the mount
2802+    * point.
2803+    */
2804+   mp->mnt_stat.f_iosize = u9fs_iosize(nmp);
2805+
2806+   /*
2807+    * A reference count is needed on the u9fsnode representing the
2808+    * remote root.  If this object is not persistent, then backward
2809+    * traversals of the mount point (i.e. "..") will not work if
2810+    * the u9fsnode gets flushed out of the cache. Ufs does not have
2811+    * this problem, because one can identify root inodes by their
2812+    * number == ROOTINO (2).
2813+    */
2814+   error = u9fs_nget(mp, nmp->nm_fh, &np, p);
2815+   np->n_fid = nmp->nm_fid;
2816+
2817+   nmp->nm_authuid = p->p_ucred->cr_uid;
2818+
2819+   if (error)
2820+     goto bad;
2821+   *vpp = U9FSTOV(np);
2822+
2823+   /*
2824+    * Get file attributes for the mountpoint.  This has the side
2825+    * effect of filling in (*vpp)->v_type with the correct value.
2826+    */
2827+   VOP_GETATTR(*vpp, &attrs, p->p_ucred, p);
2828+
2829+   /*
2830+    * Lose the lock but keep the ref.
2831+    */
2832+   VOP_UNLOCK(*vpp, 0, p);
2833+
2834+   return (0);
2835+ bad:
2836+   u9fs_disconnect(nmp->nm_so);
2837+   zfree(u9fsmount_zone, nmp);
2838+   FREE(nam, M_SONAME);
2839+   return (error);
2840+ }
2841+
2842+ /*
2843+  * VFS Operations.
2844+  *
2845+  * mount system call
2846+  * It seems a bit dumb to copyinstr() the host and path here and then
2847+  * bcopy() them in mountu9fs(), but I wanted to detect errors before
2848+  * doing the sockargs() call because sockargs() allocates an mbuf and
2849+  * an error after that means that I have to release the mbuf.
2850+  */
2851+ /* ARGSUSED */
2852+ static int
2853+ u9fs_mount(mp, path, data, ndp, p)
2854+ 	struct mount *mp;
2855+ 	char *path;
2856+ 	caddr_t data;
2857+ 	struct nameidata *ndp;
2858+ 	struct proc *p;
2859+ {
2860+   int error;
2861+   struct u9fs_args args;
2862+   struct sockaddr *nam;
2863+   struct vnode *vp;
2864+   char pth[MNAMELEN], hst[MNAMELEN];
2865+   size_t len;
2866+
2867+   if( path == NULL )
2868+     return (EOPNOTSUPP);
2869+
2870+   error = copyin(data, (caddr_t)&args, sizeof (struct u9fs_args));
2871+   if (error)
2872+     return (error);
2873+
2874+   if (args.version != U9FS_ARGSVERSION)
2875+     return (EPROGMISMATCH);
2876+
2877+   if (mp->mnt_flag & MNT_UPDATE) {
2878+ #if 0
2879+     register struct u9fsmount *nmp = VFSTONFS(mp);
2880+
2881+     if (nmp == NULL)
2882+       return (EIO);
2883+     /*
2884+      * When doing an update, we can't change from or to
2885+      * v3 and/or nqu9fs, or change cookie translation
2886+      */
2887+     args.flags = (args.flags &
2888+ 		  ~(NFSMNT_NFSV3|NFSMNT_NQNFS /*|NFSMNT_XLATECOOKIE*/)) |
2889+       (nmp->nm_flag &
2890+        (NFSMNT_NFSV3|NFSMNT_NQNFS /*|NFSMNT_XLATECOOKIE*/));
2891+     u9fs_decode_args(nmp, &args, p);
2892+ #endif
2893+     return (0);
2894+   }
2895+
2896+   error = copyinstr(path, pth, MNAMELEN-1, &len);
2897+   if (error)
2898+     return (error);
2899+   bzero(&pth[len], MNAMELEN - len);
2900+   error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
2901+   if (error)
2902+     return (error);
2903+   bzero(&hst[len], MNAMELEN - len);
2904+   /* sockargs() call must be after above copyin() calls */
2905+   error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
2906+   if (error)
2907+     return (error);
2908+   error = mountu9fs(&args, mp, nam, pth, hst, &vp, p);
2909+   return (error);
2910+ }
2911+
2912+ /*
2913+  * unmount system call
2914+  */
2915+ static int
2916+ u9fs_unmount(mp, mntflags, p)
2917+      struct mount *mp;
2918+      int mntflags;
2919+      struct proc *p;
2920+ {
2921+   register struct u9fsmount *nmp;
2922+   struct u9fsnode *np;
2923+   struct vnode *vp;
2924+   int error, flags = 0;
2925+
2926+   if (mntflags & MNT_FORCE)
2927+     flags |= FORCECLOSE;
2928+   nmp = VFSTOU9FS(mp);
2929+
2930+   if( p->p_ucred->cr_uid != nmp->nm_authuid )
2931+     return (EPERM);
2932+
2933+   /*
2934+    * Goes something like this..
2935+    * - Check for activity on the root vnode (other than ourselves).
2936+    * - Call vflush() to clear out vnodes for this file system,
2937+    *   except for the root vnode.
2938+    * - Decrement reference on the vnode representing remote root.
2939+    * - Close the socket
2940+    * - Free up the data structures
2941+    */
2942+   /*
2943+    * We need to decrement the ref. count on the u9fsnode representing
2944+    * the remote root.  See comment in mountu9fs().  The VFS unmount()
2945+    * has done vput on this vnode, otherwise we would get deadlock!
2946+    */
2947+   error = u9fs_nget(mp, nmp->nm_fh, &np, p);
2948+   if (error)
2949+     return(error);
2950+   vp = U9FSTOV(np);
2951+   if (vp->v_usecount > 2) {
2952+     vput(vp);
2953+     return (EBUSY);
2954+   }
2955+
2956+   error = vflush(mp, vp, flags);
2957+   if (error) {
2958+     vput(vp);
2959+     return (error);
2960+   }
2961+
2962+   /*
2963+    * We are now committed to the unmount.
2964+    */
2965+   /*
2966+    * There are two reference counts and one lock to get rid of here.
2967+    */
2968+   vput(vp);
2969+   vrele(vp);
2970+   vgone(vp);
2971+   u9fs_disconnect(nmp->nm_so);
2972+   FREE(nmp->nm_nam, M_SONAME);
2973+
2974+   zfree(u9fsmount_zone, nmp);
2975+   return (0);
2976+ }
2977+
2978+ /*
2979+  * Return root of a filesystem
2980+  */
2981+ static int
2982+ u9fs_root(mp, vpp)
2983+ 	struct mount *mp;
2984+ 	struct vnode **vpp;
2985+ {
2986+         register struct vnode *vp;
2987+         struct u9fsmount *nmp;
2988+         struct u9fsnode *np;
2989+         int error;
2990+
2991+         nmp = VFSTOU9FS(mp);
2992+         error = u9fs_nget(mp, nmp->nm_fh, &np, curproc); /* XXX */
2993+         if (error)
2994+                 return (error);
2995+         vp = U9FSTOV(np);
2996+         if (vp->v_type == VNON)
2997+             vp->v_type = VDIR;
2998+         vp->v_flag = VROOT;
2999+         *vpp = vp;
3000+         return (0);
3001+ }
3002+
3003+ extern int syncprt;
3004+
3005+ /*
3006+  * Flush out the buffer cache
3007+  */
3008+ /* ARGSUSED */
3009+ static int
3010+ u9fs_sync(mp, waitfor, cred, p)
3011+ 	struct mount *mp;
3012+ 	int waitfor;
3013+ 	struct ucred *cred;
3014+ 	struct proc *p;
3015+ {
3016+   /* no cache yet */
3017+   return 0;
3018+ }
3019+
3020+ /*
3021+  * U9FS flat namespace lookup.
3022+  * Currently unsupported.
3023+  */
3024+ /* ARGSUSED */
3025+ static int
3026+ u9fs_vget(mp, ino, vpp)
3027+ 	struct mount *mp;
3028+ 	ino_t ino;
3029+ 	struct vnode **vpp;
3030+ {
3031+
3032+ 	return (EOPNOTSUPP);
3033+ }
3034+
3035+ /*
3036+  * At this point, this should never happen
3037+  */
3038+ /* ARGSUSED */
3039+ static int
3040+ u9fs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
3041+ 	register struct mount *mp;
3042+ 	struct fid *fhp;
3043+ 	struct sockaddr *nam;
3044+ 	struct vnode **vpp;
3045+ 	int *exflagsp;
3046+ 	struct ucred **credanonp;
3047+ {
3048+
3049+ 	return (EINVAL);
3050+ }
3051+
3052+ /*
3053+  * Vnode pointer to File handle, should never happen either
3054+  */
3055+ /* ARGSUSED */
3056+ static int
3057+ u9fs_vptofh(vp, fhp)
3058+ 	struct vnode *vp;
3059+ 	struct fid *fhp;
3060+ {
3061+
3062+ 	return (EINVAL);
3063+ }
3064+
3065+ /*
3066+  * Vfs start routine, a no-op.
3067+  */
3068+ /* ARGSUSED */
3069+ static int
3070+ u9fs_start(mp, flags, p)
3071+ 	struct mount *mp;
3072+ 	int flags;
3073+ 	struct proc *p;
3074+ {
3075+
3076+ 	return (0);
3077+ }
3078+
3079+ /*
3080+  * Do operations associated with quotas, not supported
3081+  */
3082+ /* ARGSUSED */
3083+ static int
3084+ u9fs_quotactl(mp, cmd, uid, arg, p)
3085+ 	struct mount *mp;
3086+ 	int cmd;
3087+ 	uid_t uid;
3088+ 	caddr_t arg;
3089+ 	struct proc *p;
3090+ {
3091+
3092+ 	return (EOPNOTSUPP);
3093+ }
3094+
3095+ /*
3096+  * Called once to initialize data structures...
3097+  */
3098+ int
3099+ u9fs_init(vfsp)
3100+ 	struct vfsconf *vfsp;
3101+ {
3102+   u9fsmount_zone = zinit("U9FSMOUNT", sizeof(struct u9fsmount), 0, 0, 1);
3103+   u9fs_nhinit();			/* Init the u9fsnode table */
3104+   u9fs_uhinit();
3105+   return 0;
3106+ }
3107+
3108+ int
3109+ u9fs_uninit(vfsp)
3110+ 	struct vfsconf *vfsp;
3111+ {
3112+   return 0;
3113+ }
3114+
3115+ static int
3116+ u9fs_iosize(nmp)
3117+      struct u9fsmount* nmp;
3118+ {
3119+   int iosize;
3120+
3121+   /*
3122+    * Calculate the size used for io buffers.  Use the larger
3123+    * of the two sizes to minimise u9fs requests but make sure
3124+    * that it is at least one VM page to avoid wasting buffer
3125+    * space.
3126+    */
3127+   iosize = max(nmp->nm_rsize, nmp->nm_wsize);
3128+   if (iosize < PAGE_SIZE) iosize = PAGE_SIZE;
3129+   return iosize;
3130+ }
3131+
3132+ static void
3133+ u9fs_decode_args(nmp, argp, p)
3134+      struct u9fsmount *nmp;
3135+      struct u9fs_args *argp;
3136+      struct proc * p;
3137+ {
3138+   int s, i;
3139+   int maxio;
3140+   struct p9user * p9p, p9u;
3141+   struct u9fsuser * u9p;
3142+
3143+   s = splnet();
3144+   /* Update flags atomically.  Don't change the lock bits. */
3145+   nmp->nm_flag = argp->flags | nmp->nm_flag;
3146+   splx(s);
3147+
3148+   maxio = U9FS_MAXFDATA;
3149+
3150+   if (argp->wsize > 0) {
3151+     nmp->nm_wsize = argp->wsize;
3152+     /* Round down to multiple of blocksize */
3153+     nmp->nm_wsize &= ~(U9FS_FABLKSIZE - 1);
3154+     if (nmp->nm_wsize <= 0)
3155+       nmp->nm_wsize = U9FS_FABLKSIZE;
3156+   }
3157+   if (nmp->nm_wsize > maxio)
3158+     nmp->nm_wsize = maxio;
3159+   if (nmp->nm_wsize > MAXBSIZE)
3160+     nmp->nm_wsize = MAXBSIZE;
3161+
3162+   if (argp->rsize > 0) {
3163+     nmp->nm_rsize = argp->rsize;
3164+     /* Round down to multiple of blocksize */
3165+     nmp->nm_rsize &= ~(U9FS_FABLKSIZE - 1);
3166+     if (nmp->nm_rsize <= 0)
3167+       nmp->nm_rsize = U9FS_FABLKSIZE;
3168+   }
3169+   if (nmp->nm_rsize > maxio)
3170+     nmp->nm_rsize = maxio;
3171+   if (nmp->nm_rsize > MAXBSIZE)
3172+     nmp->nm_rsize = MAXBSIZE;
3173+
3174+   if (argp->readdirsize > 0) {
3175+     nmp->nm_readdirsize = argp->readdirsize;
3176+   }
3177+   if (nmp->nm_readdirsize > maxio)
3178+     nmp->nm_readdirsize = maxio;
3179+   if (nmp->nm_readdirsize > nmp->nm_rsize)
3180+     nmp->nm_readdirsize = nmp->nm_rsize;
3181+
3182+   if( argp->nusers ) {
3183+     p9p = argp->users;
3184+     for(i = 0; i < argp->nusers; i++) {
3185+       copyin(p9p, &p9u, sizeof(p9u));
3186+       u9fs_hashuser(p9u.p9_uid, p9u.p9_name);
3187+       p9p ++;
3188+     }
3189+     printf("%d p9users loaded\n", argp->nusers);
3190+   }
3191+
3192+   if( (u9p = u9fs_finduser(u9fs_name2uid(argp->user))) ) {
3193+     bcopy(argp->key, u9p->u_ckey, U9AUTH_DESKEYLEN);
3194+   }
3195+ }
3196diff -N -c -r /usr/src/sys/9fs/9fs_vnops.c ./9fs/9fs_vnops.c
3197*** /usr/src/sys/9fs/9fs_vnops.c	Wed Dec 31 19:00:00 1969
3198--- ./9fs/9fs_vnops.c	Mon May 22 11:40:00 2000
3199***************
3200*** 0 ****
3201--- 1,1794 ----
3202+ /*
3203+  * Copyright (c) 1989, 1993
3204+  *	The Regents of the University of California.  All rights reserved.
3205+  *
3206+  * This code is derived from software contributed to Berkeley by
3207+  * Rick Macklem at The University of Guelph.
3208+  *
3209+  * Redistribution and use in source and binary forms, with or without
3210+  * modification, are permitted provided that the following conditions
3211+  * are met:
3212+  * 1. Redistributions of source code must retain the above copyright
3213+  *    notice, this list of conditions and the following disclaimer.
3214+  * 2. Redistributions in binary form must reproduce the above copyright
3215+  *    notice, this list of conditions and the following disclaimer in the
3216+  *    documentation and/or other materials provided with the distribution.
3217+  * 3. All advertising materials mentioning features or use of this software
3218+  *    must display the following acknowledgement:
3219+  *	This product includes software developed by the University of
3220+  *	California, Berkeley and its contributors.
3221+  * 4. Neither the name of the University nor the names of its contributors
3222+  *    may be used to endorse or promote products derived from this software
3223+  *    without specific prior written permission.
3224+  *
3225+  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3226+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3227+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3228+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3229+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3230+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3231+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3232+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3233+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3234+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3235+  * SUCH DAMAGE.
3236+  *
3237+  *	@(#)u9fs_vnops.c	8.16 (Berkeley) 5/27/95
3238+  * $Id: u9fs_vnops.c,v 1.116.2.3 1999/02/13 08:03:47 dillon Exp $
3239+  */
3240+
3241+
3242+ /*
3243+  * vnode op calls for 9FS
3244+  */
3245+
3246+ #include "opt_inet.h"
3247+
3248+ #include <sys/param.h>
3249+ #include <sys/kernel.h>
3250+ #include <sys/systm.h>
3251+ #include <sys/resourcevar.h>
3252+ #include <sys/proc.h>
3253+ #include <sys/mount.h>
3254+ #include <sys/buf.h>
3255+ #include <sys/malloc.h>
3256+ #include <sys/mbuf.h>
3257+ #include <sys/namei.h>
3258+ #include <sys/socket.h>
3259+ #include <sys/vnode.h>
3260+ #include <sys/dirent.h>
3261+ #include <sys/fcntl.h>
3262+ #include <sys/lockf.h>
3263+ #include <sys/stat.h>
3264+ #include <sys/sysctl.h>
3265+
3266+ #include <vm/vm.h>
3267+ #include <vm/vm_extern.h>
3268+ #include <vm/vm_zone.h>
3269+ #include <vm/vm_prot.h>
3270+ #include <vm/vm_page.h>
3271+ #include <vm/vm_object.h>
3272+ #include <vm/vm_pager.h>
3273+ #include <vm/vnode_pager.h>
3274+
3275+ #include <net/if.h>
3276+ #include <netinet/in.h>
3277+ #include <netinet/in_var.h>
3278+
3279+ #include <9fs/bitstring.h>
3280+ #include <9fs/9p.h>
3281+ #include <9fs/9auth.h>
3282+ #include <9fs/9fs.h>
3283+
3284+ #define u9fs_poll vop_nopoll
3285+ static	int	u9fs_lookup __P((struct vop_lookup_args *));
3286+ static	int	u9fs_create __P((struct vop_create_args *));
3287+ static	int	u9fs_mknod __P((struct vop_mknod_args *));
3288+ static	int	u9fs_open __P((struct vop_open_args *));
3289+ static	int	u9fs_close __P((struct vop_close_args *));
3290+ static	int	u9fs_access __P((struct vop_access_args *));
3291+ static	int	u9fs_getattr __P((struct vop_getattr_args *));
3292+ static	int	u9fs_setattr __P((struct vop_setattr_args *));
3293+ static	int	u9fs_read __P((struct vop_read_args *));
3294+ static	int	u9fs_mmap __P((struct vop_mmap_args *));
3295+ static	int	u9fs_fsync __P((struct vop_fsync_args *));
3296+ static	int	u9fs_remove __P((struct vop_remove_args *));
3297+ static	int	u9fs_link __P((struct vop_link_args *));
3298+ static	int	u9fs_rename __P((struct vop_rename_args *));
3299+ static	int	u9fs_mkdir __P((struct vop_mkdir_args *));
3300+ static	int	u9fs_rmdir __P((struct vop_rmdir_args *));
3301+ static	int	u9fs_symlink __P((struct vop_symlink_args *));
3302+ static	int	u9fs_readdir __P((struct vop_readdir_args *));
3303+ static	int	u9fs_bmap __P((struct vop_bmap_args *));
3304+ static	int	u9fs_strategy __P((struct vop_strategy_args *));
3305+ static int	u9fs_readlink __P((struct vop_readlink_args *));
3306+ static int	u9fs_print __P((struct vop_print_args *));
3307+ static int	u9fs_advlock __P((struct vop_advlock_args *));
3308+ static int	u9fs_bwrite __P((struct vop_bwrite_args *));
3309+ static int   u9fs_abortop __P((struct vop_abortop_args *));
3310+ static int   u9fs_getpages __P((struct vop_getpages_args *));
3311+ static int   u9fs_putpages __P((struct vop_putpages_args *));
3312+ static int   u9fs_inactive __P((struct vop_inactive_args *));
3313+ static int   u9fs_reclaim __P((struct vop_reclaim_args *));
3314+ static int   u9fs_write __P((struct vop_write_args *));
3315+
3316+ /*
3317+  * Global vfs data structures for u9fs
3318+  */
3319+ vop_t **u9fs_vnodeop_p;
3320+ static struct vnodeopv_entry_desc u9fs_vnodeop_entries[] = {
3321+ 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
3322+ 	{ &vop_abortop_desc,		(vop_t *) u9fs_abortop },
3323+ 	{ &vop_access_desc,		(vop_t *) u9fs_access },
3324+ 	{ &vop_advlock_desc,		(vop_t *) u9fs_advlock },
3325+ 	{ &vop_bmap_desc,		(vop_t *) u9fs_bmap },
3326+ 	{ &vop_bwrite_desc,		(vop_t *) u9fs_bwrite },
3327+ 	{ &vop_close_desc,		(vop_t *) u9fs_close },
3328+ 	{ &vop_create_desc,		(vop_t *) u9fs_create },
3329+ 	{ &vop_fsync_desc,		(vop_t *) u9fs_fsync },
3330+ 	{ &vop_getattr_desc,		(vop_t *) u9fs_getattr },
3331+ 	{ &vop_getpages_desc,		(vop_t *) u9fs_getpages },
3332+ 	{ &vop_putpages_desc,		(vop_t *) u9fs_putpages },
3333+ 	{ &vop_inactive_desc,		(vop_t *) u9fs_inactive },
3334+ 	{ &vop_lease_desc,		(vop_t *) vop_null },
3335+ 	{ &vop_link_desc,		(vop_t *) u9fs_link },
3336+ 	{ &vop_lock_desc,		(vop_t *) vop_sharedlock },
3337+ 	{ &vop_lookup_desc,		(vop_t *) u9fs_lookup },
3338+ 	{ &vop_mkdir_desc,		(vop_t *) u9fs_mkdir },
3339+ 	{ &vop_mknod_desc,		(vop_t *) u9fs_mknod },
3340+ 	{ &vop_mmap_desc,		(vop_t *) u9fs_mmap },
3341+ 	{ &vop_open_desc,		(vop_t *) u9fs_open },
3342+ 	{ &vop_poll_desc,		(vop_t *) vop_nopoll },
3343+ 	{ &vop_print_desc,		(vop_t *) u9fs_print },
3344+ 	{ &vop_read_desc,		(vop_t *) u9fs_read },
3345+ 	{ &vop_readdir_desc,		(vop_t *) u9fs_readdir },
3346+ 	{ &vop_readlink_desc,		(vop_t *) u9fs_readlink },
3347+ 	{ &vop_reclaim_desc,		(vop_t *) u9fs_reclaim },
3348+ 	{ &vop_remove_desc,		(vop_t *) u9fs_remove },
3349+ 	{ &vop_rename_desc,		(vop_t *) u9fs_rename },
3350+ 	{ &vop_rmdir_desc,		(vop_t *) u9fs_rmdir },
3351+ 	{ &vop_setattr_desc,		(vop_t *) u9fs_setattr },
3352+ 	{ &vop_strategy_desc,		(vop_t *) u9fs_strategy },
3353+ 	{ &vop_symlink_desc,		(vop_t *) u9fs_symlink },
3354+ 	{ &vop_write_desc,		(vop_t *) u9fs_write },
3355+ 	{ NULL, NULL }
3356+ };
3357+ static struct vnodeopv_desc u9fs_vnodeop_opv_desc =
3358+ 	{ &u9fs_vnodeop_p, u9fs_vnodeop_entries };
3359+ VNODEOP_SET(u9fs_vnodeop_opv_desc);
3360+
3361+ extern vm_zone_t u9fsnode_zone;
3362+
3363+ static int u9fs_trunc(struct vnode * vp, struct ucred * cred, struct proc * p);
3364+ static void u9fs_free_fid __P((u_short fid, struct u9fsmount * nmp, struct proc * p));
3365+ static void u9fs_updtcache __P((struct u9fsnode *, struct u9fsreq *));
3366+
3367+ #define     DIRHDSIZ        (sizeof (struct dirent) - (MAXNAMLEN + 1))
3368+
3369+ /* open returns a qid for cache consistent check */
3370+ static void
3371+ u9fs_updtcache(struct u9fsnode * np, struct u9fsreq * rep)
3372+ {
3373+   if( rep->r_type != Rerror )
3374+     np->n_dir.dir_qid = rep->r_qid;
3375+ }
3376+
3377+ static int
3378+ u9fs_trunc(vp, cred, p)
3379+      register struct vnode * vp;
3380+      struct ucred * cred;
3381+      struct proc * p;
3382+ {
3383+   struct u9fsnode *np = VTOU9FS(vp);
3384+   struct u9fsmount * nmp = VFSTOU9FS(vp->v_mount);
3385+   int error;
3386+   u_short newfid;
3387+   struct u9fsreq req, rep;
3388+   u_char mode;
3389+
3390+   /*
3391+    * Disallow write attempts on filesystems mounted read-only;
3392+    * unless the file is a socket, fifo, or a block or character
3393+    * device resident on the filesystem.
3394+    */
3395+   if ( (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3396+     switch (vp->v_type) {
3397+     case VREG:
3398+     case VDIR:
3399+     case VLNK:
3400+       return (EROFS);
3401+     default:
3402+       break;
3403+     }
3404+   }
3405+   mode = U9P_MODE_WR | U9P_MODE_TRUNC;
3406+   bzero(&req, sizeof(req));
3407+   req.r_nmp = nmp;
3408+   req.r_procp = p;
3409+   newfid = u9fs_id_new(nmp->nm_fids);
3410+   req.r_type = Tclone;
3411+   req.r_fid  = np->n_fid;
3412+   req.r_newfid = newfid;
3413+   error = u9fs_request(&req, &rep, 1);
3414+   if( error )
3415+     return error;
3416+   req.r_type = Topen;
3417+   req.r_fid = newfid;
3418+   req.r_mode = mode;
3419+   error = u9fs_request(&req, &rep, 1);
3420+   if( !error )
3421+     u9fs_vinvalbuf(vp, 0, cred, p, 0);
3422+   if( error || np->n_wrfid ) {
3423+     u9fs_free_fid(newfid, nmp, p);
3424+     return error;
3425+   }
3426+
3427+   if( !U9P_PERM_EXCL(np->n_dir.dir_mode))
3428+     np->n_wrfid = newfid;
3429+   else
3430+     u9fs_free_fid(newfid, nmp, p);
3431+
3432+   return (0);
3433+ }
3434+
3435+ /*
3436+  * u9fs access vnode op.
3437+  */
3438+ static int
3439+ u9fs_access(ap)
3440+ 	struct vop_access_args /* {
3441+ 		struct vnode *a_vp;
3442+ 		int  a_mode;
3443+ 		struct ucred *a_cred;
3444+ 		struct proc *a_p;
3445+ 	} */ *ap;
3446+ {
3447+   register struct vnode *vp = ap->a_vp;
3448+   struct u9fsnode *np = VTOU9FS(vp);
3449+   struct u9fsmount * nmp = VFSTOU9FS(vp->v_mount);
3450+   struct proc * p = ap->a_p;
3451+   int error, a_mode = ap->a_mode;
3452+   u_short * fidp = 0, *fidp2 = 0, newfid;
3453+   struct u9fsreq req, rep;
3454+   u_char mode;
3455+   struct ucred * cred = ap->a_cred;
3456+
3457+   /* XXX: for the moment, only the authenticator has access */
3458+   if( cred->cr_uid != nmp->nm_authuid )
3459+     return (EPERM);
3460+
3461+   /*
3462+    * Disallow write attempts on filesystems mounted read-only;
3463+    * unless the file is a socket, fifo, or a block or character
3464+    * device resident on the filesystem.
3465+    */
3466+   if ((a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3467+     switch (vp->v_type) {
3468+     case VREG:
3469+     case VDIR:
3470+     case VLNK:
3471+       return (EROFS);
3472+     default:
3473+       break;
3474+     }
3475+   }
3476+
3477+   /* we cant open an exclusive open file here */
3478+   if( U9P_PERM_EXCL(np->n_dir.dir_mode) )
3479+     return 0;
3480+
3481+   /* check permission by actually opening it */
3482+   /* translate mode */
3483+   mode = 0;
3484+   if( a_mode & VREAD ) {
3485+     fidp = &np->n_rdfid;
3486+     mode = U9P_MODE_RD;
3487+   }
3488+   if( a_mode & VWRITE ) {
3489+     fidp = &np->n_wrfid;
3490+     mode = U9P_MODE_WR;
3491+   }
3492+   if( (a_mode & (VREAD|VWRITE)) == (VREAD|VWRITE) ) {
3493+     fidp2 = &np->n_rdfid;
3494+     mode = U9P_MODE_RDWR;
3495+   }
3496+
3497+   if( a_mode & VEXEC ) {
3498+     fidp = &np->n_rdfid;
3499+     if( vp->v_type == VREG )
3500+       mode = U9P_MODE_EX;
3501+   }
3502+
3503+   if( fidp2 == 0 )
3504+     fidp2 = fidp;
3505+
3506+   /* open fid mode */
3507+   bzero(&req, sizeof(req));
3508+   req.r_nmp = nmp;
3509+   req.r_procp = p;
3510+   newfid = u9fs_id_new(nmp->nm_fids);
3511+   req.r_type = Tclone;
3512+   req.r_fid  = np->n_fid;
3513+   req.r_newfid = newfid;
3514+   error = u9fs_request(&req, &rep, 1);
3515+   if( error )
3516+     return error;
3517+   req.r_type = Topen;
3518+   req.r_fid = newfid;
3519+   req.r_mode = mode;
3520+   error = u9fs_request(&req, &rep, 1);
3521+   u9fs_updtcache(np, &rep);
3522+   if( error || (*fidp && *fidp2 ) ) {
3523+     u9fs_free_fid(newfid, nmp, p);
3524+     return error;
3525+   }
3526+
3527+   *fidp = *fidp2 = newfid;
3528+
3529+   return (0);
3530+ }
3531+
3532+ /*
3533+  * u9fs open vnode op
3534+  * Check to see if the type is ok
3535+  * and that deletion is not in progress.
3536+  * For paged in text files, you will need to flush the page cache
3537+  * if consistency is lost.
3538+  */
3539+ /* ARGSUSED */
3540+ static int
3541+ u9fs_open(ap)
3542+ 	struct vop_open_args /* {
3543+ 		struct vnode *a_vp;
3544+ 		int  a_mode;
3545+ 		struct ucred *a_cred;
3546+ 		struct proc *a_p;
3547+ 	} */ *ap;
3548+ {
3549+   register struct vnode *vp = ap->a_vp;
3550+   struct u9fsnode *np = VTOU9FS(vp);
3551+   int error=0, a_mode = ap->a_mode;
3552+   u_short * fidp = 0, *fidp2 = 0, newfid;
3553+   struct u9fsmount * nmp = VFSTOU9FS(vp->v_mount);
3554+   struct proc * p = ap->a_p;
3555+   struct u9fsreq req, rep;
3556+   u_char mode;
3557+   struct ucred * cred = ap->a_cred;
3558+
3559+   /* assume access permissions have been checked via VOP_ACCESS */
3560+   /* the file is actually opened except the rdwr case */
3561+
3562+   if( a_mode & (O_EXCL|O_SHLOCK|O_EXLOCK) ) {
3563+ #if 0  /* XXX: what can we do here? */
3564+     return (EOPNOTSUPP);
3565+ #endif
3566+   }
3567+
3568+   /* translate mode */
3569+   mode = 0;
3570+   if( a_mode & FREAD ) {
3571+     fidp = &np->n_rdfid;
3572+     mode = U9P_MODE_RD;
3573+   }
3574+   if( a_mode & FWRITE ) {
3575+     fidp = &np->n_wrfid;
3576+     mode = U9P_MODE_WR;
3577+   }
3578+   if( (a_mode & (FREAD|FWRITE)) == (FREAD|FWRITE) ) {
3579+     fidp2 = & np->n_rdfid;
3580+     mode = U9P_MODE_RDWR;
3581+   }
3582+   if( fidp2 == 0)
3583+     fidp2 = fidp;
3584+
3585+   if( U9P_PERM_EXCL(np->n_dir.dir_mode) ) {
3586+     if( *fidp || *fidp2 )
3587+       return ENOLCK;
3588+
3589+     /* open fid mode */
3590+     bzero(&req, sizeof(req));
3591+     req.r_nmp = nmp;
3592+     req.r_procp = p;
3593+     newfid = u9fs_id_new(nmp->nm_fids);
3594+     req.r_type = Tclone;
3595+     req.r_fid  = np->n_fid;
3596+     req.r_newfid = newfid;
3597+     error = u9fs_request(&req, &rep, 1);
3598+     if( error )
3599+       return error;
3600+     req.r_type = Topen;
3601+     req.r_fid = newfid;
3602+     req.r_mode = mode;
3603+     error = u9fs_request(&req, &rep, 1);
3604+     if( error ) {
3605+       u9fs_free_fid(newfid, nmp, p);
3606+       return error;
3607+     }
3608+     u9fs_updtcache(np, &rep);
3609+
3610+     *fidp = *fidp2 = newfid;
3611+   }
3612+
3613+   if( *fidp == 0 )
3614+     panic("open");
3615+
3616+   if( *fidp2 == 0 ) {
3617+     /* open fid mode */
3618+     bzero(&req, sizeof(req));
3619+     req.r_nmp = nmp;
3620+     req.r_procp = p;
3621+     newfid = u9fs_id_new(nmp->nm_fids);
3622+     req.r_type = Tclone;
3623+     req.r_fid  = np->n_fid;
3624+     req.r_newfid = newfid;
3625+     error = u9fs_request(&req, &rep, 1);
3626+     if( error )
3627+       return error;
3628+     req.r_type = Topen;
3629+     req.r_fid = newfid;
3630+     req.r_mode = mode;
3631+     error = u9fs_request(&req, &rep, 1);
3632+     if( error ) {
3633+       u9fs_free_fid(newfid, nmp, p);
3634+       return error;
3635+     }
3636+     u9fs_updtcache(np, &rep);
3637+     *fidp2 = newfid;
3638+   }
3639+
3640+   if( np->n_qid.vers != np->n_dir.dir_qid.vers ) /* content changed */
3641+     u9fs_vinvalbuf(vp, 0, cred, p, 0);
3642+
3643+   return 0;
3644+ }
3645+
3646+ /*
3647+  * u9fs close vnode op
3648+  * What an U9FS client should do upon close after writing is a debatable issue.
3649+  * Most U9FS clients push delayed writes to the server upon close, basically for
3650+  * two reasons:
3651+  * 1 - So that any write errors may be reported back to the client process
3652+  *     doing the close system call. By far the two most likely errors are
3653+  *     U9FSERR_NOSPC and U9FSERR_DQUOT to indicate space allocation failure.
3654+  * 2 - To put a worst case upper bound on cache inconsistency between
3655+  *     multiple clients for the file.
3656+  * There is also a consistency problem for Version 2 of the protocol w.r.t.
3657+  * not being able to tell if other clients are writing a file concurrently,
3658+  * since there is no way of knowing if the changed modify time in the reply
3659+  * is only due to the write for this client.
3660+  * (U9FS Version 3 provides weak cache consistency data in the reply that
3661+  *  should be sufficient to detect and handle this case.)
3662+  *
3663+  * The current code does the following:
3664+  * for U9FS Version 2 - play it safe and flush/invalidate all dirty buffers
3665+  * for U9FS Version 3 - flush dirty buffers to the server but don't invalidate
3666+  *                     or commit them (this satisfies 1 and 2 except for the
3667+  *                     case where the server crashes after this close but
3668+  *                     before the commit RPC, which is felt to be "good
3669+  *                     enough". Changing the last argument to u9fs_flush() to
3670+  *                     a 1 would force a commit operation, if it is felt a
3671+  *                     commit is necessary now.
3672+  * for NQU9FS         - do nothing now, since 2 is dealt with via leases and
3673+  *                     1 should be dealt with via an fsync() system call for
3674+  *                     cases where write errors are important.
3675+  */
3676+ /* ARGSUSED */
3677+ static int
3678+ u9fs_close(ap)
3679+ 	struct vop_close_args /* {
3680+ 		struct vnodeop_desc *a_desc;
3681+ 		struct vnode *a_vp;
3682+ 		int  a_fflag;
3683+ 		struct ucred *a_cred;
3684+ 		struct proc *a_p;
3685+ 	} */ *ap;
3686+ {
3687+   int fflag = ap->a_fflag;
3688+   struct vnode * vp = ap->a_vp;
3689+   struct u9fsnode * np = VTOU9FS(vp);
3690+   struct u9fsmount * nmp = VFSTOU9FS(vp->v_mount);
3691+   struct proc * p = ap->a_p;
3692+
3693+   if( U9P_PERM_EXCL(np->n_dir.dir_mode) ) {
3694+     if( (fflag & FREAD) ) {
3695+       u9fs_free_fid(np->n_rdfid, nmp, p);
3696+       np->n_rdfid = 0;
3697+     }
3698+
3699+     if( (fflag & FWRITE) == FWRITE ) {
3700+       u9fs_free_fid(np->n_wrfid, nmp, p);
3701+       np->n_wrfid = 0;
3702+     }
3703+
3704+     if( (fflag & (FREAD|FWRITE)) == (FREAD|FWRITE) )
3705+       np->n_wrfid = 0;
3706+   }
3707+
3708+   return 0;
3709+ }
3710+
3711+ /*
3712+  * u9fs getattr call from vfs.
3713+  */
3714+ static int
3715+ u9fs_getattr(ap)
3716+ 	struct vop_getattr_args /* {
3717+ 		struct vnode *a_vp;
3718+ 		struct vattr *a_vap;
3719+ 		struct ucred *a_cred;
3720+ 		struct proc *a_p;
3721+ 	} */ *ap;
3722+ {
3723+   register struct vnode *vp = ap->a_vp;
3724+   register struct u9fsnode *np = VTOU9FS(vp);
3725+   int error = 0;
3726+   struct u9fsreq req, rep;
3727+   struct u9fsmount * nmp = VFSTOU9FS(vp->v_mount);
3728+   struct u9fsdir * dir;
3729+   struct vattr * vap = ap->a_vap;
3730+
3731+   /*
3732+    * Update local times for special files.
3733+    */
3734+   if (np->n_flag & (NACC | NUPD))
3735+     np->n_flag |= NCHG;
3736+ #if 0
3737+   /*
3738+    * First look in the cache.
3739+    */
3740+   if (u9fs_getattrcache(vp, ap->a_vap) == 0)
3741+     return (0);
3742+ #endif
3743+   if( np->n_fid == 0 )
3744+     panic("u9fs_getattr");
3745+
3746+   /* stat fid */
3747+   bzero(&req, sizeof(req));
3748+   req.r_nmp = nmp;
3749+   req.r_procp = ap->a_p;
3750+   req.r_type = Tstat;
3751+   req.r_fid = np->n_fid;
3752+   error = u9fs_request(& req, & rep, 1);
3753+   if( error )
3754+     return error;
3755+
3756+   /* fill in vattr */
3757+   dir = & np->n_dir;
3758+   u9p_m2d(rep.r_stat, dir);
3759+
3760+   bzero(vap, sizeof(*vap));
3761+   /* the plan9 file system has no other types. */
3762+   /* XXX: we have not delt with devices yet */
3763+   if( U9P_PERM_CHDIR(dir->dir_mode) )
3764+     vap->va_type = VDIR;
3765+   else
3766+     vap->va_type = VREG;
3767+
3768+   vap->va_mode  = U9P_PERM_ALL(dir->dir_mode);
3769+   vap->va_nlink = 1;
3770+   vap->va_uid = u9fs_name2uid(dir->dir_uid);
3771+   vap->va_gid = u9fs_name2uid(dir->dir_gid);
3772+   vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
3773+   vap->va_fileid = dir->dir_qid.path;
3774+   vap->va_size = np->n_size = dir->dir_length;
3775+   vap->va_blocksize = PAGE_SIZE;
3776+   vap->va_atime.tv_sec = dir->dir_atime;
3777+   vap->va_atime.tv_nsec = 0;
3778+   vap->va_mtime.tv_sec = dir->dir_mtime;
3779+   vap->va_mtime.tv_nsec = 0;
3780+   vap->va_ctime.tv_sec = dir->dir_mtime;
3781+   vap->va_ctime.tv_nsec = dir->dir_mtime;
3782+   vap->va_gen = VNOVAL;
3783+   vap->va_flags = 0;
3784+   vap->va_bytes = vap->va_size;
3785+   vap->va_filerev = dir->dir_qid.vers;
3786+
3787+   vp->v_type = vap->va_type;
3788+   vp->v_tag = VT_U9FS;
3789+
3790+   return (error);
3791+ }
3792+
3793+ /*
3794+  * u9fs setattr call.
3795+  */
3796+ static int
3797+ u9fs_setattr(ap)
3798+ 	struct vop_setattr_args /* {
3799+ 		struct vnodeop_desc *a_desc;
3800+ 		struct vnode *a_vp;
3801+ 		struct vattr *a_vap;
3802+ 		struct ucred *a_cred;
3803+ 		struct proc *a_p;
3804+ 	} */ *ap;
3805+ {
3806+   register struct vnode *vp = ap->a_vp;
3807+   register struct u9fsnode *np = VTOU9FS(vp);
3808+   register struct vattr *vap = ap->a_vap;
3809+   int error = 0;
3810+   struct u9fsmount * nmp = VFSTOU9FS(vp->v_mount);
3811+   struct u9fsdir dir;
3812+   struct u9fsuser * u9p;
3813+   struct vattr attr;
3814+   struct u9fsreq req, rep;
3815+
3816+   if( vp->v_mount->mnt_flag & MNT_RDONLY )
3817+     return (EROFS);
3818+
3819+   if( vap->va_nlink != VNOVAL || vap->va_uid != VNOVAL ||
3820+       vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL ||
3821+ #if 0
3822+       vap->va_size != VNOVAL || vap->va_blocksize != VNOVAL ||
3823+ #endif
3824+       vap->va_atime.tv_sec != VNOVAL || vap->va_ctime.tv_sec != VNOVAL ||
3825+       vap->va_gen != VNOVAL ||
3826+       vap->va_flags != VNOVAL || vap->va_bytes != VNOVAL ) {
3827+ #if 0
3828+     printf("%d %d %d %d %d %d %d %d %d %d %d\n", vap->va_nlink, vap->va_uid, vap->va_fsid,
3829+ 	       vap->va_fileid, vap->va_size, vap->va_blocksize,
3830+ 	       vap->va_atime.tv_sec, vap->va_ctime.tv_sec, vap->va_gen,
3831+ 	       vap->va_flags, vap->va_bytes);
3832+     printf("unsupported setattr\n");
3833+     /* touch tries to change ctime first.
3834+      * if fails, it touches the first byte
3835+     */
3836+ #endif
3837+     return (EOPNOTSUPP);
3838+   }
3839+
3840+   if( vap->va_size == 0 )
3841+     u9fs_trunc(vp, ap->a_cred, ap->a_p);
3842+
3843+   bcopy(&np->n_dir, &dir, sizeof(dir));
3844+   if( vap->va_mode  != (mode_t)VNOVAL ) {
3845+     dir.dir_mode = U9P_PERM_NONPERM(dir.dir_mode)|U9P_PERM_ALL(vap->va_mode);
3846+   }
3847+   if( vap->va_gid != VNOVAL ) {
3848+     if( (u9p = u9fs_finduser(vap->va_gid)) == 0 )
3849+       return (EINVAL);
3850+     strncpy(u9p->u_name, dir.dir_gid, U9FS_NAMELEN);
3851+   }
3852+   if( vap->va_mtime.tv_sec != VNOVAL ) {
3853+     dir.dir_mtime = vap->va_mtime.tv_sec;
3854+   }
3855+
3856+   /* stat fid */
3857+   bzero(&req, sizeof(req));
3858+   req.r_nmp = nmp;
3859+   req.r_procp = ap->a_p;
3860+   req.r_type = Twstat;
3861+   req.r_fid = np->n_fid;
3862+   u9p_d2m(&dir, req.r_stat);
3863+   error = u9fs_request(& req, & rep, 1);
3864+   if( error )
3865+     return error;
3866+   VOP_GETATTR(vp, &attr, ap->a_cred, ap->a_p);
3867+
3868+   return 0;
3869+ }
3870+
3871+ /*
3872+  * u9fs lookup call, one step at a time...
3873+  * First look in cache
3874+  * If not found, unlock the directory u9fsnode and do the rpc
3875+  */
3876+ static int
3877+ u9fs_lookup(ap)
3878+ 	struct vop_lookup_args /* {
3879+ 		struct vnodeop_desc *a_desc;
3880+ 		struct vnode *a_dvp;
3881+ 		struct vnode **a_vpp;
3882+ 		struct componentname *a_cnp;
3883+ 	} */ *ap;
3884+ {
3885+ 	struct componentname *cnp = ap->a_cnp;
3886+ 	struct vnode *dvp = ap->a_dvp;
3887+ 	struct vnode **vpp = ap->a_vpp;
3888+ 	int flags = cnp->cn_flags;
3889+ 	struct vnode *newvp;
3890+ 	struct u9fsmount *nmp;
3891+ 	long len;
3892+ 	u9fsfh_t fh;
3893+ 	struct u9fsnode *np;
3894+ 	int lockparent, wantparent, error = 0;
3895+ 	struct proc *p = cnp->cn_proc;
3896+ 	struct u9fsreq req, rep;
3897+ 	u_short newfid;
3898+ 	struct vattr attrs;
3899+
3900+ 	*vpp = NULLVP;
3901+ 	if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
3902+ 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
3903+ 		return (EROFS);
3904+ 	if (dvp->v_type != VDIR)
3905+ 		return (ENOTDIR);
3906+ 	lockparent = flags & LOCKPARENT;
3907+ 	wantparent = flags & (LOCKPARENT|WANTPARENT);
3908+ 	nmp = VFSTOU9FS(dvp->v_mount);
3909+ 	np = VTOU9FS(dvp);
3910+ #if 0
3911+ 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
3912+ 		struct vattr vattr;
3913+ 		int vpid;
3914+
3915+ 		if (error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p)) {
3916+ 			*vpp = NULLVP;
3917+ 			return (error);
3918+ 		}
3919+
3920+ 		newvp = *vpp;
3921+ 		vpid = newvp->v_id;
3922+ 		/*
3923+ 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
3924+ 		 * for an explanation of the locking protocol
3925+ 		 */
3926+ 		if (dvp == newvp) {
3927+ 			VREF(newvp);
3928+ 			error = 0;
3929+ 		} else if (flags & ISDOTDOT) {
3930+ 			VOP_UNLOCK(dvp, 0, p);
3931+ 			error = vget(newvp, LK_EXCLUSIVE, p);
3932+ 			if (!error && lockparent && (flags & ISLASTCN))
3933+ 				error = vn_lock(dvp, LK_EXCLUSIVE, p);
3934+ 		} else {
3935+ 			error = vget(newvp, LK_EXCLUSIVE, p);
3936+ 			if (!lockparent || error || !(flags & ISLASTCN))
3937+ 				VOP_UNLOCK(dvp, 0, p);
3938+ 		}
3939+ 		if (!error) {
3940+ 			if (vpid == newvp->v_id) {
3941+ 			   if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p)
3942+ 			    && vattr.va_ctime.tv_sec == VTOU9FS(newvp)->n_ctime) {
3943+ 				u9fsstats.lookupcache_hits++;
3944+ 				if (cnp->cn_nameiop != LOOKUP &&
3945+ 				    (flags & ISLASTCN))
3946+ 					cnp->cn_flags |= SAVENAME;
3947+ 				return (0);
3948+ 			   }
3949+ 			   cache_purge(newvp);
3950+ 			}
3951+ 			vput(newvp);
3952+ 			if (lockparent && dvp != newvp && (flags & ISLASTCN))
3953+ 				VOP_UNLOCK(dvp, 0, p);
3954+ 		}
3955+ 		error = vn_lock(dvp, LK_EXCLUSIVE, p);
3956+ 		*vpp = NULLVP;
3957+ 		if (error)
3958+ 			return (error);
3959+ 	}
3960+ #endif
3961+ 	error = 0;
3962+ 	newvp = NULLVP;
3963+ 	len = cnp->cn_namelen;
3964+
3965+ 	/* Tclwalk tag fid newfid name */
3966+ 	bzero(&req, sizeof(req));
3967+ 	req.r_procp = p;
3968+ 	req.r_nmp = nmp;
3969+ 	req.r_type = Tclwalk;
3970+ 	req.r_fid = np->n_fid;
3971+ 	newfid = req.r_newfid = u9fs_id_new(nmp->nm_fids);
3972+ 	bcopy(cnp->cn_nameptr, req.r_name, len);
3973+ 	if( (error = u9fs_request(&req, &rep, 1)) ) {
3974+ 	  u9fs_id_free(nmp->nm_fids, newfid);
3975+ 	  return error;
3976+ 	}
3977+
3978+ 	fh = rep.r_qid.path;
3979+ 	if( fh == 0 ) {
3980+ 	  u9fs_id_free(nmp->nm_fids, newfid);
3981+ 	  error = ENOENT;
3982+ 	  goto lastcheck;
3983+ 	}
3984+
3985+ 	/*
3986+ 	 * Handle RENAME case...
3987+ 	 */
3988+ 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
3989+ #if 0
3990+ 	  /* XXX: I dont understand this. rename foo foo? */
3991+ 		if (U9FS_CMPFH(np, fhp, fhsize)) {
3992+ 			m_freem(mrep);
3993+ 			return (EISDIR);
3994+ 		}
3995+ #endif
3996+ 		error = u9fs_nget(dvp->v_mount, fh, &np, p);
3997+ 		if (error)
3998+ 		  goto fail;
3999+
4000+ 		if ( np->n_fid )
4001+ 		  u9fs_free_fid(newfid, nmp, p);
4002+ 		else
4003+ 		  np->n_fid = newfid;
4004+
4005+ 		newvp = U9FSTOV(np);
4006+ 		*vpp = newvp;
4007+ 		cnp->cn_flags |= SAVENAME;
4008+ 		if (!lockparent)
4009+ 			VOP_UNLOCK(dvp, 0, p);
4010+ 		return (0);
4011+ 	}
4012+
4013+ 	if (flags & ISDOTDOT) {
4014+ 		VOP_UNLOCK(dvp, 0, p);
4015+ 		error = u9fs_nget(dvp->v_mount, fh, &np, p);
4016+ 		if (error) {
4017+ 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
4018+ 			goto fail;
4019+ 		}
4020+ 		if( np->n_fid )
4021+ 		  u9fs_free_fid(newfid, nmp, p);
4022+ 		else
4023+ 		  np->n_fid = req.r_newfid;
4024+
4025+ 		newvp = U9FSTOV(np);
4026+ 		if (lockparent && (flags & ISLASTCN) &&
4027+ 		    (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
4028+ 		    	vput(newvp);
4029+ 			return (error);
4030+ 		}
4031+ 	} else if (np->n_qid.path == fh) {
4032+ 	        u9fs_free_fid(newfid, nmp, p);
4033+ 		VREF(dvp);
4034+ 		newvp = dvp;
4035+ 	} else {
4036+ 		error = u9fs_nget(dvp->v_mount, fh, &np, p);
4037+ 		if (error)
4038+ 		  goto fail;
4039+
4040+ 		if( np->n_fid )
4041+ 		  u9fs_free_fid(newfid, nmp, p);
4042+ 		else
4043+ 		  np->n_fid = req.r_newfid;
4044+
4045+ 		if (!lockparent || !(flags & ISLASTCN))
4046+ 			VOP_UNLOCK(dvp, 0, p);
4047+ 		newvp = U9FSTOV(np);
4048+
4049+ 		VOP_GETATTR(newvp, & attrs, p->p_ucred, p);
4050+ 	}
4051+
4052+ 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
4053+ 		cnp->cn_flags |= SAVENAME;
4054+ #if 0
4055+ 	if ((cnp->cn_flags & MAKEENTRY) &&
4056+ 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
4057+ 		np->n_ctime = np->n_vattr.va_ctime.tv_sec;
4058+ 		cache_enter(dvp, newvp, cnp);
4059+ 	}
4060+ #endif
4061+ 	*vpp = newvp;
4062+  lastcheck:
4063+ 	if (error) {
4064+ 		if (newvp != NULLVP) {
4065+ 			vrele(newvp);
4066+ 			*vpp = NULLVP;
4067+ 		}
4068+ 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
4069+ 		    (flags & ISLASTCN) && error == ENOENT) {
4070+ 			if (!lockparent)
4071+ 				VOP_UNLOCK(dvp, 0, p);
4072+ 			if (dvp->v_mount->mnt_flag & MNT_RDONLY)
4073+ 				error = EROFS;
4074+ 			else
4075+ 				error = EJUSTRETURN;
4076+ 		}
4077+ 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
4078+ 			cnp->cn_flags |= SAVENAME;
4079+ 	}
4080+ 	return (error);
4081+
4082+  fail:
4083+ 	u9fs_free_fid(newfid, nmp, p);
4084+ 	return (error);
4085+ }
4086+
4087+ /*
4088+  * u9fs read call.
4089+  * Just call u9fs_bioread() to do the work.
4090+  */
4091+ static int
4092+ u9fs_read(ap)
4093+ 	struct vop_read_args /* {
4094+ 		struct vnode *a_vp;
4095+ 		struct uio *a_uio;
4096+ 		int  a_ioflag;
4097+ 		struct ucred *a_cred;
4098+ 	} */ *ap;
4099+ {
4100+   register struct vnode *vp = ap->a_vp;
4101+
4102+   if (vp->v_type != VREG)
4103+     return (EPERM);
4104+   return (u9fs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
4105+ }
4106+
4107+ /*
4108+  * u9fs readlink call
4109+  */
4110+ static int
4111+ u9fs_readlink(ap)
4112+ 	struct vop_readlink_args /* {
4113+ 		struct vnode *a_vp;
4114+ 		struct uio *a_uio;
4115+ 		struct ucred *a_cred;
4116+ 	} */ *ap;
4117+ {
4118+   return (EOPNOTSUPP);
4119+ }
4120+
4121+ /*
4122+  * u9fs mknod vop
4123+  * just call u9fs_mknodrpc() to do the work.
4124+  */
4125+ /* ARGSUSED */
4126+ static int
4127+ u9fs_mknod(ap)
4128+ 	struct vop_mknod_args /* {
4129+ 		struct vnode *a_dvp;
4130+ 		struct vnode **a_vpp;
4131+ 		struct componentname *a_cnp;
4132+ 		struct vattr *a_vap;
4133+ 	} */ *ap;
4134+ {
4135+   return (EOPNOTSUPP);
4136+ }
4137+
4138+ /*
4139+  * u9fs file create call
4140+  */
4141+ static int
4142+ u9fs_create(ap)
4143+ 	struct vop_create_args /* {
4144+ 		struct vnode *a_dvp;
4145+ 		struct vnode **a_vpp;
4146+ 		struct componentname *a_cnp;
4147+ 		struct vattr *a_vap;
4148+ 	} */ *ap;
4149+ {
4150+ 	register struct vnode *dvp = ap->a_dvp;
4151+ 	register struct vattr *vap = ap->a_vap;
4152+ 	register struct componentname *cnp = ap->a_cnp;
4153+ 	struct u9fsnode *np = (struct u9fsnode *)0;
4154+ 	struct vnode *newvp = (struct vnode *)0;
4155+ 	int error = 0, len;
4156+ 	struct vattr vattr;
4157+ 	struct u9fsreq req, rep;
4158+ 	struct u9fsmount *nmp;
4159+ 	u9fsfh_t fh;
4160+ 	struct proc * p;
4161+ 	int pfid;
4162+
4163+ #if 0
4164+ 	/*
4165+ 	 * Oops, not for me..
4166+ 	 */
4167+ 	if (vap->va_type == VSOCK)
4168+ 		return (u9fs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
4169+ #endif
4170+
4171+ 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
4172+ 		VOP_ABORTOP(dvp, cnp);
4173+ 		return (error);
4174+ 	}
4175+
4176+ 	nmp = VFSTOU9FS(dvp->v_mount);
4177+ 	np = VTOU9FS(dvp);
4178+ 	p = cnp->cn_proc;
4179+
4180+ 	bzero(&req, sizeof(req));
4181+ 	req.r_nmp = nmp;
4182+ 	req.r_procp = p;
4183+
4184+ 	req.r_type = Tclone;
4185+ 	pfid = req.r_fid  = np->n_fid;
4186+ 	req.r_newfid = u9fs_id_new(nmp->nm_fids);
4187+ 	error = u9fs_request(&req, &rep, 1);
4188+ 	if( error )
4189+ 	  return error;
4190+
4191+ 	req.r_type = Tcreate;
4192+ 	req.r_fid = req.r_newfid;
4193+ 	len = cnp->cn_namelen;
4194+ 	if( len > U9FS_NAMELEN )
4195+ 	  len = U9FS_NAMELEN;
4196+ 	strncpy(req.r_name, cnp->cn_nameptr, len);
4197+ 	req.r_name[U9FS_NAMELEN] = 0;
4198+ 	req.r_perm = U9P_PERM_ALL(vap->va_mode);
4199+ 	if( vap->va_type == VDIR ) {
4200+ 	  req.r_perm |= 0x80000000;
4201+ 	  req.r_mode = U9P_MODE_RD;
4202+ 	} else
4203+ 	  req.r_mode = U9P_MODE_WR | U9P_MODE_TRUNC;
4204+ 	if(vap->va_vaflags & VA_EXCLUSIVE)
4205+ 	  req.r_mode = U9P_MODE_EX;
4206+
4207+ 	error = u9fs_request(&req, &rep, 1);
4208+ 	if( error )
4209+ 	  return error;
4210+
4211+ 	fh = rep.r_qid.path;
4212+ 	u9fs_nget(dvp->v_mount, fh, &np, p);
4213+ 	newvp = U9FSTOV(np);
4214+ 	if( vap->va_type == VDIR )
4215+ 	  np->n_rdfid = req.r_fid;
4216+ 	else
4217+ 	  np->n_wrfid = req.r_fid;
4218+
4219+ 	req.r_type = Tclwalk;
4220+ 	req.r_fid  = pfid;
4221+ 	req.r_newfid = u9fs_id_new(nmp->nm_fids);
4222+ 	/* r_name is already filled */
4223+ 	error = u9fs_request(&req, &rep, 1);
4224+ 	if( error )
4225+ 	  return error;
4226+ 	np->n_fid = req.r_newfid;
4227+ 	VOP_GETATTR(newvp, & vattr, p->p_ucred, p);
4228+
4229+ 	*ap->a_vpp = newvp;
4230+ 	zfree(namei_zone, cnp->cn_pnbuf);
4231+
4232+ 	return 0;
4233+ }
4234+
4235+ /*
4236+  * u9fs file remove call
4237+  * To try and make u9fs semantics closer to ufs semantics, a file that has
4238+  * other processes using the vnode is renamed instead of removed and then
4239+  * removed later on the last close.
4240+  * - If v_usecount > 1
4241+  *	  If a rename is not already in the works
4242+  *	     call u9fs_sillyrename() to set it up
4243+  *     else
4244+  *	  do the remove rpc
4245+  */
4246+ static int
4247+ u9fs_remove(ap)
4248+ 	struct vop_remove_args /* {
4249+ 		struct vnodeop_desc *a_desc;
4250+ 		struct vnode * a_dvp;
4251+ 		struct vnode * a_vp;
4252+ 		struct componentname * a_cnp;
4253+ 	} */ *ap;
4254+ {
4255+ 	register struct vnode *vp = ap->a_vp;
4256+ 	register struct componentname *cnp = ap->a_cnp;
4257+ 	struct u9fsnode *np;
4258+ 	struct u9fsreq req, rep;
4259+ 	struct u9fsmount *nmp;
4260+ 	struct proc * p;
4261+ 	int error;
4262+
4263+ 	nmp = VFSTOU9FS(vp->v_mount);
4264+ 	np = VTOU9FS(vp);
4265+ 	p = cnp->cn_proc;
4266+ 	bzero(&req, sizeof(req));
4267+ 	req.r_nmp = nmp;
4268+ 	req.r_procp = p;
4269+ 	req.r_type = Tremove;
4270+ 	req.r_fid = np->n_fid;
4271+ 	error = u9fs_request(&req, &rep, 1);
4272+ 	if( error )
4273+ 	  return error;
4274+ 	zfree(namei_zone, cnp->cn_pnbuf);
4275+ 	return 0;
4276+ }
4277+
4278+ /*
4279+  * u9fs file rename call
4280+  */
4281+ static int
4282+ u9fs_rename(ap)
4283+ 	struct vop_rename_args  /* {
4284+ 		struct vnode *a_fdvp;
4285+ 		struct vnode *a_fvp;
4286+ 		struct componentname *a_fcnp;
4287+ 		struct vnode *a_tdvp;
4288+ 		struct vnode *a_tvp;
4289+ 		struct componentname *a_tcnp;
4290+ 	} */ *ap;
4291+ {
4292+ 	register struct vnode *fvp = ap->a_fvp;
4293+ 	register struct vnode *tvp = ap->a_tvp;
4294+ 	register struct vnode *fdvp = ap->a_fdvp;
4295+ 	register struct vnode *tdvp = ap->a_tdvp;
4296+ 	register struct componentname *tcnp = ap->a_tcnp;
4297+ 	register struct componentname *fcnp = ap->a_fcnp;
4298+ 	int error, len;
4299+ 	struct u9fsmount * nmp;
4300+ 	struct u9fsreq req, rep;
4301+ 	struct u9fsdir dir;
4302+ 	struct u9fsnode * np;
4303+
4304+ 	/* we cant do cross-directory renaming or move to an existing file */
4305+ 	if( fdvp != tdvp || tvp != 0 || fvp->v_mount->mnt_flag & MNT_RDONLY ){
4306+ 	  printf("rename to existing file not supported\n");
4307+ 	  error = EOPNOTSUPP;
4308+ 	  goto out;
4309+ 	}
4310+
4311+ 	nmp = VFSTOU9FS(fvp->v_mount);
4312+ 	np = VTOU9FS(fvp);
4313+
4314+ 	bcopy(&np->n_dir, &dir, sizeof(dir));
4315+ 	len = tcnp->cn_namelen;
4316+ 	if( len > U9FS_NAMELEN )
4317+ 	  len = U9FS_NAMELEN;
4318+ 	strncpy(dir.dir_name, tcnp->cn_nameptr, len);
4319+ 	dir.dir_name[U9FS_NAMELEN-1] = 0;
4320+
4321+ 	/* stat fid */
4322+ 	bzero(&req, sizeof(req));
4323+ 	req.r_nmp = nmp;
4324+ 	req.r_procp = fcnp->cn_proc;
4325+ 	req.r_type = Twstat;
4326+ 	req.r_fid = np->n_fid;
4327+ 	u9p_d2m(&dir, req.r_stat);
4328+ 	error = u9fs_request(& req, & rep, 1);
4329+
4330+  out:
4331+ 	if (tdvp == tvp)
4332+ 		vrele(tdvp);
4333+ 	else
4334+ 		vput(tdvp);
4335+ 	if (tvp)
4336+ 		vput(tvp);
4337+ 	vrele(fdvp);
4338+ 	vrele(fvp);
4339+
4340+ 	return error;
4341+ }
4342+
4343+ /*
4344+  * u9fs hard link create call
4345+  */
4346+ static int
4347+ u9fs_link(ap)
4348+ 	struct vop_link_args /* {
4349+ 		struct vnode *a_tdvp;
4350+ 		struct vnode *a_vp;
4351+ 		struct componentname *a_cnp;
4352+ 	} */ *ap;
4353+ {
4354+   return (EOPNOTSUPP);
4355+ }
4356+
4357+ /*
4358+  * u9fs symbolic link create call
4359+  */
4360+ static int
4361+ u9fs_symlink(ap)
4362+ 	struct vop_symlink_args /* {
4363+ 		struct vnode *a_dvp;
4364+ 		struct vnode **a_vpp;
4365+ 		struct componentname *a_cnp;
4366+ 		struct vattr *a_vap;
4367+ 		char *a_target;
4368+ 	} */ *ap;
4369+ {
4370+   return (EOPNOTSUPP);
4371+ }
4372+
4373+ /*
4374+  * u9fs make dir call
4375+  */
4376+ static int
4377+ u9fs_mkdir(ap)
4378+ 	struct vop_mkdir_args /* {
4379+ 		struct vnode *a_dvp;
4380+ 		struct vnode **a_vpp;
4381+ 		struct componentname *a_cnp;
4382+ 		struct vattr *a_vap;
4383+ 	} */ *ap;
4384+ {
4385+   struct vop_create_args cap;
4386+
4387+   cap.a_dvp = ap->a_dvp;
4388+   cap.a_vpp = ap->a_vpp;
4389+   cap.a_cnp = ap->a_cnp;
4390+   cap.a_vap = ap->a_vap;
4391+   return u9fs_create(&cap);
4392+ }
4393+
4394+ /*
4395+  * u9fs remove directory call
4396+  */
4397+ static int
4398+ u9fs_rmdir(ap)
4399+ 	struct vop_rmdir_args /* {
4400+ 		struct vnode *a_dvp;
4401+ 		struct vnode *a_vp;
4402+ 		struct componentname *a_cnp;
4403+ 	} */ *ap;
4404+ {
4405+ 	register struct vnode *vp = ap->a_vp;
4406+ 	register struct componentname *cnp = ap->a_cnp;
4407+ 	struct u9fsnode *np;
4408+ 	struct u9fsreq req, rep;
4409+ 	struct u9fsmount *nmp;
4410+ 	struct proc * p;
4411+ 	int error;
4412+
4413+ 	nmp = VFSTOU9FS(vp->v_mount);
4414+ 	np = VTOU9FS(vp);
4415+ 	p = cnp->cn_proc;
4416+ 	bzero(&req, sizeof(req));
4417+ 	req.r_nmp = nmp;
4418+ 	req.r_procp = p;
4419+ 	req.r_type = Tremove;
4420+ 	req.r_fid = np->n_fid;
4421+ 	error = u9fs_request(&req, &rep, 1);
4422+ 	if( error )
4423+ 	  return error;
4424+ 	u9fs_id_free(nmp->nm_fids, np->n_fid);
4425+ 	np->n_fid = 0;
4426+ 	zfree(namei_zone, cnp->cn_pnbuf);
4427+ 	return 0;
4428+ }
4429+
4430+ /*
4431+  * u9fs readdir call
4432+  */
4433+ static int
4434+ u9fs_readdir(ap)
4435+ 	struct vop_readdir_args /* {
4436+ 		struct vnode *a_vp;
4437+ 		struct uio *a_uio;
4438+ 		struct ucred *a_cred;
4439+ 	} */ *ap;
4440+ {
4441+   register struct vnode *vp = ap->a_vp;
4442+   register struct uio *uio = ap->a_uio;
4443+   int error;
4444+
4445+   if (vp->v_type != VDIR)
4446+     return (EPERM);
4447+
4448+   /*
4449+    * Call u9fs_bioread() to do the real work.
4450+    */
4451+   error = u9fs_bioread(vp, uio, 0, ap->a_cred, 0);
4452+
4453+   return (error);
4454+ }
4455+
4456+ /*
4457+  * Kludge City..
4458+  * - make u9fs_bmap() essentially a no-op that does no translation
4459+  * - do u9fs_strategy() by doing I/O with u9fs_readrpc/u9fs_writerpc
4460+  *   (Maybe I could use the process's page mapping, but I was concerned that
4461+  *    Kernel Write might not be enabled and also figured copyout() would do
4462+  *    a lot more work than bcopy() and also it currently happens in the
4463+  *    context of the swapper process (2).
4464+  */
4465+ static int
4466+ u9fs_bmap(ap)
4467+ 	struct vop_bmap_args /* {
4468+ 		struct vnode *a_vp;
4469+ 		daddr_t  a_bn;
4470+ 		struct vnode **a_vpp;
4471+ 		daddr_t *a_bnp;
4472+ 		int *a_runp;
4473+ 		int *a_runb;
4474+ 	} */ *ap;
4475+ {
4476+   register struct vnode *vp = ap->a_vp;
4477+
4478+   if (ap->a_vpp != NULL)
4479+     *ap->a_vpp = vp;
4480+   if (ap->a_bnp != NULL)
4481+     *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
4482+   if (ap->a_runp != NULL)
4483+     *ap->a_runp = 0;
4484+   if (ap->a_runb != NULL)
4485+     *ap->a_runb = 0;
4486+   return (0);
4487+
4488+   return 0;
4489+ }
4490+
4491+ /*
4492+  * Strategy routine.
4493+  * For async requests when u9fsiod(s) are running, queue the request by
4494+  * calling u9fs_asyncio(), otherwise just all u9fs_doio() to do the
4495+  * request.
4496+  */
4497+ static int
4498+ u9fs_strategy(ap)
4499+ 	struct vop_strategy_args *ap;
4500+ {
4501+ 	register struct buf *bp = ap->a_bp;
4502+ 	struct ucred *cr;
4503+ 	struct proc *p;
4504+ 	int error = 0;
4505+
4506+ 	if (bp->b_flags & B_PHYS)
4507+ 		panic("nfs physio");
4508+ 	if (bp->b_flags & B_ASYNC)
4509+ 	        panic("u9fs async");
4510+
4511+ 	p = curproc;	/* XXX */
4512+ 	if (bp->b_flags & B_READ)
4513+ 		cr = bp->b_rcred;
4514+ 	else
4515+ 		cr = bp->b_wcred;
4516+ 	error = u9fs_doio(bp, cr, p);
4517+ 	return (error);
4518+ }
4519+
4520+ /*
4521+  * Mmap a file
4522+  *
4523+  * NB Currently unsupported.
4524+  */
4525+ /* ARGSUSED */
4526+ static int
4527+ u9fs_mmap(ap)
4528+ 	struct vop_mmap_args /* {
4529+ 		struct vnode *a_vp;
4530+ 		int  a_fflags;
4531+ 		struct ucred *a_cred;
4532+ 		struct proc *a_p;
4533+ 	} */ *ap;
4534+ {
4535+ 	return (EINVAL);
4536+ }
4537+
4538+ /*
4539+  * fsync vnode op. Just call u9fs_flush() with commit == 1.
4540+  */
4541+ /* ARGSUSED */
4542+ static int
4543+ u9fs_fsync(ap)
4544+ 	struct vop_fsync_args /* {
4545+ 		struct vnodeop_desc *a_desc;
4546+ 		struct vnode * a_vp;
4547+ 		struct ucred * a_cred;
4548+ 		int  a_waitfor;
4549+ 		struct proc * a_p;
4550+ 	} */ *ap;
4551+ {
4552+   /* we have a blocking writeback cache */
4553+   return 0;
4554+ }
4555+
4556+ /*
4557+  * U9FS advisory byte-level locks.
4558+  * Currently unsupported.
4559+  */
4560+ static int
4561+ u9fs_advlock(ap)
4562+ 	struct vop_advlock_args /* {
4563+ 		struct vnode *a_vp;
4564+ 		caddr_t  a_id;
4565+ 		int  a_op;
4566+ 		struct flock *a_fl;
4567+ 		int  a_flags;
4568+ 	} */ *ap;
4569+ {
4570+ 	register struct u9fsnode *np = VTOU9FS(ap->a_vp);
4571+
4572+ 	/*
4573+ 	 * The following kludge is to allow diskless support to work
4574+ 	 * until a real NFS lockd is implemented. Basically, just pretend
4575+ 	 * that this is a local lock.
4576+ 	 */
4577+ 	return (lf_advlock(ap, &(np->n_lockf), np->n_size));
4578+ }
4579+
4580+ /*
4581+  * Print out the contents of an u9fsnode.
4582+  */
4583+ static int
4584+ u9fs_print(ap)
4585+ 	struct vop_print_args /* {
4586+ 		struct vnode *a_vp;
4587+ 	} */ *ap;
4588+ {
4589+   panic("u9fs_print");
4590+   return 0;
4591+ }
4592+
4593+ /*
4594+  * Just call u9fs_writebp() with the force argument set to 1.
4595+  */
4596+ static int
4597+ u9fs_bwrite(ap)
4598+ 	struct vop_bwrite_args /* {
4599+ 		struct vnode *a_bp;
4600+ 	} */ *ap;
4601+ {
4602+   panic("u9fs_bwrite");
4603+   return 0;
4604+ }
4605+
4606+ /*
4607+  * Vnode op for VM getpages.
4608+  */
4609+ static int
4610+ u9fs_getpages(ap)
4611+ 	struct vop_getpages_args /* {
4612+ 		struct vnode *a_vp;
4613+ 		vm_page_t *a_m;
4614+ 		int a_count;
4615+ 		int a_reqpage;
4616+ 		vm_ooffset_t a_offset;
4617+ 	} */ *ap;
4618+ {
4619+ 	int i, error, nextoff, size, toff, npages, count;
4620+ 	struct uio uio;
4621+ 	struct iovec iov;
4622+ 	vm_offset_t kva;
4623+ 	struct buf *bp;
4624+ 	struct vnode *vp;
4625+ 	struct proc *p;
4626+ 	struct ucred *cred;
4627+ 	struct u9fsmount *nmp;
4628+ 	vm_page_t *pages;
4629+
4630+ 	vp = ap->a_vp;
4631+ 	p = curproc;				/* XXX */
4632+ 	cred = curproc->p_ucred;		/* XXX */
4633+ 	nmp = VFSTOU9FS(vp->v_mount);
4634+ 	pages = ap->a_m;
4635+ 	count = ap->a_count;
4636+
4637+ 	if (vp->v_object == NULL) {
4638+ 		printf("u9fs_getpages: called with non-merged cache vnode??\n");
4639+ 		return VM_PAGER_ERROR;
4640+ 	}
4641+
4642+ 	/*
4643+ 	 * We use only the kva address for the buffer, but this is extremely
4644+ 	 * convienient and fast.
4645+ 	 */
4646+ 	bp = getpbuf();
4647+
4648+ 	npages = btoc(count);
4649+ 	kva = (vm_offset_t) bp->b_data;
4650+ 	pmap_qenter(kva, pages, npages);
4651+
4652+ 	iov.iov_base = (caddr_t) kva;
4653+ 	iov.iov_len = count;
4654+ 	uio.uio_iov = &iov;
4655+ 	uio.uio_iovcnt = 1;
4656+ 	uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
4657+ 	uio.uio_resid = count;
4658+ 	uio.uio_segflg = UIO_SYSSPACE;
4659+ 	uio.uio_rw = UIO_READ;
4660+ 	uio.uio_procp = p;
4661+
4662+ 	error = u9fs_readrpc(vp, &uio, cred);
4663+ 	pmap_qremove(kva, npages);
4664+
4665+ 	relpbuf(bp);
4666+
4667+ 	if (error && (uio.uio_resid == count))
4668+ 		return VM_PAGER_ERROR;
4669+
4670+ 	size = count - uio.uio_resid;
4671+
4672+ 	for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
4673+ 		vm_page_t m;
4674+ 		nextoff = toff + PAGE_SIZE;
4675+ 		m = pages[i];
4676+
4677+ 		m->flags &= ~PG_ZERO;
4678+
4679+ 		if (nextoff <= size) {
4680+ 			m->valid = VM_PAGE_BITS_ALL;
4681+ 			m->dirty = 0;
4682+ 		} else {
4683+ 			int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
4684+ 			vm_page_set_validclean(m, 0, nvalid);
4685+ 		}
4686+
4687+ 		if (i != ap->a_reqpage) {
4688+ 			/*
4689+ 			 * Whether or not to leave the page activated is up in
4690+ 			 * the air, but we should put the page on a page queue
4691+ 			 * somewhere (it already is in the object).  Result:
4692+ 			 * It appears that emperical results show that
4693+ 			 * deactivating pages is best.
4694+ 			 */
4695+
4696+ 			/*
4697+ 			 * Just in case someone was asking for this page we
4698+ 			 * now tell them that it is ok to use.
4699+ 			 */
4700+ 			if (!error) {
4701+ 				if (m->flags & PG_WANTED)
4702+ 					vm_page_activate(m);
4703+ 				else
4704+ 					vm_page_deactivate(m);
4705+ 				vm_page_wakeup(m);
4706+ 			} else {
4707+ 				vnode_pager_freepage(m);
4708+ 			}
4709+ 		}
4710+ 	}
4711+ 	return 0;
4712+ }
4713+
4714+ /*
4715+  * Vnode op for VM putpages.
4716+  */
4717+ static int
4718+ u9fs_putpages(ap)
4719+ 	struct vop_putpages_args /* {
4720+ 		struct vnode *a_vp;
4721+ 		vm_page_t *a_m;
4722+ 		int a_count;
4723+ 		int a_sync;
4724+ 		int *a_rtvals;
4725+ 		vm_ooffset_t a_offset;
4726+ 	} */ *ap;
4727+ {
4728+   panic("u9fs_putpages");
4729+   return 0;
4730+ }
4731+
4732+ static int
4733+ u9fs_inactive(ap)
4734+ 	struct vop_inactive_args /* {
4735+ 		struct vnode *a_vp;
4736+ 		struct proc *a_p;
4737+ 	} */ *ap;
4738+ {
4739+   VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
4740+   return 0;
4741+ }
4742+
4743+ /*
4744+  * Reclaim an u9fsnode so that it can be used for other purposes.
4745+  */
4746+ static int
4747+ u9fs_reclaim(ap)
4748+ 	struct vop_reclaim_args /* {
4749+ 		struct vnode *a_vp;
4750+ 	} */ *ap;
4751+ {
4752+ 	register struct vnode *vp = ap->a_vp;
4753+ 	register struct u9fsnode *np = VTOU9FS(vp);
4754+ 	register struct u9fsmount *nmp = VFSTOU9FS(vp->v_mount);
4755+ 	struct proc * p = curproc;
4756+
4757+ 	/* some vnodes do not have fids due to previous access failure */
4758+ 	if( np->n_fid ) {
4759+ 	  /* clunk fids */
4760+ 	  u9fs_free_fid(np->n_fid, nmp, p);
4761+ 	  if( np->n_rdfid )
4762+ 	    u9fs_free_fid(np->n_rdfid, nmp, p);
4763+ 	  if( np->n_wrfid )
4764+ 	    u9fs_free_fid(np->n_wrfid, nmp, p);
4765+ 	}
4766+
4767+ 	LIST_REMOVE(np, n_hash);
4768+ 	cache_purge(vp);
4769+ 	zfree(u9fsnode_zone, vp->v_data);
4770+ 	vp->v_data = (void *)0;
4771+
4772+ 	return (0);
4773+ }
4774+
4775+ /*
4776+  * Vnode op for write using bio
4777+  */
4778+ static int
4779+ u9fs_write(ap)
4780+ 	struct vop_write_args /* {
4781+ 		struct vnode *a_vp;
4782+ 		struct uio *a_uio;
4783+ 		int  a_ioflag;
4784+ 		struct ucred *a_cred;
4785+ 	} */ *ap;
4786+ {
4787+   if (ap->a_vp->v_type != VREG)
4788+     return (EIO);
4789+
4790+   return u9fs_biowrite(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
4791+ }
4792+
4793+ /*
4794+  * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually
4795+  * done. Currently nothing to do.
4796+  */
4797+ /* ARGSUSED */
4798+ static int
4799+ u9fs_abortop(ap)
4800+ 	struct vop_abortop_args /* {
4801+ 		struct vnode *a_dvp;
4802+ 		struct componentname *a_cnp;
4803+ 	} */ *ap;
4804+ {
4805+ 	return (0);
4806+ }
4807+
4808+ /*
4809+  * u9fs write call
4810+  */
4811+ int
4812+ u9fs_writerpc(vp, uiop, cred)
4813+ 	register struct vnode *vp;
4814+ 	register struct uio *uiop;
4815+ 	struct ucred *cred;
4816+ {
4817+   struct u9fsmount *nmp = VFSTOU9FS(vp->v_mount);
4818+   int error = 0, len, tsiz, rlen;
4819+   struct u9fsreq req, rep;
4820+   struct u9fsnode * np = VTOU9FS(vp);
4821+   struct proc * p = uiop->uio_procp;
4822+   struct mbuf * top;
4823+
4824+   tsiz = uiop->uio_resid;
4825+   if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
4826+     return (EFBIG);
4827+   bzero(&req, sizeof(req));
4828+   req.r_nmp = nmp;
4829+   req.r_procp = p;
4830+   req.r_type = Twrite;
4831+   req.r_fid = np->n_wrfid;
4832+   while (tsiz > 0) {
4833+     len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
4834+     req.r_offset = uiop->uio_offset;
4835+     req.r_count = len;
4836+     error = u9fs_uiotombuf(uiop, &top, len);
4837+     if( error )
4838+       break;
4839+     req.r_data = (char *)top;
4840+     error = u9fs_request(&req, &rep, 1);
4841+     if( error )
4842+       break;
4843+     rlen = rep.r_count;
4844+     if( rlen < len ) {
4845+       error = EIO;
4846+       break;
4847+     }
4848+     tsiz -= len;
4849+
4850+     /* each write message increments version number by one.
4851+        to avoid flushing our write cache, update the version */
4852+     if( np->n_qid.vers )
4853+       np->n_qid.vers++;
4854+     else
4855+       np->n_qid.vers = np->n_dir.dir_qid.vers + 1;
4856+   }
4857+   if (error)
4858+     uiop->uio_resid = tsiz;
4859+   return (error);
4860+ }
4861+
4862+ /*
4863+  * Readdir rpc call.
4864+  * Called from below the buffer cache by u9fs_doio().
4865+  */
4866+ int
4867+ u9fs_readdirrpc(vp, uiop, cred)
4868+ 	struct vnode *vp;
4869+ 	register struct uio *uiop;
4870+ 	struct ucred *cred;
4871+
4872+ {
4873+ 	register int len, left;
4874+ 	register struct dirent *dp;
4875+ 	struct u9fsmount *nmp = VFSTOU9FS(vp->v_mount);
4876+ 	struct u9fsnode *np = VTOU9FS(vp);
4877+ 	int error = 0, tlen, more_dirs = 1, bigenough;
4878+ 	struct u9fsreq req, rep;
4879+ 	int count;
4880+ 	struct u9fsdir u9dir;
4881+
4882+ 	bigenough = uiop->uio_resid >= sizeof(struct dirent);
4883+ 	bzero(&req, sizeof(req));
4884+ 	req.r_nmp = nmp;
4885+ 	req.r_type = Tread;
4886+ 	req.r_fid = np->n_rdfid;
4887+ 	req.r_count = nmp->nm_readdirsize;
4888+ 	while ( more_dirs && bigenough ) {
4889+ 	  req.r_offset = uiop->uio_offset;
4890+ 	  error = u9fs_request(&req, &rep, 0);
4891+ 	  if( error )
4892+ 	    return error;
4893+
4894+ 	  count = rep.r_count;
4895+ 	  more_dirs = (count == req.r_count);
4896+ 	  len = 0;
4897+ 	  dp = (struct dirent *)uiop->uio_iov->iov_base;
4898+ 	  left = uiop->uio_resid;
4899+ 	  while( len < count ) {
4900+ 	    /* XXX: too conservative, but OK */
4901+ 	    if( left < sizeof(*dp) ) {
4902+ 	      bigenough = 0;
4903+ 	      break;
4904+ 	    }
4905+ 	    if( u9p_m_m2d(&req.r_mrep, & u9dir) ) {
4906+ 	      printf("u9p_m_m2d failed!\n");
4907+ 	      return (EIO);
4908+ 	    }
4909+
4910+ 	    dp->d_fileno = u9dir.dir_qid.path;
4911+ 	    if( U9P_PERM_CHDIR(u9dir.dir_mode) )
4912+ 	      dp->d_type = DT_DIR;
4913+ 	    else
4914+ 	      dp->d_type = DT_REG;
4915+ 	    u9dir.dir_name[U9FS_NAMELEN-1] = 0; /* just to be sure */
4916+ 	    dp->d_namlen = strlen(u9dir.dir_name);
4917+ 	    memcpy(dp->d_name, u9dir.dir_name, dp->d_namlen+1);
4918+ 	    tlen = DIRHDSIZ + dp->d_namlen + 4;
4919+ 	    tlen = tlen - (tlen & 0x3);
4920+ 	    dp->d_reclen = tlen;
4921+ 	    dp = (struct dirent *)(((char *)dp) + tlen);
4922+ 	    left -= tlen;
4923+ 	    len += sizeof(u9dir);
4924+ 	  }
4925+ 	  tlen = uiop->uio_resid - left;
4926+ 	  uiop->uio_resid = left;
4927+ 	  uiop->uio_iov->iov_base += tlen;
4928+ 	  uiop->uio_iov->iov_len -= tlen;
4929+ 	  uiop->uio_offset += len;
4930+ 	  m_freem(req.r_mrep);
4931+ 	}
4932+ 	return 0;
4933+ }
4934+
4935+ /*
4936+  * u9fs read rpc call
4937+  * Ditto above
4938+  */
4939+ int
4940+ u9fs_readrpc(vp, uiop, cred)
4941+ 	register struct vnode *vp;
4942+ 	struct uio *uiop;
4943+ 	struct ucred *cred;
4944+ {
4945+   struct u9fsmount *nmp;
4946+   struct u9fsnode *np = VTOU9FS(vp);
4947+   int error = 0, len, retlen, tsiz;
4948+   struct u9fsreq req, rep;
4949+
4950+   nmp = VFSTOU9FS(vp->v_mount);
4951+   tsiz = uiop->uio_resid;
4952+   if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
4953+     return (EFBIG);
4954+   bzero(&req, sizeof(req));
4955+   req.r_nmp = nmp;
4956+   req.r_type = Tread;
4957+   req.r_fid = np->n_rdfid;
4958+   while (tsiz > 0) {
4959+     len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
4960+     req.r_count = len;
4961+     req.r_offset = uiop->uio_offset;
4962+     error = u9fs_request(&req, &rep, 0);
4963+     if( error )
4964+       return error;
4965+     retlen = rep.r_count;
4966+     if( retlen && (error = u9fs_mbuftouio(req.r_mrep, uiop, retlen)) ) {
4967+       m_freem(req.r_mrep);
4968+       return error;
4969+     }
4970+
4971+     m_freem(req.r_mrep);
4972+     req.r_mrep = 0;
4973+     tsiz -= retlen;
4974+     if (retlen < len)
4975+       tsiz = 0;
4976+   }
4977+   return (0);
4978+ }
4979+
4980+ static void u9fs_free_fid(fid, nmp, p)
4981+      u_short fid;
4982+      struct u9fsmount * nmp;
4983+      struct proc * p;
4984+ {
4985+   struct u9fsreq req, rep;
4986+
4987+   /* clunk fid */
4988+   bzero(&req, sizeof(req));
4989+   req.r_nmp = nmp;
4990+   req.r_procp = p;
4991+   req.r_type = Tclunk;
4992+   req.r_fid = fid;
4993+   u9fs_request(&req, &rep, 1);
4994+   u9fs_id_free(nmp->nm_fids, fid);
4995+ }
4996diff -N -c -r /usr/src/sys/9fs/9p.c ./9fs/9p.c
4997*** /usr/src/sys/9fs/9p.c	Wed Dec 31 19:00:00 1969
4998--- ./9fs/9p.c	Thu Nov 25 15:04:16 1999
4999***************
5000*** 0 ****
5001--- 1,974 ----
5002+ #include <sys/param.h>
5003+ #include <sys/systm.h>
5004+ #include <sys/socket.h>
5005+ #include <sys/socketvar.h>
5006+ #include <netinet/in.h>
5007+ #include <sys/mbuf.h>
5008+ #include <sys/malloc.h>
5009+ #include <sys/vnode.h>
5010+ #include <sys/mount.h>
5011+
5012+ #include <9fs/bitstring.h>
5013+ #include <9fs/9p.h>
5014+ #include <9fs/9auth.h>
5015+ #include <9fs/9fs.h>
5016+
5017+ int u9p_usetcp = 0;
5018+ struct u9fs_reqq u9fs_reqq;
5019+
5020+ #define	N2HCHAR(x)		x = *p++
5021+ #define	N2HSHORT(x)	x = (p[0] | (p[1]<<8)); p += 2
5022+ #define	N2HLONG(x)		x = (p[0] | (p[1]<<8) |\
5023+ 				(p[2]<<16) | (p[3]<<24)); p += 4
5024+ #define	N2HQUAD(x)	x = (u_int64_t)(p[0] | (p[1]<<8) |\
5025+ 					(p[2]<<16) | (p[3]<<24)) |\
5026+ 				((u_int64_t)(p[4] | (p[5]<<8) |\
5027+ 					(p[6]<<16) | (p[7]<<24)) << 32); p += 8
5028+ #define	N2HSTRING(x,n)	bcopy(p, x, n); p += n
5029+
5030+ #define	H2NCHAR(x)	*p++ = x
5031+ #define	H2NSHORT(x)	p[0]=x; p[1]=x>>8; p += 2
5032+ #define	H2NLONG(x)		p[0]=x; p[1]=x>>8; p[2]=x>>16; p[3]=x>>24; p += 4
5033+ #define	H2NQUAD(x)	p[0]=x;	p[1]=x>>8;\
5034+ 			p[2]=x>>16;	p[3]=x>>24;\
5035+ 			p[4]=x>>32;	p[5]=x>>40;\
5036+ 			p[6]=x>>48;	p[7]=x>>56;\
5037+ 			p += 8
5038+ #define	H2NSTRING(x,n)	bcopy(x, p, n); p += n
5039+
5040+ static void u9p_print __P((u_char * m, int len, struct u9fsreq * f));
5041+
5042+ static char * u9p_types[] = {
5043+   "Tnop",
5044+   "Rnop",
5045+   "Tosession",
5046+   "Rosession",
5047+   "Terror",
5048+   "Rerror",
5049+   "Tflush",
5050+   "Rflush",
5051+   "Toattach",
5052+   "Roattach",
5053+   "Tclone",
5054+   "Rclone",
5055+   "Twalk",
5056+   "Rwalk",
5057+   "Topen",
5058+   "Ropen",
5059+   "Tcreate",
5060+   "Rcreate",
5061+   "Tread",
5062+   "Rread",
5063+   "Twrite",
5064+   "Rwrite",
5065+   "Tclunk",
5066+   "Rclunk",
5067+   "Tremove",
5068+   "Rremove",
5069+   "Tstat",
5070+   "Rstat",
5071+   "Twstat",
5072+   "Rwstat",
5073+   "Tclwalk",
5074+   "Rclwalk",
5075+   "Tauth",
5076+   "Rauth",
5077+   "Tsession",
5078+   "Rsession",
5079+   "Tattach",
5080+   "Rattach",
5081+   "Ttunnel",
5082+   "Rtunnel",
5083+   "Tmax"
5084+ };
5085+
5086+ int u9p_m2s(char *ap, int n, struct u9fsreq *f)
5087+ {
5088+ 	u_char *p;
5089+
5090+ 	p = (u_char*)ap;
5091+ 	N2HCHAR(f->r_type);
5092+ 	N2HSHORT(f->r_tag);
5093+ 	switch(f->r_type)
5094+ 	{
5095+ 	default:
5096+ 		return 0;
5097+
5098+ 	case Tnop:
5099+ 	case Tosession:
5100+ 		break;
5101+
5102+ 	case Tsession:
5103+ 		N2HSTRING(f->r_chal, sizeof(f->r_chal));
5104+ 		break;
5105+
5106+ 	case Tflush:
5107+ 		N2HSHORT(f->r_oldtag);
5108+ 		break;
5109+
5110+ 	case Tattach:
5111+ 		N2HSHORT(f->r_fid);
5112+ 		N2HSTRING(f->r_uname, sizeof(f->r_uname));
5113+ 		N2HSTRING(f->r_aname, sizeof(f->r_aname));
5114+ 		N2HSTRING(f->r_ticket, sizeof(f->r_ticket));
5115+ 		N2HSTRING(f->r_auth, sizeof(f->r_auth));
5116+ 		break;
5117+
5118+ 	case Toattach:
5119+ 		N2HSHORT(f->r_fid);
5120+ 		N2HSTRING(f->r_uname, sizeof(f->r_uname));
5121+ 		N2HSTRING(f->r_aname, sizeof(f->r_aname));
5122+ 		N2HSTRING(f->r_ticket, U9FS_NAMELEN);
5123+ 		break;
5124+
5125+ 	case Tauth:
5126+ 		N2HSHORT(f->r_fid);
5127+ 		N2HSTRING(f->r_uname, sizeof(f->r_uname));
5128+ 		N2HSTRING(f->r_ticket, 8+U9FS_NAMELEN);
5129+ 		break;
5130+
5131+ 	case Tclone:
5132+ 		N2HSHORT(f->r_fid);
5133+ 		N2HSHORT(f->r_newfid);
5134+ 		break;
5135+
5136+ 	case Twalk:
5137+ 		N2HSHORT(f->r_fid);
5138+ 		N2HSTRING(f->r_name, sizeof(f->r_name));
5139+ 		break;
5140+
5141+ 	case Topen:
5142+ 		N2HSHORT(f->r_fid);
5143+ 		N2HCHAR(f->r_mode);
5144+ 		break;
5145+
5146+ 	case Tcreate:
5147+ 		N2HSHORT(f->r_fid);
5148+ 		N2HSTRING(f->r_name, sizeof(f->r_name));
5149+ 		N2HLONG(f->r_perm);
5150+ 		N2HCHAR(f->r_mode);
5151+ 		break;
5152+
5153+ 	case Tread:
5154+ 		N2HSHORT(f->r_fid);
5155+ 		N2HQUAD(f->r_offset);
5156+ 		N2HSHORT(f->r_count);
5157+ 		break;
5158+
5159+ 	case Twrite:
5160+ 		N2HSHORT(f->r_fid);
5161+ 		N2HQUAD(f->r_offset);
5162+ 		N2HSHORT(f->r_count);
5163+ 		p++;	/* pad(1) */
5164+ 		f->r_data = (char*)p; p += f->r_count;
5165+ 		break;
5166+
5167+ 	case Ttunnel:
5168+ 		N2HSHORT(f->r_fid);
5169+ 		break;
5170+
5171+ 	case Tclunk:
5172+ 		N2HSHORT(f->r_fid);
5173+ 		break;
5174+
5175+ 	case Tremove:
5176+ 		N2HSHORT(f->r_fid);
5177+ 		break;
5178+
5179+ 	case Tstat:
5180+ 		N2HSHORT(f->r_fid);
5181+ 		break;
5182+
5183+ 	case Twstat:
5184+ 		N2HSHORT(f->r_fid);
5185+ 		N2HSTRING(f->r_stat, sizeof(f->r_stat));
5186+ 		break;
5187+
5188+ 	case Tclwalk:
5189+ 		N2HSHORT(f->r_fid);
5190+ 		N2HSHORT(f->r_newfid);
5191+ 		N2HSTRING(f->r_name, sizeof(f->r_name));
5192+ 		break;
5193+ /*
5194+  */
5195+ 	case Rnop:
5196+ 	case Rosession:
5197+ 		break;
5198+
5199+ 	case Rsession:
5200+ 		N2HSTRING(f->r_chal, sizeof(f->r_chal));
5201+ 		N2HSTRING(f->r_authid, sizeof(f->r_authid));
5202+ 		N2HSTRING(f->r_authdom, sizeof(f->r_authdom));
5203+ 		break;
5204+
5205+ 	case Rerror:
5206+ 		N2HSTRING(f->r_ename, sizeof(f->r_ename));
5207+ 		break;
5208+
5209+ 	case Rflush:
5210+ 		break;
5211+
5212+ 	case Rattach:
5213+ 		N2HSHORT(f->r_fid);
5214+ 		N2HLONG(f->r_qid.path);
5215+ 		N2HLONG(f->r_qid.vers);
5216+ 		N2HSTRING(f->r_rauth, sizeof(f->r_rauth));
5217+ 		break;
5218+
5219+ 	case Roattach:
5220+ 		N2HSHORT(f->r_fid);
5221+ 		N2HLONG(f->r_qid.path);
5222+ 		N2HLONG(f->r_qid.vers);
5223+ 		break;
5224+
5225+ 	case Rauth:
5226+ 		N2HSHORT(f->r_fid);
5227+ 		N2HSTRING(f->r_ticket, 8+8+7+7);
5228+ 		break;
5229+
5230+ 	case Rclone:
5231+ 		N2HSHORT(f->r_fid);
5232+ 		break;
5233+
5234+ 	case Rwalk:
5235+ 	case Rclwalk:
5236+ 		N2HSHORT(f->r_fid);
5237+ 		N2HLONG(f->r_qid.path);
5238+ 		N2HLONG(f->r_qid.vers);
5239+ 		break;
5240+
5241+ 	case Ropen:
5242+ 		N2HSHORT(f->r_fid);
5243+ 		N2HLONG(f->r_qid.path);
5244+ 		N2HLONG(f->r_qid.vers);
5245+ 		break;
5246+
5247+ 	case Rcreate:
5248+ 		N2HSHORT(f->r_fid);
5249+ 		N2HLONG(f->r_qid.path);
5250+ 		N2HLONG(f->r_qid.vers);
5251+ 		break;
5252+
5253+ 	case Rread:
5254+ 		N2HSHORT(f->r_fid);
5255+ 		N2HSHORT(f->r_count);
5256+ 		p++;	/* pad(1) */
5257+ 		f->r_data = (char*)p; p += f->r_count;
5258+ 		break;
5259+
5260+ 	case Rwrite:
5261+ 		N2HSHORT(f->r_fid);
5262+ 		N2HSHORT(f->r_count);
5263+ 		break;
5264+
5265+ 	case Rtunnel:
5266+ 		N2HSHORT(f->r_fid);
5267+ 		break;
5268+
5269+ 	case Rclunk:
5270+ 		N2HSHORT(f->r_fid);
5271+ 		break;
5272+
5273+ 	case Rremove:
5274+ 		N2HSHORT(f->r_fid);
5275+ 		break;
5276+
5277+ 	case Rstat:
5278+ 		N2HSHORT(f->r_fid);
5279+ 		N2HSTRING(f->r_stat, sizeof(f->r_stat));
5280+ 		break;
5281+
5282+ 	case Rwstat:
5283+ 		N2HSHORT(f->r_fid);
5284+ 		break;
5285+ 	}
5286+ 	if((u_char*)ap+n == p)
5287+ 		return n;
5288+ 	return 0;
5289+ }
5290+
5291+ void u9p_print(u_char * m, int len, struct u9fsreq * f)
5292+ {
5293+   struct u9fsreq u9fsreq;
5294+
5295+   if( f == 0 )
5296+     f = & u9fsreq;
5297+
5298+   if( len < 3 ) {
5299+     printf("truncated-9p %d", len);
5300+     return;
5301+   }
5302+
5303+   if( u9p_m2s((char *)m, len, f) == 0 )
5304+     return;
5305+
5306+   printf("%s tag %d ", u9p_types[f->r_type-Tnop], f->r_tag);
5307+
5308+   switch( f->r_type ) {
5309+ 	default:
5310+ 	  return;
5311+
5312+ 	case Tnop:
5313+ 	case Tosession:
5314+ 	case Toattach:
5315+ 	case Tauth:
5316+ 		break;
5317+
5318+ 	case Tsession:
5319+ 	case Rsession:
5320+ 	  printf("chal 0x%x 0x%x", *(u_int *)&f->r_chal[0], *(u_int *)&f->r_chal[4]);
5321+ 		break;
5322+
5323+ 	case Tflush:
5324+ 	  printf("oldtag %d", f->r_oldtag);
5325+ 		break;
5326+
5327+ 	case Tclone:
5328+ 	  printf("fid %d newfid %d", f->r_fid, f->r_newfid);
5329+ 		break;
5330+
5331+ 	case Twalk:
5332+ 	  printf("fid %d name %s", f->r_fid, f->r_name);
5333+ 		break;
5334+
5335+ 	case Topen:
5336+ 	  printf("fid %d %c", f->r_fid, f->r_mode);
5337+ 		break;
5338+
5339+ 	case Tcreate:
5340+ 	  printf("fid %d name %s perm 0x%x mode %c", f->r_fid,
5341+ 		 f->r_name, f->r_perm, f->r_mode);
5342+ 		break;
5343+
5344+ 	case Tread:
5345+ 	case Twrite:
5346+ 	  printf("fid %d offset 0x%llx count %d", f->r_fid,
5347+ 		 f->r_offset, f->r_count);
5348+ 		break;
5349+
5350+ 	case Tattach:
5351+ 	case Ttunnel:
5352+ 	case Tclunk:
5353+ 	case Tremove:
5354+ 	case Tstat:
5355+ 	case Twstat:
5356+ 	case Rclone:
5357+ 	case Rtunnel:
5358+ 	case Rclunk:
5359+ 	case Rremove:
5360+ 	case Rstat:
5361+ 	case Rwstat:
5362+ 	  printf("fid %d", f->r_fid);
5363+ 		break;
5364+
5365+ 	case Tclwalk:
5366+ 	  printf("fid %d ", f->r_fid);
5367+ 	  printf("newfid  %d ", f->r_newfid);
5368+ 	  printf("name %s", f->r_name);
5369+ 		break;
5370+ /*
5371+  */
5372+ 	case Rnop:
5373+ 	case Rosession:
5374+ 	case Rflush:
5375+ 	case Roattach:
5376+ 	case Rauth:
5377+ 		break;
5378+
5379+ 	case Rerror:
5380+ 	  printf("ename %s", f->r_ename);
5381+ 		break;
5382+
5383+ 	case Rattach:
5384+ 	case Rwalk:
5385+ 	case Rclwalk:
5386+ 	case Ropen:
5387+ 	case Rcreate:
5388+ 	  printf("fid %d ", f->r_fid);
5389+ 	  printf("qid 0x%x 0x%x", f->r_qid.path, f->r_qid.vers);
5390+ 		break;
5391+
5392+ 	case Rread:
5393+ 	  printf("fid %d count %d ", f->r_fid, f->r_count);
5394+ 	  break;
5395+
5396+ 	case Rwrite:
5397+ 	  printf("fid %d count %d", f->r_fid, f->r_count);
5398+ 		break;
5399+   }
5400+ }
5401+
5402+ int
5403+ u9p_s2m(struct u9fsreq *f, char *ap, int copydata)
5404+ {
5405+ 	u_char *p;
5406+
5407+ 	p = (u_char*)ap;
5408+ 	H2NCHAR(f->r_type);
5409+ 	H2NSHORT(f->r_tag);
5410+ 	switch(f->r_type)
5411+ 	{
5412+ 	default:
5413+ 		return 0;
5414+
5415+ 	case Tosession:
5416+ 	case Tnop:
5417+ 		break;
5418+
5419+ 	case Tsession:
5420+ 		H2NSTRING(f->r_chal, sizeof(f->r_chal));
5421+ 		break;
5422+
5423+ 	case Tflush:
5424+ 		H2NSHORT(f->r_oldtag);
5425+ 		break;
5426+
5427+ 	case Tattach:
5428+ 		H2NSHORT(f->r_fid);
5429+ 		H2NSTRING(f->r_uname, sizeof(f->r_uname));
5430+ 		H2NSTRING(f->r_aname, sizeof(f->r_aname));
5431+ 		H2NSTRING(f->r_ticket, sizeof(f->r_ticket));
5432+ 		H2NSTRING(f->r_auth, sizeof(f->r_auth));
5433+ 		break;
5434+
5435+ 	case Toattach:
5436+ 		H2NSHORT(f->r_fid);
5437+ 		H2NSTRING(f->r_uname, sizeof(f->r_uname));
5438+ 		H2NSTRING(f->r_aname, sizeof(f->r_aname));
5439+ 		H2NSTRING(f->r_ticket, U9FS_NAMELEN);
5440+ 		break;
5441+
5442+ 	case Tauth:
5443+ 		H2NSHORT(f->r_fid);
5444+ 		H2NSTRING(f->r_uname, sizeof(f->r_uname));
5445+ 		H2NSTRING(f->r_ticket, 8+U9FS_NAMELEN);
5446+ 		break;
5447+
5448+ 	case Tclone:
5449+ 		H2NSHORT(f->r_fid);
5450+ 		H2NSHORT(f->r_newfid);
5451+ 		break;
5452+
5453+ 	case Twalk:
5454+ 		H2NSHORT(f->r_fid);
5455+ 		H2NSTRING(f->r_name, sizeof(f->r_name));
5456+ 		break;
5457+
5458+ 	case Topen:
5459+ 		H2NSHORT(f->r_fid);
5460+ 		H2NCHAR(f->r_mode);
5461+ 		break;
5462+
5463+ 	case Tcreate:
5464+ 		H2NSHORT(f->r_fid);
5465+ 		H2NSTRING(f->r_name, sizeof(f->r_name));
5466+ 		H2NLONG(f->r_perm);
5467+ 		H2NCHAR(f->r_mode);
5468+ 		break;
5469+
5470+ 	case Tread:
5471+ 		H2NSHORT(f->r_fid);
5472+ 		H2NQUAD(f->r_offset);
5473+ 		H2NSHORT(f->r_count);
5474+ 		break;
5475+
5476+ 	case Twrite:
5477+ 		H2NSHORT(f->r_fid);
5478+ 		H2NQUAD(f->r_offset);
5479+ 		H2NSHORT(f->r_count);
5480+ 		p++;	/* pad(1) */
5481+ 		if( copydata ) {
5482+ 		  H2NSTRING(f->r_data, f->r_count);
5483+ 		}
5484+ 		break;
5485+
5486+ 	case Ttunnel:
5487+ 		H2NSHORT(f->r_fid);
5488+ 		break;
5489+
5490+ 	case Tclunk:
5491+ 		H2NSHORT(f->r_fid);
5492+ 		break;
5493+
5494+ 	case Tremove:
5495+ 		H2NSHORT(f->r_fid);
5496+ 		break;
5497+
5498+ 	case Tstat:
5499+ 		H2NSHORT(f->r_fid);
5500+ 		break;
5501+
5502+ 	case Twstat:
5503+ 		H2NSHORT(f->r_fid);
5504+ 		H2NSTRING(f->r_stat, sizeof(f->r_stat));
5505+ 		break;
5506+
5507+ 	case Tclwalk:
5508+ 		H2NSHORT(f->r_fid);
5509+ 		H2NSHORT(f->r_newfid);
5510+ 		H2NSTRING(f->r_name, sizeof(f->r_name));
5511+ 		break;
5512+ /*
5513+  */
5514+ 	case Rosession:
5515+ 	case Rnop:
5516+ 		break;
5517+
5518+ 	case Rsession:
5519+ 		H2NSTRING(f->r_chal, sizeof(f->r_chal));
5520+ 		H2NSTRING(f->r_authid, sizeof(f->r_authid));
5521+ 		H2NSTRING(f->r_authdom, sizeof(f->r_authdom));
5522+ 		break;
5523+
5524+ 	case Rerror:
5525+ 		H2NSTRING(f->r_ename, sizeof(f->r_ename));
5526+ 		break;
5527+
5528+ 	case Rflush:
5529+ 		break;
5530+
5531+ 	case Rattach:
5532+ 		H2NSHORT(f->r_fid);
5533+ 		H2NLONG(f->r_qid.path);
5534+ 		H2NLONG(f->r_qid.vers);
5535+ 		H2NSTRING(f->r_rauth, sizeof(f->r_rauth));
5536+ 		break;
5537+
5538+ 	case Roattach:
5539+ 		H2NSHORT(f->r_fid);
5540+ 		H2NLONG(f->r_qid.path);
5541+ 		H2NLONG(f->r_qid.vers);
5542+ 		break;
5543+
5544+ 	case Rauth:
5545+ 		H2NSHORT(f->r_fid);
5546+ 		H2NSTRING(f->r_ticket, 8+8+7+7);
5547+ 		break;
5548+
5549+ 	case Rclone:
5550+ 		H2NSHORT(f->r_fid);
5551+ 		break;
5552+
5553+ 	case Rwalk:
5554+ 	case Rclwalk:
5555+ 		H2NSHORT(f->r_fid);
5556+ 		H2NLONG(f->r_qid.path);
5557+ 		H2NLONG(f->r_qid.vers);
5558+ 		break;
5559+
5560+ 	case Ropen:
5561+ 		H2NSHORT(f->r_fid);
5562+ 		H2NLONG(f->r_qid.path);
5563+ 		H2NLONG(f->r_qid.vers);
5564+ 		break;
5565+
5566+ 	case Rcreate:
5567+ 		H2NSHORT(f->r_fid);
5568+ 		H2NLONG(f->r_qid.path);
5569+ 		H2NLONG(f->r_qid.vers);
5570+ 		break;
5571+
5572+ 	case Rread:
5573+ 		H2NSHORT(f->r_fid);
5574+ 		H2NSHORT(f->r_count);
5575+ 		p++;	/* pad(1) */
5576+ 		if( copydata ) {
5577+ 		  H2NSTRING(f->r_data, f->r_count);
5578+ 		}
5579+ 		break;
5580+
5581+ 	case Rwrite:
5582+ 		H2NSHORT(f->r_fid);
5583+ 		H2NSHORT(f->r_count);
5584+ 		break;
5585+
5586+ 	case Rtunnel:
5587+ 		H2NSHORT(f->r_fid);
5588+ 		break;
5589+
5590+ 	case Rclunk:
5591+ 		H2NSHORT(f->r_fid);
5592+ 		break;
5593+
5594+ 	case Rremove:
5595+ 		H2NSHORT(f->r_fid);
5596+ 		break;
5597+
5598+ 	case Rstat:
5599+ 		H2NSHORT(f->r_fid);
5600+ 		if( copydata )
5601+ 		  H2NSTRING(f->r_stat, sizeof(f->r_stat));
5602+ 		break;
5603+
5604+ 	case Rwstat:
5605+ 		H2NSHORT(f->r_fid);
5606+ 		break;
5607+ 	}
5608+ 	return p - (u_char*)ap;
5609+ }
5610+
5611+ int
5612+ u9p_m2d(char *ap, struct u9fsdir *f)
5613+ {
5614+ 	u_char *p;
5615+
5616+ 	p = (u_char*)ap;
5617+ 	N2HSTRING(f->dir_name, sizeof(f->dir_name));
5618+ 	N2HSTRING(f->dir_uid, sizeof(f->dir_uid));
5619+ 	N2HSTRING(f->dir_gid, sizeof(f->dir_gid));
5620+ 	N2HLONG(f->dir_qid.path);
5621+ 	N2HLONG(f->dir_qid.vers);
5622+ 	N2HLONG(f->dir_mode);
5623+ 	N2HLONG(f->dir_atime);
5624+ 	N2HLONG(f->dir_mtime);
5625+ 	N2HQUAD(f->dir_length);
5626+ 	N2HSHORT(f->dir_type);
5627+ 	N2HSHORT(f->dir_dev);
5628+ 	return p - (u_char*)ap;
5629+ }
5630+
5631+ int
5632+ u9p_d2m(struct u9fsdir *f, char *ap)
5633+ {
5634+ 	u_char *p;
5635+
5636+ 	p = (u_char*)ap;
5637+ 	H2NSTRING(f->dir_name, sizeof(f->dir_name));
5638+ 	H2NSTRING(f->dir_uid, sizeof(f->dir_uid));
5639+ 	H2NSTRING(f->dir_gid, sizeof(f->dir_gid));
5640+ 	H2NLONG(f->dir_qid.path);
5641+ 	H2NLONG(f->dir_qid.vers);
5642+ 	H2NLONG(f->dir_mode);
5643+ 	H2NLONG(f->dir_atime);
5644+ 	H2NLONG(f->dir_mtime);
5645+ 	H2NQUAD(f->dir_length);
5646+ 	H2NSHORT(f->dir_type);
5647+ 	H2NSHORT(f->dir_dev);
5648+ 	return p - (u_char*)ap;
5649+ }
5650+
5651+ /* parse 9P types */
5652+ int u9p_type(char * t)
5653+ {
5654+   int i;
5655+
5656+   for(i = 0; i < sizeof(u9p_types)/sizeof(u9p_types[0]); i++) {
5657+     if( strcmp(u9p_types[i], t) == 0 )
5658+       return (i+Tnop);
5659+   }
5660+   return 0;
5661+ }
5662+
5663+ /* m is freed if shorter than s */
5664+ #if 1
5665+ #define U9P_PULLUP(m,s)  if( (*(m))->m_len < (s) && ((*(m)) = m_pullup((*(m)),(s))) == 0 ) return 1; p = mtod((*(m)), u_char *)
5666+ #else
5667+ #define U9P_PULLUP(m,s)  if( (*(m))->m_len < (s) && ((*(m)) = m_pullup((*(m)),(s))) == 0 ) panic("PULLUP"); p = mtod((*(m)), u_char *)
5668+ #endif
5669+
5670+ #define U9P_ADJ(m,s) (*(m))->m_len -= (s); (*(m))->m_data += (s)
5671+
5672+ u_short u9p_m_tag(struct mbuf ** m)
5673+ {
5674+   char * p;
5675+   u_short t;
5676+
5677+   U9P_PULLUP(m,3);
5678+   p = mtod(*m, char *);
5679+   p++;
5680+   N2HSHORT(t);
5681+
5682+   return t;
5683+ }
5684+
5685+ int
5686+ u9p_m_m2s(struct mbuf **m, struct u9fsreq *f)
5687+ {
5688+   u_char *p;
5689+
5690+   U9P_PULLUP(m,3);
5691+   N2HCHAR(f->r_type);
5692+   N2HSHORT(f->r_tag);
5693+   U9P_ADJ(m, sizeof(f->r_type)+sizeof(f->r_tag));
5694+
5695+   switch(f->r_type) {
5696+   default:
5697+     goto drop;
5698+
5699+   case Tnop:
5700+     break;
5701+
5702+   case Tsession:
5703+     U9P_PULLUP(m,sizeof(f->r_chal));
5704+     N2HSTRING(f->r_chal, sizeof(f->r_chal));
5705+     U9P_ADJ(m, sizeof(f->r_chal));
5706+     break;
5707+
5708+   case Tflush:
5709+     U9P_PULLUP(m,sizeof(f->r_oldtag));
5710+     N2HSHORT(f->r_oldtag);
5711+     U9P_ADJ(m, f->r_oldtag);
5712+     break;
5713+
5714+   case Tattach:
5715+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_uname)+sizeof(f->r_aname));
5716+     N2HSHORT(f->r_fid);
5717+     N2HSTRING(f->r_uname, sizeof(f->r_uname));
5718+     N2HSTRING(f->r_aname, sizeof(f->r_aname));
5719+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_uname)+sizeof(f->r_aname));
5720+
5721+     U9P_PULLUP(m, sizeof(f->r_ticket)+sizeof(f->r_auth));
5722+     N2HSTRING(f->r_ticket, sizeof(f->r_ticket));
5723+     N2HSTRING(f->r_auth, sizeof(f->r_auth));
5724+     U9P_ADJ(m, sizeof(f->r_ticket)+sizeof(f->r_auth));
5725+     break;
5726+
5727+   case Tclone:
5728+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_newfid));
5729+     N2HSHORT(f->r_fid);
5730+     N2HSHORT(f->r_newfid);
5731+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_newfid));
5732+     break;
5733+
5734+   case Twalk:
5735+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_name));
5736+     N2HSHORT(f->r_fid);
5737+     N2HSTRING(f->r_name, sizeof(f->r_name));
5738+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_name));
5739+     break;
5740+
5741+   case Topen:
5742+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_mode));
5743+     N2HSHORT(f->r_fid);
5744+     N2HCHAR(f->r_mode);
5745+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_mode));
5746+     break;
5747+
5748+   case Tcreate:
5749+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_name)
5750+ 	       +sizeof(f->r_perm)+sizeof(f->r_mode));
5751+     N2HSHORT(f->r_fid);
5752+     N2HSTRING(f->r_name, sizeof(f->r_name));
5753+     N2HLONG(f->r_perm);
5754+     N2HCHAR(f->r_mode);
5755+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_name)
5756+ 	    +sizeof(f->r_perm)+sizeof(f->r_mode));
5757+     break;
5758+
5759+   case Tread:
5760+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count));
5761+     N2HSHORT(f->r_fid);
5762+     N2HQUAD(f->r_offset);
5763+     N2HSHORT(f->r_count);
5764+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count));
5765+     break;
5766+
5767+   case Twrite:
5768+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count));
5769+     N2HSHORT(f->r_fid);
5770+     N2HQUAD(f->r_offset);
5771+     N2HSHORT(f->r_count);
5772+     p++;	/* pad(1) */
5773+     f->r_data = (char*)p; p += f->r_count;
5774+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count)+1);
5775+     break;
5776+
5777+   case Tclunk:
5778+   case Tremove:
5779+   case Tstat:
5780+    U9P_PULLUP(m, sizeof(f->r_fid));
5781+     N2HSHORT(f->r_fid);
5782+     U9P_ADJ(m, sizeof(f->r_fid));
5783+     break;
5784+
5785+   case Twstat:
5786+     U9P_PULLUP(m, sizeof(f->r_fid));
5787+     N2HSHORT(f->r_fid);
5788+     m_copydata(*m, sizeof(f->r_fid), sizeof(f->r_stat), f->r_stat);
5789+     m_adj(*m, sizeof(f->r_fid)+sizeof(f->r_stat));
5790+     break;
5791+
5792+   case Tclwalk:
5793+      U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_newfid)+sizeof(f->r_name));
5794+      N2HSHORT(f->r_fid);
5795+      N2HSHORT(f->r_newfid);
5796+      N2HSTRING(f->r_name, sizeof(f->r_name));
5797+      U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_newfid)+sizeof(f->r_name));
5798+      break;
5799+ /*
5800+  */
5801+   case Rnop:
5802+     break;
5803+
5804+   case Rsession:
5805+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_authid)+sizeof(f->r_authdom));
5806+     N2HSTRING(f->r_chal, sizeof(f->r_chal));
5807+     N2HSTRING(f->r_authid, sizeof(f->r_authid));
5808+     N2HSTRING(f->r_authdom, sizeof(f->r_authdom));
5809+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_authid)+sizeof(f->r_authdom));
5810+     break;
5811+
5812+   case Rerror:
5813+     U9P_PULLUP(m, sizeof(f->r_ename));
5814+     N2HSTRING(f->r_ename, sizeof(f->r_ename));
5815+     U9P_ADJ(m, sizeof(f->r_ename));
5816+     break;
5817+
5818+   case Rflush:
5819+     break;
5820+
5821+   case Rattach:
5822+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
5823+ 	       +sizeof(f->r_qid.vers)+sizeof(f->r_rauth));
5824+     N2HSHORT(f->r_fid);
5825+     N2HLONG(f->r_qid.path);
5826+     N2HLONG(f->r_qid.vers);
5827+     N2HSTRING(f->r_rauth, sizeof(f->r_rauth));
5828+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
5829+ 	    +sizeof(f->r_qid.vers)+sizeof(f->r_rauth));
5830+     break;
5831+
5832+   case Rclone:
5833+     U9P_PULLUP(m, sizeof(f->r_fid));
5834+     N2HSHORT(f->r_fid);
5835+     U9P_ADJ(m, sizeof(f->r_fid));
5836+     break;
5837+
5838+   case Rwalk:
5839+   case Rclwalk:
5840+   case Ropen:
5841+   case Rcreate:
5842+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
5843+                +sizeof(f->r_qid.vers));
5844+     N2HSHORT(f->r_fid);
5845+     N2HLONG(f->r_qid.path);
5846+     N2HLONG(f->r_qid.vers);
5847+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
5848+             +sizeof(f->r_qid.vers));
5849+     break;
5850+
5851+   case Rread:
5852+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_count));
5853+     N2HSHORT(f->r_fid);
5854+     N2HSHORT(f->r_count);
5855+     p++;	/* pad(1) */
5856+     f->r_data = (char*)p; p += f->r_count;
5857+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_count)+1);
5858+     break;
5859+
5860+   case Rwrite:
5861+     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_count));
5862+     N2HSHORT(f->r_fid);
5863+     N2HSHORT(f->r_count);
5864+     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_count));
5865+     break;
5866+
5867+   case Rclunk:
5868+   case Rremove:
5869+   case Rwstat:
5870+     U9P_PULLUP(m, sizeof(f->r_fid));
5871+     N2HSHORT(f->r_fid);
5872+     U9P_ADJ(m, sizeof(f->r_fid));
5873+     break;
5874+
5875+   case Rstat:
5876+     U9P_PULLUP(m, sizeof(f->r_fid));
5877+     N2HSHORT(f->r_fid);
5878+     m_copydata(*m, sizeof(f->r_fid), sizeof(f->r_stat), f->r_stat);
5879+     m_adj(*m, sizeof(f->r_fid)+sizeof(f->r_stat));
5880+     break;
5881+
5882+   }
5883+   return 0;
5884+
5885+  drop:
5886+   m_freem(*m);
5887+   return 1;
5888+ }
5889+
5890+ struct mbuf *
5891+ u9p_m_s2m (struct u9fsreq *f)
5892+ {
5893+   register struct mbuf * m;
5894+   struct mbuf * m0;
5895+   char * ap;
5896+   int sz;
5897+
5898+   /* we want one contiguous piece */
5899+   if( f->r_type == Tattach || f->r_type == Rstat || f->r_type == Twstat )
5900+     sz = 146; /* sizeof a Tattach */
5901+   else
5902+     sz = 87; /* sizeof a Tsession */
5903+
5904+   MGETHDR(m, M_WAIT, MT_DATA);
5905+   if( sz > MHLEN )
5906+     MCLGET(m, M_WAIT);
5907+   m->m_len = 0;
5908+
5909+   if ( M_TRAILINGSPACE(m) < sz )
5910+     panic("u9p_m_s2m");
5911+
5912+   ap = mtod(m, char *);
5913+   m->m_len = u9p_s2m(f, ap, 0);
5914+   m->m_pkthdr.len = m->m_len;
5915+
5916+   /* append data mbufs  */
5917+   switch ( f->r_type ) {
5918+   default:
5919+     break;
5920+   case Twrite:
5921+   case Rread:
5922+     m0 = (struct mbuf *)f->r_data;
5923+     m->m_next = m0;
5924+     m->m_pkthdr.len += f->r_count;
5925+     break;
5926+   }
5927+
5928+   return m;
5929+ }
5930+
5931+ int
5932+ u9p_m_m2d (struct mbuf **m, struct u9fsdir *f)
5933+ {
5934+   u_char *p;
5935+
5936+   U9P_PULLUP(m, sizeof(f->dir_name)+sizeof(f->dir_uid)+sizeof(f->dir_gid));
5937+   N2HSTRING(f->dir_name, sizeof(f->dir_name));
5938+   N2HSTRING(f->dir_uid, sizeof(f->dir_uid));
5939+   N2HSTRING(f->dir_gid, sizeof(f->dir_gid));
5940+   U9P_ADJ(m, sizeof(f->dir_name)+sizeof(f->dir_uid)+sizeof(f->dir_gid));
5941+
5942+   U9P_PULLUP(m, sizeof(f->dir_qid)+sizeof(f->dir_mode)
5943+ 	     +sizeof(f->dir_atime)+sizeof(f->dir_mtime)
5944+ 	     +sizeof(f->dir_length)+sizeof(f->dir_type)+sizeof(f->dir_dev));
5945+   N2HLONG(f->dir_qid.path);
5946+   N2HLONG(f->dir_qid.vers);
5947+   N2HLONG(f->dir_mode);
5948+   N2HLONG(f->dir_atime);
5949+   N2HLONG(f->dir_mtime);
5950+   N2HQUAD(f->dir_length);
5951+   N2HSHORT(f->dir_type);
5952+   N2HSHORT(f->dir_dev);
5953+   U9P_ADJ(m, sizeof(f->dir_qid)+sizeof(f->dir_mode)
5954+ 	     +sizeof(f->dir_atime)+sizeof(f->dir_mtime)
5955+ 	     +sizeof(f->dir_length)+sizeof(f->dir_type)+sizeof(f->dir_dev));
5956+
5957+   return 0;
5958+ }
5959+
5960+ struct mbuf * u9p_m_d2m (struct u9fsdir *f)
5961+ {
5962+   char * ap;
5963+   struct mbuf * m;
5964+   MGET(m, M_WAIT, MT_DATA);
5965+   MCLGET(m, M_WAIT);
5966+   m->m_len = 0;
5967+
5968+   if ( M_TRAILINGSPACE(m) < sizeof(struct u9fsdir) )
5969+     panic("u9p_m_d2m");
5970+
5971+   ap = mtod(m, char *);
5972+   m->m_len = u9p_d2m(f, ap);
5973+
5974+   return m;
5975+ }
5976diff -N -c -r /usr/src/sys/9fs/9p.h ./9fs/9p.h
5977*** /usr/src/sys/9fs/9p.h	Wed Dec 31 19:00:00 1969
5978--- ./9fs/9p.h	Thu Nov 25 15:45:46 1999
5979***************
5980*** 0 ****
5981--- 1,183 ----
5982+ #ifndef _9FS_9P_H_
5983+ #define _9FS_9P_H_
5984+
5985+
5986+ #define U9FS_AUTHLEN 13
5987+ #define U9FS_NAMELEN    28
5988+ #define U9FS_TICKETLEN  72
5989+ #define U9FS_ERRLEN     64
5990+ #define U9FS_DOMLEN     48
5991+ #define U9FS_CHALLEN    8
5992+ #define U9FS_DIRLEN     116
5993+ #define U9FS_MAXFDATA  8192
5994+ #define U9FS_MAXDDATA  (((int)U9FS_MAXFDATA/U9FS_DIRLEN)*U9FS_DIRLEN)
5995+
5996+ #define U9P_MODE_RD    0x0
5997+ #define U9P_MODE_WR    0x1
5998+ #define U9P_MODE_RDWR  0x2
5999+ #define U9P_MODE_EX    0x3
6000+ #define U9P_MODE_TRUNC 0x10
6001+ #define U9P_MODE_CLOSE 0x40
6002+
6003+ #define U9P_PERM_CHDIR(m) (0x80000000&(m))
6004+ #define U9P_PERM_OWNER(m) ((m)&0x7)
6005+ #define U9P_PERM_GROUP(m) (((m)>>3)&0x7)
6006+ #define U9P_PERM_OTHER(m) (((m)>>6)&0x7)
6007+ #define U9P_PERM_ALL(m)   ((m)&0777)
6008+ #define U9P_PERM_EXCL(m)    ((m)&0x20000000)
6009+ #define U9P_PERM_APPEND(m)  ((m)&0x40000000)
6010+ #define U9P_PERM_NONPERM(m) ((m)&0xfffffe00)
6011+
6012+ /* this is too small */
6013+ typedef u_int32_t u9fsfh_t;
6014+
6015+ struct u9fs_qid {
6016+ 	u9fsfh_t	path;
6017+ 	u_int32_t	vers;
6018+ };
6019+
6020+ struct	u9fsreq {
6021+   TAILQ_ENTRY(u9fsreq) r_chain;
6022+   struct u9fsreq * r_rep;
6023+   struct mbuf * r_mrep;
6024+   struct proc	*r_procp;	/* Proc that did I/O system call */
6025+   struct u9fsmount *r_nmp;
6026+
6027+   /* actual content of the 9P message */
6028+ 	char	r_type;
6029+ 	short	r_fid;
6030+ 	u_short	r_tag;
6031+ 	union {
6032+ 		struct {
6033+ 			u_short	oldtag;		/* Tflush */
6034+ 			struct u9fs_qid qid;		/* Rattach, Rwalk, Ropen, Rcreate */
6035+ 			char	rauth[U9FS_AUTHLEN];	/* Rattach */
6036+ 		} u1;
6037+ 		struct {
6038+ 			char	uname[U9FS_NAMELEN];		/* Tattach */
6039+ 			char	aname[U9FS_NAMELEN];		/* Tattach */
6040+ 			char	ticket[U9FS_TICKETLEN];	/* Tattach */
6041+ 			char	auth[U9FS_AUTHLEN];	/* Tattach */
6042+ 		} u2;
6043+ 		struct {
6044+ 			char	ename[U9FS_ERRLEN];		/* Rerror */
6045+ 			char	authid[U9FS_NAMELEN];	/* Rsession */
6046+ 			char	authdom[U9FS_DOMLEN];	/* Rsession */
6047+ 			char	chal[U9FS_CHALLEN];		/* Tsession/Rsession */
6048+ 		} u3;
6049+ 		struct {
6050+ 			u_int32_t	perm;		/* Tcreate */
6051+ 			short	newfid;		/* Tclone, Tclwalk */
6052+ 			char	name[U9FS_NAMELEN];	/* Twalk, Tclwalk, Tcreate */
6053+ 			char	mode;		/* Tcreate, Topen */
6054+ 		} u4;
6055+ 		struct {
6056+ 			u_int64_t	offset;		/* Tread, Twrite */
6057+ 			u_short	        count;		/* Tread, Twrite, Rread */
6058+ 			char	*data;		/* Twrite, Rread */
6059+ 		} u5;
6060+ 			char	stat[U9FS_DIRLEN];	/* Twstat, Rstat */
6061+ 	} u;
6062+ };
6063+
6064+ #define r_oldtag u.u1.oldtag
6065+ #define r_qid u.u1.qid
6066+ #define r_rauth u.u1.rauth
6067+ #define r_uname u.u2.uname
6068+ #define r_aname u.u2.aname
6069+ #define r_ticket  u.u2.ticket
6070+ #define r_auth  u.u2.auth
6071+ #define r_ename  u.u3.ename
6072+ #define r_authid  u.u3.authid
6073+ #define r_authdom  u.u3.authdom
6074+ #define r_chal  u.u3.chal
6075+ #define r_perm  u.u4.perm
6076+ #define r_newfid  u.u4.newfid
6077+ #define r_name  u.u4.name
6078+ #define r_mode  u.u4.mode
6079+ #define r_offset  u.u5.offset
6080+ #define r_count  u.u5.count
6081+ #define r_data  u.u5.data
6082+ #define r_stat  u.stat
6083+
6084+ struct u9fsdir {
6085+   char	dir_name[U9FS_NAMELEN];
6086+   char	dir_uid[U9FS_NAMELEN];
6087+   char	dir_gid[U9FS_NAMELEN];
6088+   struct u9fs_qid	dir_qid;
6089+   u_int32_t	dir_mode;
6090+   u_int32_t	dir_atime;
6091+   u_int32_t	dir_mtime;
6092+   union {
6093+     u_int64_t	length;
6094+     struct {	/* little endian */
6095+       u_int32_t	llength;
6096+       u_int32_t	hlength;
6097+     } l;
6098+   } u;
6099+   u_short	dir_type;
6100+   u_short	dir_dev;
6101+ };
6102+
6103+ #define dir_length u.length
6104+ #define dir_llength u.l.llength
6105+ #define dir_hlength u.l.hlength
6106+
6107+ enum
6108+ {
6109+ 	Tnop =		50,
6110+ 	Rnop,
6111+ 	Tosession =	52,	/* illegal */
6112+ 	Rosession,		/* illegal */
6113+ 	Terror =	54,	/* illegal */
6114+ 	Rerror,
6115+ 	Tflush =	56,
6116+ 	Rflush,
6117+ 	Toattach =	58,	/* illegal */
6118+ 	Roattach,		/* illegal */
6119+ 	Tclone =	60,
6120+ 	Rclone,
6121+ 	Twalk =		62,
6122+ 	Rwalk,
6123+ 	Topen =		64,
6124+ 	Ropen,
6125+ 	Tcreate =	66,
6126+ 	Rcreate,
6127+ 	Tread =		68,
6128+ 	Rread,
6129+ 	Twrite =	70,
6130+ 	Rwrite,
6131+ 	Tclunk =	72,
6132+ 	Rclunk,
6133+ 	Tremove =	74,
6134+ 	Rremove,
6135+ 	Tstat =		76,
6136+ 	Rstat,
6137+ 	Twstat =	78,
6138+ 	Rwstat,
6139+ 	Tclwalk =	80,
6140+ 	Rclwalk,
6141+ 	Tauth =		82,	/* illegal */
6142+ 	Rauth,			/* illegal */
6143+ 	Tsession =	84,
6144+ 	Rsession,
6145+ 	Tattach =	86,
6146+ 	Rattach,
6147+ 	Ttunnel =	88,
6148+ 	Rtunnel,
6149+ 	Tmax
6150+ };
6151+
6152+ int u9p_m2s __P((char *ap, int n, struct u9fsreq *f));
6153+ int u9p_s2m __P((struct u9fsreq *f, char *ap, int copydata));
6154+ int u9p_m2d __P((char *ap, struct u9fsdir *f));
6155+ int u9p_d2m __P((struct u9fsdir *f, char *ap));
6156+ int u9p_type __P((char * t));
6157+
6158+ int u9p_m_m2s __P((struct mbuf **m, struct u9fsreq *f));
6159+ struct mbuf * u9p_m_s2m __P((struct u9fsreq *f));
6160+ int u9p_m_m2d __P((struct mbuf **m, struct u9fsdir *f));
6161+ struct mbuf * u9p_m_d2m __P((struct u9fsdir *f));
6162+ u_short u9p_m_tag __P((struct mbuf **m));
6163+
6164+ #endif
6165diff -N -c -r /usr/src/sys/9fs/bitstring.h ./9fs/bitstring.h
6166*** /usr/src/sys/9fs/bitstring.h	Wed Dec 31 19:00:00 1969
6167--- ./9fs/bitstring.h	Thu Oct 21 12:34:50 1999
6168***************
6169*** 0 ****
6170--- 1,143 ----
6171+ /*
6172+  * Copyright (c) 1989, 1993
6173+  *	The Regents of the University of California.  All rights reserved.
6174+  *
6175+  * This code is derived from software contributed to Berkeley by
6176+  * Paul Vixie.
6177+  *
6178+  * Redistribution and use in source and binary forms, with or without
6179+  * modification, are permitted provided that the following conditions
6180+  * are met:
6181+  * 1. Redistributions of source code must retain the above copyright
6182+  *    notice, this list of conditions and the following disclaimer.
6183+  * 2. Redistributions in binary form must reproduce the above copyright
6184+  *    notice, this list of conditions and the following disclaimer in the
6185+  *    documentation and/or other materials provided with the distribution.
6186+  * 3. All advertising materials mentioning features or use of this software
6187+  *    must display the following acknowledgement:
6188+  *	This product includes software developed by the University of
6189+  *	California, Berkeley and its contributors.
6190+  * 4. Neither the name of the University nor the names of its contributors
6191+  *    may be used to endorse or promote products derived from this software
6192+  *    without specific prior written permission.
6193+  *
6194+  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6195+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6196+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6197+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6198+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6199+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6200+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6201+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6202+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6203+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6204+  * SUCH DAMAGE.
6205+  *
6206+  *	@(#)bitstring.h	8.1 (Berkeley) 7/19/93
6207+  */
6208+
6209+ #ifndef _BITSTRING_H_
6210+ #define	_BITSTRING_H_
6211+
6212+ typedef	unsigned char bitstr_t;
6213+
6214+ /* internal macros */
6215+ 				/* byte of the bitstring bit is in */
6216+ #define	_bit_byte(bit) \
6217+ 	((bit) >> 3)
6218+
6219+ 				/* mask for the bit within its byte */
6220+ #define	_bit_mask(bit) \
6221+ 	(1 << ((bit)&0x7))
6222+
6223+ /* external macros */
6224+ 				/* bytes in a bitstring of nbits bits */
6225+ #define	bitstr_size(nbits) \
6226+ 	((((nbits) - 1) >> 3) + 1)
6227+
6228+ 				/* allocate a bitstring */
6229+ #define	bit_alloc(space, nbits, type, flags) \
6230+ 	MALLOC((space), bitstr_t *, \
6231+         (u_int)bitstr_size(nbits)*sizeof(bitstr_t), (type), (flags))
6232+
6233+ 				/* allocate a bitstring on the stack */
6234+ #define	bit_decl(name, nbits) \
6235+ 	(name)[bitstr_size(nbits)]
6236+
6237+ 				/* is bit N of bitstring name set? */
6238+ #define	bit_test(name, bit) \
6239+ 	((name)[_bit_byte(bit)] & _bit_mask(bit))
6240+
6241+ 				/* set bit N of bitstring name */
6242+ #define	bit_set(name, bit) \
6243+ 	(name)[_bit_byte(bit)] |= _bit_mask(bit)
6244+
6245+ 				/* clear bit N of bitstring name */
6246+ #define	bit_clear(name, bit) \
6247+ 	(name)[_bit_byte(bit)] &= ~_bit_mask(bit)
6248+
6249+ 				/* clear bits start ... stop in bitstring */
6250+ #define	bit_nclear(name, start, stop) { \
6251+ 	register bitstr_t *_name = name; \
6252+ 	register int _start = start, _stop = stop; \
6253+ 	register int _startbyte = _bit_byte(_start); \
6254+ 	register int _stopbyte = _bit_byte(_stop); \
6255+ 	if (_startbyte == _stopbyte) { \
6256+ 		_name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
6257+ 				      (0xff << ((_stop&0x7) + 1))); \
6258+ 	} else { \
6259+ 		_name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
6260+ 		while (++_startbyte < _stopbyte) \
6261+ 			_name[_startbyte] = 0; \
6262+ 		_name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
6263+ 	} \
6264+ }
6265+
6266+ 				/* set bits start ... stop in bitstring */
6267+ #define	bit_nset(name, start, stop) { \
6268+ 	register bitstr_t *_name = name; \
6269+ 	register int _start = start, _stop = stop; \
6270+ 	register int _startbyte = _bit_byte(_start); \
6271+ 	register int _stopbyte = _bit_byte(_stop); \
6272+ 	if (_startbyte == _stopbyte) { \
6273+ 		_name[_startbyte] |= ((0xff << (_start&0x7)) & \
6274+ 				    (0xff >> (7 - (_stop&0x7)))); \
6275+ 	} else { \
6276+ 		_name[_startbyte] |= 0xff << ((_start)&0x7); \
6277+ 		while (++_startbyte < _stopbyte) \
6278+ 	    		_name[_startbyte] = 0xff; \
6279+ 		_name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
6280+ 	} \
6281+ }
6282+
6283+ 				/* find first bit clear in name */
6284+ #define	bit_ffc(name, nbits, value) { \
6285+ 	register bitstr_t *_name = name; \
6286+ 	register int _byte, _nbits = nbits; \
6287+ 	register int _stopbyte = _bit_byte(_nbits), _value = -1; \
6288+ 	for (_byte = 0; _byte <= _stopbyte; ++_byte) \
6289+ 		if (_name[_byte] != 0xff) { \
6290+ 			_value = _byte << 3; \
6291+ 			for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
6292+ 			    ++_value, _stopbyte >>= 1); \
6293+ 			break; \
6294+ 		} \
6295+ 	*(value) = _value; \
6296+ }
6297+
6298+ 				/* find first bit set in name */
6299+ #define	bit_ffs(name, nbits, value) { \
6300+ 	register bitstr_t *_name = name; \
6301+ 	register int _byte, _nbits = nbits; \
6302+ 	register int _stopbyte = _bit_byte(_nbits), _value = -1; \
6303+ 	for (_byte = 0; _byte <= _stopbyte; ++_byte) \
6304+ 		if (_name[_byte]) { \
6305+ 			_value = _byte << 3; \
6306+ 			for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
6307+ 			    ++_value, _stopbyte >>= 1); \
6308+ 			break; \
6309+ 		} \
6310+ 	*(value) = _value; \
6311+ }
6312+
6313+ #endif /* !_BITSTRING_H_ */
6314diff -N -c -r /usr/src/sys/conf/files ./conf/files
6315*** /usr/src/sys/conf/files	Fri Apr 30 15:32:40 1999
6316--- ./conf/files	Thu Nov 25 15:34:34 1999
6317***************
6318*** 535,540 ****
6319--- 535,541 ----
6320  netinet/tcp_timer.c	optional inet
6321  netinet/tcp_usrreq.c	optional inet
6322  netinet/udp_usrreq.c	optional inet
6323+ netinet/il.c		optional  il
6324  netipx/ipx.c		optional ipx
6325  netipx/ipx_cksum.c	optional ipx
6326  netipx/ipx_input.c	optional ipx
6327***************
6328*** 571,576 ****
6329--- 572,586 ----
6330  nfs/nfs_syscalls.c	optional nfs
6331  nfs/nfs_vfsops.c	optional nfs
6332  nfs/nfs_vnops.c		optional nfs
6333+ 9fs/9fs_vfsops.c	optional u9fs
6334+ 9fs/9fs_vnops.c		optional u9fs
6335+ 9fs/9p.c		optional u9fs
6336+ 9fs/9auth.c		optional u9fs
6337+ 9fs/9crypt.c		optional u9fs
6338+ 9fs/9fs_subr.c		optional u9fs
6339+ 9fs/9fs_socket.c	optional u9fs
6340+ 9fs/9fs_bio.c		optional u9fs
6341+ 9fs/9fs_node.c		optional u9fs
6342  nfs/bootp_subr.c	optional bootp
6343  nfs/krpc_subr.c		optional bootp
6344  pccard/pccard.c		optional card
6345diff -N -c -r /usr/src/sys/conf/options ./conf/options
6346*** /usr/src/sys/conf/options	Tue May 11 01:35:28 1999
6347--- ./conf/options	Mon Oct 11 19:59:14 1999
6348***************
6349*** 202,207 ****
6350--- 202,208 ----
6351  BRIDGE			opt_bdg.h
6352  MROUTING		opt_mrouting.h
6353  INET			opt_inet.h
6354+ IL			opt_inet.h
6355  IPDIVERT
6356  DUMMYNET		opt_ipdn.h
6357  IPFIREWALL		opt_ipfw.h
6358***************
6359*** 314,319 ****
6360--- 315,322 ----
6361  NFS_MUIDHASHSIZ		opt_nfs.h
6362  NFS_NOSERVER		opt_nfs.h
6363  NFS_DEBUG		opt_nfs.h
6364+
6365+ U9FS
6366
6367  # give bktr an opt_bktr.h file
6368  OVERRIDE_CARD		opt_bktr.h
6369diff -N -c -r /usr/src/sys/i386/conf/IL ./i386/conf/IL
6370*** /usr/src/sys/i386/conf/IL	Wed Dec 31 19:00:00 1969
6371--- ./i386/conf/IL	Sat Oct 23 14:01:36 1999
6372***************
6373*** 0 ****
6374--- 1,234 ----
6375+ #
6376+ # GENERIC -- Generic machine with WD/AHx/NCR/BTx family disks
6377+ #
6378+ # For more information read the handbook part System Administration ->
6379+ # Configuring the FreeBSD Kernel -> The Configuration File.
6380+ # The handbook is available in /usr/share/doc/handbook or online as
6381+ # latest version from the FreeBSD World Wide Web server
6382+ # <URL:http://www.FreeBSD.ORG/>
6383+ #
6384+ # An exhaustive list of options and more detailed explanations of the
6385+ # device lines is present in the ./LINT configuration file. If you are
6386+ # in doubt as to the purpose or necessity of a line, check first in LINT.
6387+ #
6388+ #	$Id: GENERIC,v 1.143.2.2 1999/02/15 02:50:07 des Exp $
6389+
6390+ machine		"i386"
6391+ cpu		"I586_CPU"
6392+ cpu		"I686_CPU"
6393+ ident		GENERIC
6394+ maxusers	128
6395+
6396+ #options		DDB
6397+ options		IL			# plan9's IL
6398+ options		"U9FS"			# plan9's 9fs client
6399+ options		INET			#InterNETworking
6400+ options		FFS			#Berkeley Fast Filesystem
6401+ options		FFS_ROOT		#FFS usable as root device [keep this!]
6402+ options		MFS			#Memory Filesystem
6403+ options		MFS_ROOT		#MFS usable as root device, "MFS" req'ed
6404+ options		NFS			#Network Filesystem
6405+ options		NFS_ROOT		#NFS usable as root device, "NFS" req'ed
6406+ options		"CD9660"		#ISO 9660 Filesystem
6407+ options		"CD9660_ROOT"		#CD-ROM usable as root. "CD9660" req'ed
6408+ options		PROCFS			#Process filesystem
6409+ options         FDESC                   #File descriptor filesystem
6410+ options		"COMPAT_43"		#Compatible with BSD 4.3 [KEEP THIS!]
6411+ options		SCSI_DELAY=15000	#Be pessimistic about Joe SCSI device
6412+ options		UCONSOLE		#Allow users to grab the console
6413+ options		FAILSAFE		#Be conservative
6414+ options		USERCONFIG		#boot -c editor
6415+ options		VISUAL_USERCONFIG	#visual boot -c editor
6416+ options		NMBCLUSTERS=4096
6417+ options		MAXFILES=10000
6418+
6419+ config		kernel	root on wd0
6420+
6421+ # To make an SMP kernel, the next two are needed
6422+ #options	SMP			# Symmetric MultiProcessor Kernel
6423+ #options	APIC_IO			# Symmetric (APIC) I/O
6424+ # Optionally these may need tweaked, (defaults shown):
6425+ #options	NCPU=2			# number of CPUs
6426+ #options	NBUS=4			# number of busses
6427+ #options	NAPIC=1			# number of IO APICs
6428+ #options	NINTR=24		# number of INTs
6429+
6430+ controller	isa0
6431+ controller	eisa0
6432+ controller	pci0
6433+
6434+ controller	fdc0	at isa? port "IO_FD1" bio irq 6 drq 2
6435+ disk		fd0	at fdc0 drive 0
6436+ disk		fd1	at fdc0 drive 1
6437+
6438+ options		"CMD640"	# work around CMD640 chip deficiency
6439+ controller	wdc0	at isa? port "IO_WD1" bio irq 14 flags 0xa0ff vector wdintr
6440+ disk		wd0	at wdc0 drive 0
6441+ disk		wd1	at wdc0 drive 1
6442+
6443+ controller	wdc1	at isa? port "IO_WD2" bio irq 15 flags 0xa0ff vector wdintr
6444+ disk		wd2	at wdc1 drive 0
6445+ disk		wd3	at wdc1 drive 1
6446+
6447+ options		ATAPI		#Enable ATAPI support for IDE bus
6448+ options		ATAPI_STATIC	#Don't do it as an LKM
6449+ #device		acd0		#IDE CD-ROM
6450+ #device		wfd0		#IDE Floppy (e.g. LS-120)
6451+
6452+ # A single entry for any of these controllers (ncr, ahb, ahc) is
6453+ # sufficient for any number of installed devices.
6454+ #controller	ncr0
6455+ #controller	ahb0
6456+ #controller	ahc0
6457+ #controller	isp0
6458+
6459+ # This controller offers a number of configuration options, too many to
6460+ # document here  - see the LINT file in this directory and look up the
6461+ # dpt0 entry there for much fuller documentation on this.
6462+ controller      dpt0
6463+
6464+ #controller	adv0	at isa? port ? cam irq ?
6465+ #controller	adw0
6466+ #controller	bt0	at isa? port ? cam irq ?
6467+ #controller	aha0	at isa? port ? cam irq ?
6468+ #controller	aic0	at isa? port 0x340 bio irq 11
6469+
6470+ controller	scbus0
6471+
6472+ device		da0
6473+
6474+ device		sa0
6475+
6476+ device		pass0
6477+
6478+ device		cd0	#Only need one of these, the code dynamically grows
6479+
6480+ #device		wt0	at isa? port 0x300 bio irq 5 drq 1
6481+ #device		mcd0	at isa? port 0x300 bio irq 10
6482+
6483+ #controller	matcd0	at isa? port 0x230 bio
6484+
6485+ #device		scd0	at isa? port 0x230 bio
6486+
6487+ # atkbdc0 controlls both the keyboard and the PS/2 mouse
6488+ controller	atkbdc0	at isa? port IO_KBD tty
6489+ device		atkbd0	at isa? tty irq 1
6490+ device		psm0	at isa? tty irq 12
6491+
6492+ device		vga0	at isa? port ? conflicts
6493+
6494+ # splash screen/screen saver
6495+ pseudo-device	splash
6496+
6497+ # syscons is the default console driver, resembling an SCO console
6498+ device		sc0	at isa? tty
6499+ # Enable this and PCVT_FREEBSD for pcvt vt220 compatible console driver
6500+ #device		vt0	at isa? tty
6501+ #options		XSERVER			# support for X server
6502+ #options		FAT_CURSOR		# start with block cursor
6503+ # If you have a ThinkPAD, uncomment this along with the rest of the PCVT lines
6504+ #options		PCVT_SCANSET=2		# IBM keyboards are non-std
6505+
6506+ device		npx0	at isa? port IO_NPX irq 13
6507+
6508+ #
6509+ # Laptop support (see LINT for more options)
6510+ #
6511+ device		apm0    at isa?	disable	flags 0x31 # Advanced Power Management
6512+
6513+ # PCCARD (PCMCIA) support
6514+ #controller	card0
6515+ #device		pcic0	at card?
6516+ #device		pcic1	at card?
6517+
6518+ device		sio0	at isa? port "IO_COM1" flags 0x10 tty irq 4
6519+ device		sio1	at isa? port "IO_COM2" tty irq 3
6520+ device		sio2	at isa? disable port "IO_COM3" tty irq 5
6521+ device		sio3	at isa? disable port "IO_COM4" tty irq 9
6522+
6523+ # Parallel port
6524+ device		ppc0	at isa? port? net irq 7
6525+ controller	ppbus0
6526+ device		nlpt0	at ppbus?
6527+ device		plip0	at ppbus?
6528+ device		ppi0	at ppbus?
6529+ #controller	vpo0	at ppbus?
6530+
6531+ #
6532+ # The following Ethernet NICs are all PCI devices.
6533+ #
6534+ device ax0		# ASIX AX88140A
6535+ device de0		# DEC/Intel DC21x4x (``Tulip'')
6536+ device fxp0		# Intel EtherExpress PRO/100B (82557, 82558)
6537+ device mx0		# Macronix 98713/98715/98725 (``PMAC'')
6538+ device pn0		# Lite-On 82c168/82c169 (``PNIC'')
6539+ device rl0		# RealTek 8129/8139
6540+ device tl0		# Texas Instruments ThunderLAN
6541+ device tx0		# SMC 9432TX (83c170 ``EPIC'')
6542+ device vr0		# VIA Rhine, Rhine II
6543+ device vx0		# 3Com 3c590, 3c595 (``Vortex'')
6544+ device wb0		# Winbond W89C840F
6545+ device xl0		# 3Com 3c90x (``Boomerang'', ``Cyclone'')
6546+
6547+ # Order is important here due to intrusive probes, do *not* alphabetize
6548+ # this list of network interfaces until the probes have been fixed.
6549+ # Right now it appears that the ie0 must be probed before ep0. See
6550+ # revision 1.20 of this file.
6551+
6552+ #device ed0 at isa? port 0x280 net irq 10 iomem 0xd8000
6553+ #device ie0 at isa? port 0x300 net irq 10 iomem 0xd0000
6554+ #device ep0 at isa? port 0x300 net irq 10
6555+ #device ex0 at isa? port? net irq?
6556+ #device fe0 at isa? port 0x300 net irq ?
6557+ #device le0 at isa? port 0x300 net irq 5 iomem 0xd0000
6558+ #device lnc0 at isa? port 0x280 net irq 10 drq 0
6559+ #device ze0 at isa? port 0x300 net irq 10 iomem 0xd8000
6560+ #device zp0 at isa? port 0x300 net irq 10 iomem 0xd8000
6561+ #device cs0 at isa? port 0x300 net irq ?
6562+
6563+ pseudo-device	loop
6564+ pseudo-device	ether
6565+ pseudo-device	sl	1
6566+ pseudo-device	ppp	1
6567+ pseudo-device	tun	1
6568+ pseudo-device	pty	32
6569+ pseudo-device	gzip		# Exec gzipped a.out's
6570+
6571+ # KTRACE enables the system-call tracing facility ktrace(2).
6572+ # This adds 4 KB bloat to your kernel, and slightly increases
6573+ # the costs of each syscall.
6574+ options		KTRACE		#kernel tracing
6575+
6576+ # This provides support for System V shared memory and message queues.
6577+ #
6578+ options		SYSVSHM
6579+ options		SYSVMSG
6580+
6581+ #  The `bpfilter' pseudo-device enables the Berkeley Packet Filter.  Be
6582+ #  aware of the legal and administrative consequences of enabling this
6583+ #  option.  The number of devices determines the maximum number of
6584+ #  simultaneous BPF clients programs runnable.
6585+ pseudo-device	bpfilter 4	#Berkeley packet filter
6586+
6587+
6588+ # USB support
6589+ #controller    uhci0
6590+ #controller    ohci0
6591+ #controller    usb0
6592+ #
6593+ # for the moment we have to specify the priorities of the device
6594+ # drivers explicitly by the ordering in the list below. This will
6595+ # be changed in the future.
6596+ #
6597+ #device        ums0
6598+ #device        ukbd0
6599+ #device        ulpt0
6600+ #device        uhub0
6601+ #device        ucom0
6602+ #device        umodem0
6603+ #device        hid0
6604+ #device        ugen0
6605+
6606+ #
6607+ #options       USB_DEBUG
6608+ #options       USBVERBOSE
6609diff -N -c -r /usr/src/sys/netinet/il.c ./netinet/il.c
6610*** /usr/src/sys/netinet/il.c	Wed Dec 31 19:00:00 1969
6611--- ./netinet/il.c	Tue Nov 23 19:16:13 1999
6612***************
6613*** 0 ****
6614--- 1,1147 ----
6615+ #include <unistd.h>
6616+ #include <ctype.h>
6617+ #include <sys/types.h>
6618+ #include <sys/param.h>
6619+ #include <sys/time.h>
6620+ #include <sys/systm.h>
6621+ #include <vm/vm_zone.h>
6622+
6623+ #include <sys/malloc.h>
6624+ #include <machine/param.h>
6625+ #include <sys/mbuf.h>
6626+ #include <sys/protosw.h>
6627+ #include <sys/socket.h>
6628+ #include <sys/socketvar.h>
6629+ #include <sys/proc.h>
6630+ #include <net/if.h>
6631+ #include <net/route.h>
6632+ #include <netinet/in_systm.h>
6633+ #include <netinet/in.h>
6634+ #include <netinet/in_var.h>
6635+ #include <netinet/if_ether.h>
6636+ #include <netinet/ip.h>
6637+ #include <netinet/ip_var.h>
6638+ #include <netinet/in_pcb.h>
6639+ #include <errno.h>
6640+
6641+ #include <netinet/il.h>
6642+ #include <netinet/il_var.h>
6643+
6644+ struct ilpcb * il_drop(struct ilpcb *ilpcb, int errno0);
6645+ static struct ilpcb * il_close(struct ilpcb *ilpcb);
6646+
6647+ /* kernel protocol states needed */
6648+ static struct inpcbhead ilb;
6649+ static struct inpcbinfo ilbinfo;
6650+
6651+ u_long il_sendspace = 1024*64;
6652+ u_long il_recvspace = 1024*64;
6653+
6654+ /*
6655+  * Target size of IL PCB hash tables. Must be a power of two.
6656+  *
6657+  * Note that this can be overridden by the kernel environment
6658+  * variable net.inet.tcp.tcbhashsize
6659+  */
6660+ #ifndef ILBHASHSIZE
6661+ #define ILBHASHSIZE	512
6662+ #endif
6663+
6664+ enum				/* Connection state */
6665+ {
6666+ 	ILS_CLOSED,
6667+ 	ILS_SYNCER,
6668+ 	ILS_SYNCEE,
6669+ 	ILS_ESTABLISHED,
6670+ 	ILS_LISTENING,
6671+ 	ILS_CLOSING,
6672+ 	ILS_OPENING,		/* only for file server */
6673+ };
6674+
6675+ char	*ilstates[] =
6676+ {
6677+ 	"Closed",
6678+ 	"Syncer",
6679+ 	"Syncee",
6680+ 	"Established",
6681+ 	"Listening",
6682+ 	"Closing",
6683+ 	"Opening",		/* only for file server */
6684+ };
6685+
6686+ enum				/* Packet types */
6687+ {
6688+ 	ILT_SYNC,
6689+ 	ILT_DATA,
6690+ 	ILT_DATAQUERY,
6691+ 	ILT_ACK,
6692+ 	ILT_QUERY,
6693+ 	ILT_STATE,
6694+ 	ILT_CLOSE
6695+ };
6696+
6697+ char	*iltype[] =
6698+ {
6699+ 	"sync",
6700+ 	"data",
6701+ 	"dataquery",
6702+ 	"ack",
6703+ 	"query",
6704+ 	"state",
6705+ 	"close",
6706+ };
6707+
6708+ /*
6709+  * This is the actual shape of what we allocate using the zone
6710+  * allocator.  Doing it this way allows us to protect both structures
6711+  * using the same generation count, and also eliminates the overhead
6712+  * of allocating tcpcbs separately.  By hiding the structure here,
6713+  * we avoid changing most of the rest of the code (although it needs
6714+  * to be changed, eventually, for greater efficiency).
6715+  */
6716+ #define	ALIGNMENT	32
6717+ #define	ALIGNM1		(ALIGNMENT - 1)
6718+ struct	inp_ilpcb {
6719+ 	union {
6720+ 		struct	inpcb inp;
6721+ 		char	align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1];
6722+ 	} inp_tp_u;
6723+ 	struct	ilpcb ilpcb;
6724+ };
6725+ #undef ALIGNMENT
6726+ #undef ALIGNM1
6727+
6728+ static __inline struct mbuf * il_segq_top(struct ilpcb * ilpcb)
6729+ {
6730+   return (ilpcb->segq);
6731+ }
6732+
6733+ static __inline void il_segq_dequeue(struct ilpcb * ilpcb)
6734+ {
6735+   struct mbuf * m = ilpcb->segq;
6736+   ilpcb->segq = m->m_nextpkt;
6737+   m->m_nextpkt = 0;
6738+ }
6739+
6740+ static __inline void il_segq_insert(struct ilpcb * ilpcb, struct mbuf * m, u_long seq, struct ilhdr * il)
6741+ {
6742+   u_long pseq;
6743+   struct mbuf * mp, * mq;
6744+
6745+   m->m_pkthdr.header = il;
6746+
6747+   mp = 0;
6748+   mq = ilpcb->segq;
6749+   while ( mq ) {
6750+     il = mq->m_pkthdr.header;
6751+     pseq = ntohl(*(u_long *)il->ilid);
6752+     if( pseq > seq )
6753+       break;
6754+     if( pseq == seq ) { /* we already got this packet */
6755+       m_freem(m);
6756+       return;
6757+     }
6758+     mp = mq;
6759+     mq = mq->m_nextpkt;
6760+   }
6761+
6762+   if( mp == 0 ) {
6763+     m->m_nextpkt = ilpcb->segq;
6764+     ilpcb->segq = m;
6765+     return;
6766+   }
6767+   mp->m_nextpkt = m;
6768+   m->m_nextpkt = mq;
6769+ }
6770+
6771+ void il_init()
6772+ {
6773+   LIST_INIT(&ilb);
6774+   ilbinfo.listhead = &ilb;
6775+   ilbinfo.hashbase = hashinit(ILBHASHSIZE, M_PCB, &ilbinfo.hashmask);
6776+   ilbinfo.porthashbase = hashinit(ILBHASHSIZE, M_PCB,
6777+ 				  &ilbinfo.porthashmask);
6778+   ilbinfo.ipi_zone = zinit("ilpcb", sizeof(struct inp_ilpcb), maxsockets,
6779+ 			   ZONE_INTERRUPT, 0);
6780+ }
6781+
6782+ /* fill in il header and cksum, ip src/dst addresses */
6783+ static int il_output(struct ilpcb * ilpcb, struct mbuf *m, int type, u_long seq, u_char spec)
6784+ {
6785+   struct ilhdr * il;
6786+   struct ip * ip;
6787+   int illen;
6788+   struct inpcb * inp;
6789+   struct socket * so;
6790+
6791+   /* XXX: check total size is less than IP_MAXPACKET */
6792+
6793+   if( m == 0 ) {
6794+     inp = ilpcb->inpcb;
6795+     so = inp->inp_socket;
6796+     m = m_copypacket(so->so_snd.sb_mb, M_DONTWAIT);
6797+   }
6798+
6799+   /*
6800+    * Calculate data length and get a mbuf
6801+    * for IL and IP headers.
6802+    */
6803+   illen = m->m_pkthdr.len; /* size of il payload */
6804+   M_PREPEND(m, sizeof(struct ip) + sizeof(struct ilhdr), M_DONTWAIT);
6805+   if( m == 0 )
6806+     return ENOBUFS;
6807+
6808+   ip = mtod(m, struct ip *);
6809+   il = (struct ilhdr *) (ip+1);
6810+   bzero(ip, sizeof(*ip));
6811+
6812+   ip->ip_p = IPPROTO_IL;
6813+   ip->ip_src = ilpcb->inpcb->inp_laddr;
6814+   ip->ip_dst = ilpcb->inpcb->inp_faddr;
6815+   ip->ip_len = m->m_pkthdr.len;
6816+   ip->ip_ttl = ilpcb->inpcb->inp_ip_ttl;	/* XXX */
6817+   ip->ip_tos = ilpcb->inpcb->inp_ip_tos;	/* XXX */
6818+
6819+   *(u_short *)il->illen = htons(illen + sizeof(struct ilhdr));
6820+   il->iltype = type;
6821+   il->ilspec = spec;
6822+   *(u_short *)il->ilsrc = ilpcb->inpcb->inp_lport;
6823+   *(u_short *)il->ildst = ilpcb->inpcb->inp_fport;
6824+   if ( type != ILT_SYNC )
6825+     *(u_long *)il->ilid = htonl(seq);
6826+   else
6827+     *(u_long *)il->ilid = htonl(ilpcb->start);
6828+
6829+   if( type != ILT_ACK && type != ILT_STATE) {
6830+     if( ilpcb->rxt_timer == 0 )
6831+       ilpcb->rxt_timer = ilpcb->rxt_timer_cur;
6832+     if( ilpcb->death_timer == 0 )
6833+       ilpcb->death_timer = ilpcb->death_timer_cur;
6834+   }
6835+
6836+   *(u_long *)il->ilack = htonl(ilpcb->recvd);
6837+   il->ilsum[0] = il->ilsum[1] = 0;
6838+
6839+   /* IL checksum does not cover IP header */
6840+   m->m_data += sizeof(struct ip);
6841+   m->m_len  -= sizeof(struct ip);
6842+   *(u_short *)il->ilsum = in_cksum(m, illen + sizeof(struct ilhdr));
6843+   m->m_data -= sizeof(struct ip);
6844+   m->m_len  += sizeof(struct ip);
6845+
6846+   return ip_output(m, ilpcb->inpcb->inp_options, &ilpcb->inpcb->inp_route,
6847+ 		   ilpcb->inpcb->inp_socket->so_options & SO_DONTROUTE ,0);
6848+ }
6849+
6850+ static int il_send_empty(struct ilpcb * ilpcb, int type, u_char spec)
6851+ {
6852+   struct mbuf * m0;
6853+
6854+   MGETHDR(m0, M_DONTWAIT, MT_DATA);
6855+   m0->m_len = 0;
6856+   m0->m_pkthdr.len = 0;
6857+   MH_ALIGN(m0, 0); /* leave space for the packet header */
6858+
6859+   return il_output(ilpcb, m0, type, ilpcb->next, spec);
6860+ }
6861+
6862+ static int il_respond(struct ilpcb * ilpcb, struct ip * ip, struct ilhdr *il, int type, u_char spec)
6863+ {
6864+   struct mbuf * m;
6865+   int illen;
6866+   struct ip * ip0;
6867+   struct ilhdr *il0;
6868+   struct route * ro;
6869+   struct route sro;
6870+
6871+   if( ilpcb ) {
6872+     ro = & ilpcb->inpcb->inp_route;
6873+   } else {
6874+     ro = &sro;
6875+     bzero(ro, sizeof *ro);
6876+   }
6877+
6878+   MGETHDR(m, M_DONTWAIT, MT_DATA);
6879+   m->m_len = 0;
6880+   m->m_pkthdr.len = 0;
6881+   MH_ALIGN(m, 0); /* leave space for the packet header */
6882+   illen = m->m_pkthdr.len; /* size of il payload */
6883+   M_PREPEND(m, sizeof(struct ip) + sizeof(struct ilhdr), M_DONTWAIT);
6884+   if( m == 0 )
6885+     return ENOBUFS;
6886+
6887+   ip0 = mtod(m, struct ip *);
6888+   il0 = (struct ilhdr *) (ip0+1);
6889+   bzero(ip0, sizeof(*ip0));
6890+
6891+   ip0->ip_p = IPPROTO_IL;
6892+   ip0->ip_src = ip->ip_dst;
6893+   ip0->ip_dst = ip->ip_src;
6894+   ip0->ip_ttl = ip_defttl;
6895+   ip0->ip_len = sizeof(struct ip) + sizeof(struct ilhdr);
6896+   *(u_short *)il0->illen = htons(illen + sizeof(struct ilhdr));
6897+   il0->iltype = type;
6898+   il0->ilspec = spec;
6899+   bcopy(il->ilsrc, il0->ildst, 2);
6900+   bcopy(il->ildst, il0->ilsrc, 2);
6901+   *(u_long *)il0->ilid = 0;
6902+   bcopy(il->ilid, il0->ilack, 4);
6903+   il0->ilsum[0] = il0->ilsum[1] = 0;
6904+
6905+   /* IL checksum does not cover IP header */
6906+   m->m_data += sizeof(struct ip);
6907+   m->m_len  -= sizeof(struct ip);
6908+   *(u_short *)il0->ilsum = in_cksum(m, illen + sizeof(struct ilhdr));
6909+   m->m_data -= sizeof(struct ip);
6910+   m->m_len  += sizeof(struct ip);
6911+
6912+   return ip_output(m, 0, ro, 0 ,0);
6913+ }
6914+
6915+ static struct ilpcb *
6916+ il_newconn(struct ilpcb * ilpcb, struct in_addr ti_dst, u_short ti_dport,
6917+ 	   struct in_addr ti_src, u_short ti_sport)
6918+ {
6919+   register struct ilpcb * ilpcb0;
6920+   struct socket *so2, * so;
6921+   struct inpcb * inp;
6922+   struct sockaddr_in sin;
6923+
6924+   so = ilpcb->inpcb->inp_socket;
6925+   so2 = sonewconn(so, 0);
6926+   if (so2 == 0) {
6927+     so2 = sodropablereq(so);
6928+     if (so2) {
6929+       il_drop(sotoilpcb(so2), ETIMEDOUT);
6930+       so2 = sonewconn(so, 0);
6931+     }
6932+     if (!so2)
6933+       return 0;
6934+   }
6935+   so = so2;
6936+
6937+   inp = (struct inpcb *)so->so_pcb;
6938+   inp->inp_laddr = ti_dst;
6939+   inp->inp_lport = ti_dport;
6940+   if (in_pcbinshash(inp) != 0) {
6941+ 				/*
6942+ 				 * Undo the assignments above if we failed to put
6943+ 				 * the PCB on the hash lists.
6944+ 				 */
6945+     inp->inp_laddr.s_addr = INADDR_ANY;
6946+     inp->inp_lport = 0;
6947+
6948+     soabort(so);
6949+     return 0;
6950+   }
6951+
6952+   bzero((char *)&sin, sizeof(sin));
6953+   sin.sin_family = AF_INET;
6954+   sin.sin_len = sizeof(sin);
6955+   sin.sin_addr = ti_src;
6956+   sin.sin_port = ti_sport;
6957+   if (in_pcbconnect(inp, (struct sockaddr *)&sin, &proc0)) {
6958+     inp->inp_laddr.s_addr = INADDR_ANY;
6959+     soabort(so);
6960+     return 0;
6961+   }
6962+
6963+   ilpcb0 = intoilpcb(inp);
6964+   ilpcb0->state = ILS_LISTENING;
6965+
6966+   return ilpcb0;
6967+ }
6968+
6969+ /* ack processing */
6970+ static void il_proc_ack(struct ilpcb * ilpcb, struct socket * so, u_long ack)
6971+ {
6972+   if( ack >= ilpcb->unacked ) {
6973+     ilpcb->rxt_timer = 0;
6974+     ilpcb->death_timer = 0;
6975+
6976+     /* the rxt timer is not prop. to RTT */
6977+     /* reset it so that the first rxt is always 1 second */
6978+     ilpcb->rxt_timer_cur = 2;
6979+
6980+     if( ack >= ilpcb->next )
6981+       ack = ilpcb->next - 1;
6982+     while (ilpcb->unacked <= ack ) {
6983+       sbdroprecord(&so->so_snd);
6984+       ilpcb->unacked++;
6985+     }
6986+     if( ilpcb->unacked != ilpcb->next ) {
6987+       ilpcb->rxt_timer = ilpcb->rxt_timer_cur;
6988+       ilpcb->death_timer = ilpcb->death_timer_cur; /* do we need this here? */
6989+     }
6990+     sowwakeup(so);
6991+   }
6992+ }
6993+
6994+ static int il_proc_data(struct ilpcb * ilpcb, struct socket * so, struct mbuf * m, u_long seq, int spec)
6995+ {
6996+   struct mbuf * m0;
6997+   struct ip * ip;
6998+   int hlen = sizeof(struct ip) + sizeof(struct ilhdr);
6999+   struct ilhdr * il;
7000+   int needack = 0;
7001+
7002+   ip = mtod(m, struct ip *);
7003+   il = (struct ilhdr *)(ip+1);
7004+   if( seq == ilpcb->recvd + 1 ) {
7005+     needack = 1;
7006+     while(1) {
7007+       ilpcb->recvd = seq;
7008+
7009+       m->m_len -= hlen;
7010+       m->m_pkthdr.len -= hlen;
7011+       m->m_data += hlen;
7012+       sbappendrecord(&so->so_rcv, m);
7013+
7014+       if( (m0 = il_segq_top(ilpcb)) == 0 )
7015+ 	break;
7016+       ip = mtod(m0, struct ip *);
7017+       il = (struct ilhdr *)(ip+1);
7018+       seq = ntohl(*(u_long *)il->ilid);
7019+       if( seq != ilpcb->recvd + 1 )
7020+ 	break;
7021+       il_segq_dequeue(ilpcb);
7022+       m = m0;
7023+     };
7024+     sorwakeup(so);
7025+   } else {
7026+     if( seq > ilpcb->recvd )
7027+       il_segq_insert(ilpcb, m, seq, il);
7028+     else
7029+       m_freem(m);
7030+   }
7031+
7032+   return needack;
7033+ }
7034+
7035+ /* assume we only have one connection */
7036+ void il_input(struct mbuf * m, int iphlen)
7037+ {
7038+   struct ilhdr * il;
7039+   struct ilpcb * ilpcb = 0;
7040+   int len, type;
7041+   u_long seq, ack;
7042+   struct ip * ip;
7043+   struct inpcb * inp;
7044+   u_short sport, dport;
7045+   struct socket * so;
7046+   u_char spec;
7047+
7048+   /*
7049+    * Strip IP options, if any; should skip this,
7050+    * make available to user, and use on returned packets,
7051+    * but we don't yet have a way to check the checksum
7052+    * with options still present.
7053+    */
7054+   if (iphlen > sizeof (struct ip)) {
7055+     ip_stripoptions(m, (struct mbuf *)0);
7056+     iphlen = sizeof(struct ip);
7057+   }
7058+
7059+   /*
7060+    * Get IP and IL header together in first mbuf.
7061+    */
7062+   ip = mtod(m, struct ip *);
7063+   if (m->m_len < iphlen + sizeof(struct ilhdr)) {
7064+     if ((m = m_pullup(m, iphlen + sizeof(struct ilhdr))) == 0) {
7065+       return;
7066+     }
7067+     ip = mtod(m, struct ip *);
7068+   }
7069+   il = (struct ilhdr *)((caddr_t)ip + iphlen);
7070+
7071+   len = ntohs(*(u_short *)il->illen);
7072+   seq = ntohl(*(u_long *)il->ilid);
7073+   ack = ntohl(*(u_long *)il->ilack);
7074+   sport = *(u_short *)il->ilsrc;
7075+   dport = *(u_short *)il->ildst;
7076+   type = il->iltype;
7077+   spec = il->ilspec;
7078+
7079+   inp = in_pcblookup_hash(&ilbinfo, ip->ip_src, sport, ip->ip_dst, dport, 1);
7080+   if ( inp == 0 && type == ILT_SYNC )
7081+     goto dropwithrest;
7082+   if( inp == 0 )
7083+     goto drop;
7084+
7085+   ilpcb = intoilpcb(inp);
7086+   if( ilpcb == 0 )
7087+     goto drop;
7088+
7089+   so = inp->inp_socket;
7090+   if( type == ILT_QUERY ) { /* XXX: can we use the same mbuf to send? */
7091+     il_send_empty(ilpcb, ILT_STATE, il->ilspec);
7092+     goto drop;
7093+   }
7094+
7095+  again:
7096+   /* FSM transition */
7097+   switch( ilpcb->state ) {
7098+   case ILS_SYNCER:
7099+     if( ack != ilpcb->start )
7100+       goto drop;
7101+     switch( type ) {
7102+     case ILT_SYNC:
7103+       ilpcb->unacked++;
7104+       ilpcb->recvd = seq;
7105+       il_send_empty(ilpcb, ILT_ACK, 0);
7106+       ilpcb->state = ILS_ESTABLISHED;
7107+       ilpcb->rxt_timer = 0;
7108+       ilpcb->death_timer = 0;
7109+       soisconnected(inp->inp_socket);
7110+       break;
7111+     case ILT_CLOSE:
7112+       il_drop(ilpcb, ECONNREFUSED);
7113+       break;
7114+     }
7115+     break;
7116+
7117+   case ILS_LISTENING:
7118+     if( type == ILT_SYNC && ack == 0 && so->so_options & SO_ACCEPTCONN ) {
7119+       ilpcb = il_newconn(ilpcb, ip->ip_dst, dport, ip->ip_src, sport);
7120+
7121+       ilpcb->next = ilpcb->start = random();
7122+       ilpcb->unacked = ilpcb->next;
7123+       ilpcb->rstart = ilpcb->recvd = seq;
7124+       ilpcb->state = ILS_SYNCEE;
7125+       il_send_empty(ilpcb, ILT_SYNC, 0);
7126+       ilpcb->next++;
7127+     } else
7128+       il_respond(ilpcb, ip, il, ILT_CLOSE, 0);
7129+     break;
7130+
7131+   case ILS_SYNCEE:
7132+     if( ack == ilpcb->start ) {
7133+       ilpcb->rxt_timer = 0;
7134+       ilpcb->unacked++;
7135+       ilpcb->state = ILS_ESTABLISHED;
7136+       soisconnected(so);
7137+       goto again;
7138+       break;
7139+     }
7140+     if( type == ILT_SYNC && seq == ilpcb->recvd && ack == 0 )
7141+       il_send_empty(ilpcb, ILT_SYNC, 0);
7142+     break;
7143+
7144+   case ILS_ESTABLISHED:
7145+     il_proc_ack(ilpcb, so, ack);
7146+     switch( type ) {
7147+     case ILT_DATA:
7148+       if( il_proc_data(ilpcb, so, m, seq, spec) )
7149+ 	ilpcb->flags |= ILF_NEEDACK;
7150+       goto done;
7151+       break;
7152+     case ILT_DATAQUERY:
7153+       il_proc_data(ilpcb, so, m, seq, spec);
7154+       il_send_empty(ilpcb, ILT_STATE, spec);
7155+       goto done;
7156+       break;
7157+     case ILT_CLOSE:
7158+       if( ack < ilpcb->next && ack >= ilpcb->start ) {
7159+ 	if( ilpcb->recvd+1 == seq )
7160+ 	  ilpcb->recvd = seq;
7161+ 	il_send_empty(ilpcb, ILT_CLOSE, 0);
7162+ 	ilpcb->state = ILS_CLOSING;
7163+       }
7164+       break;
7165+     case ILT_STATE:
7166+       if( ack < ilpcb->rxt_max ) {
7167+ 	ilpcb->rxt_max = ilpcb->next;
7168+ 	il_output(ilpcb, 0, ILT_DATAQUERY, ilpcb->unacked, 1);
7169+       }
7170+       break;
7171+     case ILT_SYNC:
7172+       il_send_empty(ilpcb, ILT_ACK, 0);
7173+       break;
7174+     }
7175+     break;
7176+
7177+   case	ILS_CLOSED:
7178+     goto drop;
7179+     break;
7180+
7181+   case ILS_CLOSING:
7182+     if( type == ILT_CLOSE ) {
7183+       if( ilpcb->recvd+1 == seq )
7184+ 	ilpcb->recvd = seq;
7185+       il_send_empty(ilpcb, ILT_CLOSE, 0);
7186+       ilpcb->state = ILS_CLOSED;
7187+       il_close(ilpcb);
7188+     }
7189+     break;
7190+   }
7191+
7192+   m_freem(m);
7193+  done:
7194+   return;
7195+
7196+  dropwithrest:
7197+   il_respond(ilpcb, ip, il, ILT_CLOSE, 0);
7198+  drop:
7199+   m_freem(m);
7200+ }
7201+
7202+ static void il_sendseqinit(struct ilpcb * ilpcb)
7203+ {
7204+   ilpcb->start = ilpcb->next = random();
7205+   ilpcb->unacked = ilpcb->next;
7206+   ilpcb->state = ILS_SYNCER;
7207+   ilpcb->next++;
7208+ }
7209+
7210+ static void il_rxt_timeout(struct ilpcb * ilpcb)
7211+ {
7212+   switch ( ilpcb->state ) {
7213+   case ILS_ESTABLISHED:
7214+     il_output(ilpcb, 0, ILT_DATAQUERY, ilpcb->unacked, 1);
7215+     ilpcb->rxtot++;
7216+     break;
7217+   case ILS_SYNCER:
7218+   case ILS_SYNCEE:
7219+     il_send_empty(ilpcb, ILT_SYNC, 0);
7220+     break;
7221+   case ILS_CLOSING:
7222+     il_send_empty(ilpcb, ILT_CLOSE, 0);
7223+     break;
7224+   }
7225+   ilpcb->rxt_timer = ilpcb->rxt_timer_cur;
7226+ }
7227+
7228+ void il_ctlinput(int cmd, struct sockaddr *sa, void *vip)
7229+ {}
7230+
7231+ int  il_ctloutput(struct socket *so, struct sockopt *sopt)
7232+ { return 0; }
7233+
7234+ void il_drain()
7235+ {}
7236+
7237+ void il_slowtimo()
7238+ {
7239+   struct ilpcb * ilpcb;
7240+   struct inpcb * inp;
7241+   int s;
7242+
7243+   s = splnet();
7244+   for(inp = ilb.lh_first; inp; inp = inp->inp_list.le_next) {
7245+     ilpcb = intoilpcb(inp);
7246+     if(ilpcb->death_timer &&  --ilpcb->death_timer == 0 )
7247+       il_drop(ilpcb, ETIMEDOUT);
7248+
7249+     if(ilpcb->rxt_timer &&  --ilpcb->rxt_timer == 0 ) {
7250+       ilpcb->rxt_timer_cur <<= 1;
7251+       il_rxt_timeout(ilpcb);
7252+     }
7253+   }
7254+   splx(s);
7255+ }
7256+
7257+ void il_fasttimo()
7258+ {
7259+   struct ilpcb * ilpcb;
7260+   struct inpcb * inp;
7261+   int s;
7262+
7263+   s = splnet();
7264+   for(inp = ilb.lh_first; inp; inp = inp->inp_list.le_next) {
7265+     ilpcb = intoilpcb(inp);
7266+     if(ilpcb->flags & ILF_NEEDACK) {
7267+       ilpcb->flags &= ~ILF_NEEDACK;
7268+       il_send_empty(ilpcb, ILT_ACK, 0);
7269+     }
7270+   }
7271+   splx(s);
7272+ }
7273+
7274+ static struct ilpcb * il_newilpcb(struct inpcb * inp)
7275+ {
7276+   struct inp_ilpcb *it;
7277+   register struct ilpcb *ilpcb;
7278+
7279+   it = (struct inp_ilpcb *)inp;
7280+   ilpcb = &it->ilpcb;
7281+   bzero((char *) ilpcb, sizeof(struct ilpcb));
7282+
7283+   ilpcb->state = ILS_CLOSED;
7284+   ilpcb->inpcb = inp;
7285+   ilpcb->rxt_timer_cur = 2;
7286+   ilpcb->death_timer_cur = 20;
7287+
7288+   ilpcb->inpcb = inp;	/* XXX */
7289+   inp->inp_ip_ttl = ip_defttl;
7290+   inp->inp_ppcb = (caddr_t)ilpcb;
7291+   return (ilpcb);		/* XXX */
7292+ }
7293+
7294+ /*
7295+  * Common subroutine to open a TCP connection to remote host specified
7296+  * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
7297+  * port number if needed.  Call in_pcbladdr to do the routing and to choose
7298+  * a local host address (interface).  If there is an existing incarnation
7299+  * of the same connection in TIME-WAIT state and if the remote host was
7300+  * sending CC options and if the connection duration was < MSL, then
7301+  * truncate the previous TIME-WAIT state and proceed.
7302+  * Initialize connection parameters and enter SYN-SENT state.
7303+  */
7304+ static int
7305+ il_connect(struct ilpcb *ilpcb, struct sockaddr *nam, struct proc *p)
7306+ {
7307+ 	struct inpcb *inp = ilpcb->inpcb, *oinp;
7308+ 	struct socket *so = inp->inp_socket;
7309+ 	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
7310+ 	struct sockaddr_in *ifaddr;
7311+ 	int error;
7312+
7313+ 	if (inp->inp_lport == 0) {
7314+ 		error = in_pcbbind(inp, (struct sockaddr *)0, p);
7315+ 		if (error)
7316+ 			return error;
7317+ 	}
7318+
7319+ 	/*
7320+ 	 * Cannot simply call in_pcbconnect, because there might be an
7321+ 	 * earlier incarnation of this same connection still in
7322+ 	 * TIME_WAIT state, creating an ADDRINUSE error.
7323+ 	 */
7324+ 	error = in_pcbladdr(inp, nam, &ifaddr);
7325+ 	if (error)
7326+ 		return error;
7327+ 	oinp = in_pcblookup_hash(inp->inp_pcbinfo,
7328+ 	    sin->sin_addr, sin->sin_port,
7329+ 	    inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
7330+ 						: ifaddr->sin_addr,
7331+ 	    inp->inp_lport,  0);
7332+ 	if (oinp) {
7333+ 			return EADDRINUSE;
7334+ 	}
7335+ 	if (inp->inp_laddr.s_addr == INADDR_ANY)
7336+ 		inp->inp_laddr = ifaddr->sin_addr;
7337+ 	inp->inp_faddr = sin->sin_addr;
7338+ 	inp->inp_fport = sin->sin_port;
7339+ 	in_pcbrehash(inp);
7340+
7341+ #if 0
7342+ 	ilpcb->t_template = tcp_template(tp);
7343+ 	if (ilpcb->t_template == 0) {
7344+ 		in_pcbdisconnect(inp);
7345+ 		return ENOBUFS;
7346+ 	}
7347+ #endif
7348+
7349+ 	soisconnecting(so);
7350+ 	il_sendseqinit(ilpcb);
7351+
7352+ 	return 0;
7353+ }
7354+
7355+ static int il_usr_send(struct socket *so, int flags, struct mbuf * m, struct sockaddr *addr, struct mbuf *control, struct proc *p)
7356+ {
7357+   struct ilpcb * ilpcb;
7358+   struct inpcb * inp = sotoinpcb(so);
7359+   int error;
7360+   struct mbuf * m0;
7361+
7362+   if (inp == 0) {
7363+     m_freem(m);
7364+     return EINVAL;
7365+   }
7366+   ilpcb = intoilpcb(inp);
7367+
7368+   if (sbspace(&so->so_snd) < -512) {
7369+     m_freem(m);
7370+     error = ENOBUFS;
7371+     goto out;
7372+   }
7373+
7374+   sbappendrecord(&so->so_snd, m);
7375+   m0 = m_copypacket(m, M_DONTWAIT);
7376+   error = il_output(ilpcb, m0, ILT_DATA, ilpcb->next++, 0);
7377+
7378+  out:
7379+   return error;
7380+ }
7381+
7382+ static int il_usr_attach(struct socket *so, int proto, struct proc *p)
7383+ {
7384+   int s = splnet();
7385+   int error = 0;
7386+   struct inpcb *inp = sotoinpcb(so);
7387+   struct ilpcb *ilpcb = 0;
7388+
7389+   if (inp) {
7390+     error = EISCONN;
7391+     goto out;
7392+   }
7393+
7394+   if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
7395+     error = soreserve(so, il_sendspace, il_recvspace);
7396+     if (error)
7397+       goto out;
7398+   }
7399+
7400+   error = in_pcballoc(so, &ilbinfo, p);
7401+
7402+   if (error)
7403+     goto out;
7404+
7405+   inp = sotoinpcb(so);
7406+   ilpcb = il_newilpcb(inp);
7407+   if (ilpcb == 0) {
7408+     int nofd = so->so_state & SS_NOFDREF;	/* XXX */
7409+
7410+     so->so_state &= ~SS_NOFDREF;	/* don't free the socket yet */
7411+     in_pcbdetach(inp);
7412+     so->so_state |= nofd;
7413+     error = ENOBUFS;
7414+     goto out;
7415+   }
7416+   ilpcb->state = ILS_CLOSED;
7417+   ilpcb->segq = 0;
7418+
7419+  out:
7420+   splx(s);
7421+   return error;
7422+
7423+ }
7424+
7425+ static int il_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
7426+ {
7427+   int s = splnet();
7428+   int error = 0;
7429+   struct inpcb *inp = sotoinpcb(so);
7430+   struct ilpcb *ilpcb;
7431+   struct sockaddr_in *sinp;
7432+
7433+   if (inp == 0) {
7434+     splx(s);
7435+     return EINVAL;
7436+   }
7437+   ilpcb = intoilpcb(inp);
7438+
7439+ 	/*
7440+ 	 * Must check for multicast addresses and disallow binding
7441+ 	 * to them.
7442+ 	 */
7443+   sinp = (struct sockaddr_in *)nam;
7444+   if (sinp->sin_family == AF_INET &&
7445+       IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
7446+     error = EAFNOSUPPORT;
7447+     goto out;
7448+   }
7449+   error = in_pcbbind(inp, nam, p);
7450+  out: splx(s);
7451+   return error;
7452+ }
7453+
7454+ /*
7455+  * Initiate connection to peer.
7456+  * Create a template for use in transmissions on this connection.
7457+  * Enter SYN_SENT state, and mark socket as connecting.
7458+  * Start keep-alive timer, and seed output sequence space.
7459+  * Send initial segment on connection.
7460+  */
7461+ static int
7462+ il_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
7463+ {
7464+   int s = splnet();
7465+   int error = 0;
7466+   struct inpcb *inp = sotoinpcb(so);
7467+   struct ilpcb *ilpcb;
7468+   struct sockaddr_in *sinp;
7469+
7470+   if (inp == 0) {
7471+     splx(s);
7472+     return EINVAL;
7473+   }
7474+   ilpcb = intoilpcb(inp);
7475+
7476+   /*
7477+    * Must disallow TCP ``connections'' to multicast addresses.
7478+    */
7479+   sinp = (struct sockaddr_in *)nam;
7480+   if (sinp->sin_family == AF_INET
7481+       && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
7482+     error = EAFNOSUPPORT;
7483+     goto out;
7484+   }
7485+
7486+   if ((error = il_connect(ilpcb, nam, p)) != 0)
7487+     goto out;
7488+
7489+   error = il_send_empty(ilpcb, ILT_SYNC, 0);
7490+
7491+  out: splx(s);
7492+   return error;
7493+ }
7494+
7495+ /*
7496+  * Close a TCP control block:
7497+  *	discard all space held by the tcp
7498+  *	discard internet protocol block
7499+  *	wake up any sleepers
7500+  */
7501+ static struct ilpcb *
7502+ il_close(struct ilpcb *ilpcb)
7503+ {
7504+ 	register struct mbuf *q;
7505+ 	register struct mbuf *nq;
7506+ 	struct inpcb *inp = ilpcb->inpcb;
7507+ 	struct socket *so = inp->inp_socket;
7508+
7509+ 	/* free the reassembly queue, if any */
7510+ 	for (q = ilpcb->segq; q; q = nq) {
7511+ 		nq = q->m_nextpkt;
7512+ 		ilpcb->segq = nq;
7513+ 		m_freem(q);
7514+ 	}
7515+ 	inp->inp_ppcb = NULL;
7516+ 	soisdisconnected(so);
7517+ 	in_pcbdetach(inp);
7518+ 	return ((struct ilpcb *)0);
7519+ }
7520+
7521+ /*
7522+  * User issued close, and wish to trail through shutdown states:
7523+  * if never received SYN, just forget it.  If got a SYN from peer,
7524+  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
7525+  * If already got a FIN from peer, then almost done; go to LAST_ACK
7526+  * state.  In all other cases, have already sent FIN to peer (e.g.
7527+  * after PRU_SHUTDOWN), and just have to play tedious game waiting
7528+  * for peer to send FIN or not respond to keep-alives, etc.
7529+  * We can let the user exit from the close as soon as the FIN is acked.
7530+  */
7531+ static struct ilpcb *
7532+ il_usrclosed(struct ilpcb *ilpcb)
7533+ {
7534+
7535+ 	switch (ilpcb->state) {
7536+ 	case ILS_CLOSED:
7537+ 	case ILS_LISTENING:
7538+ 		ilpcb->state = ILS_CLOSED;
7539+ 		ilpcb = il_close(ilpcb);
7540+ 		break;
7541+
7542+ 	case ILS_SYNCER:
7543+ 	case ILS_SYNCEE:
7544+ 	case ILS_ESTABLISHED:
7545+ 	  il_send_empty(ilpcb, ILT_CLOSE, 0);
7546+ 	  ilpcb->state = ILS_CLOSING;
7547+ 	  break;
7548+
7549+ 	case ILS_CLOSING:
7550+ 		break;
7551+ 	}
7552+ 	return (ilpcb);
7553+ }
7554+
7555+ /*
7556+  * Drop a TCP connection, reporting
7557+  * the specified error.  If connection is synchronized,
7558+  * then send a RST to peer.
7559+  */
7560+ struct ilpcb *
7561+ il_drop(ilpcb, errno0)
7562+      register struct ilpcb *ilpcb;
7563+      int errno0;
7564+ {
7565+   struct socket *so = ilpcb->inpcb->inp_socket;
7566+
7567+   panic("il_drop");
7568+
7569+   switch(ilpcb->state) {
7570+   case ILS_SYNCEE:
7571+   case ILS_ESTABLISHED:
7572+   case ILS_CLOSING:
7573+     il_send_empty(ilpcb, ILT_CLOSE, 0);
7574+   default:
7575+     break;
7576+   }
7577+   ilpcb->state = ILS_CLOSED;
7578+   so->so_error = errno0;
7579+   return (il_close(ilpcb));
7580+ }
7581+
7582+ /*
7583+  * Initiate (or continue) disconnect.
7584+  * If embryonic state, just send reset (once).
7585+  * If in ``let data drain'' option and linger null, just drop.
7586+  * Otherwise (hard), mark socket disconnecting and drop
7587+  * current input data; switch states based on user close, and
7588+  * send segment to peer (with FIN).
7589+  */
7590+ static struct ilpcb *
7591+ il_disconnect(struct ilpcb *ilpcb)
7592+ {
7593+   struct socket *so = ilpcb->inpcb->inp_socket;
7594+
7595+   soisdisconnecting(so);
7596+   sbflush(&so->so_rcv);
7597+   ilpcb = il_usrclosed(ilpcb);
7598+
7599+   return (ilpcb);
7600+ }
7601+
7602+
7603+ /*
7604+  * pru_detach() detaches the IL protocol from the socket.
7605+  * If the protocol state is non-embryonic, then can't
7606+  * do this directly: have to initiate a pru_disconnect(),
7607+  * which may finish later; embryonic TCB's can just
7608+  * be discarded here.
7609+  */
7610+ static int
7611+ il_usr_detach(struct socket *so)
7612+ {
7613+ 	int s = splnet();
7614+ 	int error = 0;
7615+ 	struct inpcb *inp = sotoinpcb(so);
7616+ 	struct ilpcb *ilpcb;
7617+
7618+ 	if (inp == 0) {
7619+ 		splx(s);
7620+ 		return EINVAL;	/* XXX */
7621+ 	}
7622+ 	ilpcb = intoilpcb(inp);
7623+ 	ilpcb = il_disconnect(ilpcb);
7624+ 	splx(s);
7625+ 	return error;
7626+ }
7627+
7628+ /*
7629+  * Mark the connection as being incapable of further output.
7630+  */
7631+ static int
7632+ il_usr_shutdown(struct socket *so)
7633+ {
7634+ 	int s = splnet();
7635+ 	int error = 0;
7636+ 	struct inpcb *inp = sotoinpcb(so);
7637+ 	struct ilpcb *ilpcb;
7638+
7639+   if (inp == 0) {
7640+     splx(s);
7641+     return EINVAL;
7642+   }
7643+   ilpcb = intoilpcb(inp);
7644+
7645+   socantsendmore(so);
7646+   ilpcb = il_usrclosed(ilpcb);
7647+   splx(s);
7648+   return error;
7649+ }
7650+
7651+ /*
7652+  * Initiate disconnect from peer.
7653+  * If connection never passed embryonic stage, just drop;
7654+  * else if don't need to let data drain, then can just drop anyways,
7655+  * else have to begin TCP shutdown process: mark socket disconnecting,
7656+  * drain unread data, state switch to reflect user close, and
7657+  * send segment (e.g. FIN) to peer.  Socket will be really disconnected
7658+  * when peer sends FIN and acks ours.
7659+  *
7660+  * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
7661+  */
7662+ static int
7663+ il_usr_disconnect(struct socket *so)
7664+ {
7665+   int s = splnet();
7666+   int error = 0;
7667+   struct inpcb *inp = sotoinpcb(so);
7668+   struct ilpcb * ilpcb;
7669+
7670+   if (inp == 0) {
7671+     splx(s);
7672+     return EINVAL;
7673+   }
7674+   ilpcb = intoilpcb(inp);
7675+
7676+   il_disconnect(ilpcb);
7677+   splx(s);
7678+   return error;
7679+ }
7680+
7681+ /*
7682+  * Abort the TCP.
7683+  */
7684+ static int
7685+ il_usr_abort(struct socket *so)
7686+ {
7687+ 	int s = splnet();
7688+ 	int error = 0;
7689+ 	struct inpcb *inp = sotoinpcb(so);
7690+ 	struct ilpcb * ilpcb;
7691+
7692+   if (inp == 0) {
7693+     splx(s);
7694+     return EINVAL;
7695+   }
7696+   ilpcb = intoilpcb(inp);
7697+
7698+   ilpcb = il_drop(ilpcb, ECONNABORTED);
7699+   splx(s);
7700+   return error;
7701+
7702+ }
7703+
7704+ /*
7705+  * Prepare to accept connections.
7706+  */
7707+ static int
7708+ il_usr_listen(struct socket *so, struct proc *p)
7709+ {
7710+   int s = splnet();
7711+   int error = 0;
7712+   struct inpcb *inp = sotoinpcb(so);
7713+   struct ilpcb *ilpcb;
7714+
7715+   if (inp == 0) {
7716+     splx(s);
7717+     return EINVAL;
7718+   }
7719+   ilpcb = intoilpcb(inp);
7720+
7721+   if (inp->inp_lport == 0)
7722+     error = in_pcbbind(inp, (struct sockaddr *)0, p);
7723+   if (error == 0)
7724+     ilpcb->state = ILS_LISTENING;
7725+
7726+   splx(s);
7727+   return error;
7728+ }
7729+
7730+ /*
7731+  * Accept a connection.  Essentially all the work is
7732+  * done at higher levels; just return the address
7733+  * of the peer, storing through addr.
7734+  */
7735+ static int
7736+ il_usr_accept(struct socket *so, struct sockaddr **nam)
7737+ {
7738+   int s = splnet();
7739+   int error = 0;
7740+   struct inpcb *inp = sotoinpcb(so);
7741+   struct ilpcb * ilpcb;
7742+
7743+   if (inp == 0) {
7744+     splx(s);
7745+     return EINVAL;
7746+   }
7747+   ilpcb = intoilpcb(inp);
7748+
7749+   in_setpeeraddr(so, nam);
7750+   splx(s);
7751+   return error;
7752+ }
7753+
7754+ /* xxx - should be const */
7755+ struct pr_usrreqs il_usrreqs = {
7756+ 	il_usr_abort, il_usr_accept, il_usr_attach, il_usr_bind,
7757+ 	il_usr_connect, pru_connect2_notsupp, in_control, il_usr_detach,
7758+ 	il_usr_disconnect, il_usr_listen, in_setpeeraddr, pru_rcvd_notsupp,
7759+ 	pru_rcvoob_notsupp, il_usr_send, pru_sense_null, il_usr_shutdown,
7760+ 	in_setsockaddr, sosend, soreceive, sopoll
7761+ };
7762diff -N -c -r /usr/src/sys/netinet/il.h ./netinet/il.h
7763*** /usr/src/sys/netinet/il.h	Wed Dec 31 19:00:00 1969
7764--- ./netinet/il.h	Thu Sep 30 11:24:51 1999
7765***************
7766*** 0 ****
7767--- 1,17 ----
7768+
7769+ #ifndef NETINET_IL_H_
7770+ #define NETINET_IL_H_
7771+
7772+ struct ilhdr
7773+ {
7774+ 	u_char	ilsum[2];	/* Checksum including header */
7775+ 	u_char	illen[2];	/* Packet length */
7776+ 	u_char	iltype;		/* Packet type */
7777+ 	u_char	ilspec;		/* Special */
7778+ 	u_char	ilsrc[2];	/* Src port */
7779+ 	u_char	ildst[2];	/* Dst port */
7780+ 	u_char	ilid[4];	/* Sequence id */
7781+ 	u_char	ilack[4];	/* Acked sequence */
7782+ };
7783+
7784+ #endif
7785diff -N -c -r /usr/src/sys/netinet/il_var.h ./netinet/il_var.h
7786*** /usr/src/sys/netinet/il_var.h	Wed Dec 31 19:00:00 1969
7787--- ./netinet/il_var.h	Thu Oct  7 10:45:05 1999
7788***************
7789*** 0 ****
7790--- 1,46 ----
7791+ #ifndef NETINET_IL_VAR_H_
7792+ #define NETINET_IL_VAR_H_
7793+
7794+ struct ilpcb			/* Control block */
7795+ {
7796+   int	state;		/* Connection state */
7797+   struct inpcb * inpcb;  /* back pointer to internet pcb */
7798+   u_long unacked;
7799+
7800+ #define ILF_NEEDACK 1
7801+   u_long flags;
7802+
7803+   u_long rxt_max;
7804+   int rxt_timer;  /* number of ticks to the next timeout */
7805+   int rxt_timer_cur;  /* current rxt timer period */
7806+
7807+   int death_timer;
7808+   int death_timer_cur;
7809+
7810+   u_long	next;		/* Id of next to send */
7811+   u_long	recvd;		/* Last packet received */
7812+
7813+   u_long	start;		/* Local start id */
7814+   u_long	rstart;		/* Remote start id */
7815+   int	rxtot;		/* number of retransmits on this connection */
7816+
7817+   struct mbuf * segq;
7818+ };
7819+
7820+ #define	intoilpcb(ip)	((struct ilpcb *)(ip)->inp_ppcb)
7821+ #define	sotoilpcb(so)	(intoilpcb(sotoinpcb(so)))
7822+
7823+ #ifdef KERNEL
7824+ void il_init __P((void));
7825+ void il_input __P((struct mbuf * m, int iphlen));
7826+ void il_slowtimo __P((void));
7827+ void il_fasttimo __P((void));
7828+ void il_ctlinput __P((int cmd, struct sockaddr *sa, void *vip));
7829+ int  il_ctloutput __P((struct socket *so, struct sockopt *sopt));
7830+ void il_drain __P((void));
7831+
7832+ extern struct pr_usrreqs il_usrreqs;
7833+
7834+ #endif
7835+
7836+ #endif
7837diff -N -c -r /usr/src/sys/netinet/in_proto.c ./netinet/in_proto.c
7838*** /usr/src/sys/netinet/in_proto.c	Sat Aug 22 23:07:14 1998
7839--- ./netinet/in_proto.c	Wed Oct  6 17:55:12 1999
7840***************
7841*** 36,41 ****
7842--- 36,42 ----
7843
7844  #include "opt_ipdivert.h"
7845  #include "opt_ipx.h"
7846+ #include "opt_inet.h"
7847
7848  #include <sys/param.h>
7849  #include <sys/kernel.h>
7850***************
7851*** 71,76 ****
7852--- 72,82 ----
7853  #include <netns/ns_if.h>
7854  #endif
7855
7856+ #ifdef IL
7857+ #include <netinet/il.h>
7858+ #include <netinet/il_var.h>
7859+ #endif
7860+
7861  extern	struct domain inetdomain;
7862  static	struct pr_usrreqs nousrreqs;
7863
7864***************
7865*** 161,166 ****
7866--- 167,181 ----
7867    0,
7868    0,		0,		0,		0,
7869    &rip_usrreqs
7870+ },
7871+ #endif
7872+ #ifdef IL
7873+ { SOCK_SEQPACKET,	&inetdomain,	IPPROTO_IL,
7874+ 	PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD|PR_ATOMIC,
7875+   il_input,	0,		il_ctlinput,	il_ctloutput,
7876+   0,
7877+   il_init,	il_fasttimo,	il_slowtimo,	il_drain,
7878+   &il_usrreqs
7879  },
7880  #endif
7881  	/* raw wildcard */
7882diff -N -c -r /usr/src/sys/sys/vnode.h ./sys/vnode.h
7883*** /usr/src/sys/sys/vnode.h	Sat Mar 20 04:37:49 1999
7884--- ./sys/vnode.h	Fri Oct 15 17:44:42 1999
7885***************
7886*** 62,68 ****
7887  enum vtagtype	{
7888  	VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_PC, VT_LFS, VT_LOFS, VT_FDESC,
7889  	VT_PORTAL, VT_NULL, VT_UMAP, VT_KERNFS, VT_PROCFS, VT_AFS, VT_ISOFS,
7890! 	VT_UNION, VT_MSDOSFS, VT_DEVFS, VT_TFS, VT_VFS, VT_CODA, VT_NTFS
7891  };
7892
7893  /*
7894--- 62,68 ----
7895  enum vtagtype	{
7896  	VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_PC, VT_LFS, VT_LOFS, VT_FDESC,
7897  	VT_PORTAL, VT_NULL, VT_UMAP, VT_KERNFS, VT_PROCFS, VT_AFS, VT_ISOFS,
7898! 	VT_UNION, VT_MSDOSFS, VT_DEVFS, VT_TFS, VT_VFS, VT_CODA, VT_NTFS, VT_U9FS
7899  };
7900
7901  /*
7902