Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/vnode.h>
#include <sys/mount.h>

#include <9fs/bitstring.h>
#include <9fs/9p.h>
#include <9fs/9auth.h>
#include <9fs/9fs.h>

int u9p_usetcp = 0;
struct u9fs_reqq u9fs_reqq;

#define N2HCHAR(x)              x = *p++
#define N2HSHORT(x)     x = (p[0] | (p[1]<<8)); p += 2
#define N2HLONG(x)              x = (p[0] | (p[1]<<8) |\
                                (p[2]<<16) | (p[3]<<24)); p += 4
#define N2HQUAD(x)      x = (u_int64_t)(p[0] | (p[1]<<8) |\
                                        (p[2]<<16) | (p[3]<<24)) |\
                                ((u_int64_t)(p[4] | (p[5]<<8) |\
                                        (p[6]<<16) | (p[7]<<24)) << 32); p += 8
#define N2HSTRING(x,n)  bcopy(p, x, n); p += n

#define H2NCHAR(x)      *p++ = x
#define H2NSHORT(x)     p[0]=x; p[1]=x>>8; p += 2
#define H2NLONG(x)              p[0]=x; p[1]=x>>8; p[2]=x>>16; p[3]=x>>24; p += 4
#define H2NQUAD(x)      p[0]=x; p[1]=x>>8;\
                        p[2]=x>>16;     p[3]=x>>24;\
                        p[4]=x>>32;     p[5]=x>>40;\
                        p[6]=x>>48;     p[7]=x>>56;\
                        p += 8
#define H2NSTRING(x,n)  bcopy(x, p, n); p += n

static void u9p_print __P((u_char * m, int len, struct u9fsreq * f));

static char * u9p_types[] = {
  "Tnop",
  "Rnop",
  "Tosession",
  "Rosession",
  "Terror",
  "Rerror",
  "Tflush",
  "Rflush",
  "Toattach",
  "Roattach",
  "Tclone",
  "Rclone",
  "Twalk",
  "Rwalk",
  "Topen",
  "Ropen",
  "Tcreate",
  "Rcreate",
  "Tread",
  "Rread",
  "Twrite",
  "Rwrite",
  "Tclunk",
  "Rclunk",
  "Tremove",
  "Rremove",
  "Tstat",
  "Rstat",
  "Twstat",
  "Rwstat",
  "Tclwalk",
  "Rclwalk",
  "Tauth",
  "Rauth",
  "Tsession",
  "Rsession",
  "Tattach",
  "Rattach",
  "Ttunnel",
  "Rtunnel",
  "Tmax"
};

int u9p_m2s(char *ap, int n, struct u9fsreq *f)
{
        u_char *p;

        p = (u_char*)ap;
        N2HCHAR(f->r_type);
        N2HSHORT(f->r_tag);
        switch(f->r_type)
        {
        default:
                return 0;

        case Tnop:
        case Tosession:
                break;

        case Tsession:
                N2HSTRING(f->r_chal, sizeof(f->r_chal));
                break;

        case Tflush:
                N2HSHORT(f->r_oldtag);
                break;

        case Tattach:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_uname, sizeof(f->r_uname));
                N2HSTRING(f->r_aname, sizeof(f->r_aname));
                N2HSTRING(f->r_ticket, sizeof(f->r_ticket));
                N2HSTRING(f->r_auth, sizeof(f->r_auth));
                break;

        case Toattach:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_uname, sizeof(f->r_uname));
                N2HSTRING(f->r_aname, sizeof(f->r_aname));
                N2HSTRING(f->r_ticket, U9FS_NAMELEN);
                break;

        case Tauth:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_uname, sizeof(f->r_uname));
                N2HSTRING(f->r_ticket, 8+U9FS_NAMELEN);
                break;

        case Tclone:
                N2HSHORT(f->r_fid);
                N2HSHORT(f->r_newfid);
                break;

        case Twalk:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_name, sizeof(f->r_name));
                break;

        case Topen:
                N2HSHORT(f->r_fid);
                N2HCHAR(f->r_mode);
                break;

        case Tcreate:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_name, sizeof(f->r_name));
                N2HLONG(f->r_perm);
                N2HCHAR(f->r_mode);
                break;

        case Tread:
                N2HSHORT(f->r_fid);
                N2HQUAD(f->r_offset);
                N2HSHORT(f->r_count);
                break;

        case Twrite:
                N2HSHORT(f->r_fid);
                N2HQUAD(f->r_offset);
                N2HSHORT(f->r_count);
                p++;    /* pad(1) */
                f->r_data = (char*)p; p += f->r_count;
                break;

        case Ttunnel:
                N2HSHORT(f->r_fid);
                break;

        case Tclunk:
                N2HSHORT(f->r_fid);
                break;

        case Tremove:
                N2HSHORT(f->r_fid);
                break;

        case Tstat:
                N2HSHORT(f->r_fid);
                break;

        case Twstat:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_stat, sizeof(f->r_stat));
                break;

        case Tclwalk:
                N2HSHORT(f->r_fid);
                N2HSHORT(f->r_newfid);
                N2HSTRING(f->r_name, sizeof(f->r_name));
                break;
/*
 */
        case Rnop:
        case Rosession:
                break;

        case Rsession:
                N2HSTRING(f->r_chal, sizeof(f->r_chal));
                N2HSTRING(f->r_authid, sizeof(f->r_authid));
                N2HSTRING(f->r_authdom, sizeof(f->r_authdom));
                break;

        case Rerror:
                N2HSTRING(f->r_ename, sizeof(f->r_ename));
                break;

        case Rflush:
                break;

        case Rattach:
                N2HSHORT(f->r_fid);
                N2HLONG(f->r_qid.path);
                N2HLONG(f->r_qid.vers);
                N2HSTRING(f->r_rauth, sizeof(f->r_rauth));
                break;

        case Roattach:
                N2HSHORT(f->r_fid);
                N2HLONG(f->r_qid.path);
                N2HLONG(f->r_qid.vers);
                break;

        case Rauth:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_ticket, 8+8+7+7);
                break;

        case Rclone:
                N2HSHORT(f->r_fid);
                break;

        case Rwalk:
        case Rclwalk:
                N2HSHORT(f->r_fid);
                N2HLONG(f->r_qid.path);
                N2HLONG(f->r_qid.vers);
                break;

        case Ropen:
                N2HSHORT(f->r_fid);
                N2HLONG(f->r_qid.path);
                N2HLONG(f->r_qid.vers);
                break;

        case Rcreate:
                N2HSHORT(f->r_fid);
                N2HLONG(f->r_qid.path);
                N2HLONG(f->r_qid.vers);
                break;

        case Rread:
                N2HSHORT(f->r_fid);
                N2HSHORT(f->r_count);
                p++;    /* pad(1) */
                f->r_data = (char*)p; p += f->r_count;
                break;

        case Rwrite:
                N2HSHORT(f->r_fid);
                N2HSHORT(f->r_count);
                break;

        case Rtunnel:
                N2HSHORT(f->r_fid);
                break;

        case Rclunk:
                N2HSHORT(f->r_fid);
                break;

        case Rremove:
                N2HSHORT(f->r_fid);
                break;

        case Rstat:
                N2HSHORT(f->r_fid);
                N2HSTRING(f->r_stat, sizeof(f->r_stat));
                break;

        case Rwstat:
                N2HSHORT(f->r_fid);
                break;
        }
        if((u_char*)ap+n == p)
                return n;
        return 0;
}

void u9p_print(u_char * m, int len, struct u9fsreq * f)
{
  struct u9fsreq u9fsreq;

  if( f == 0 )
    f = & u9fsreq;

  if( len < 3 ) {
    printf("truncated-9p %d", len);
    return;
  }

  if( u9p_m2s((char *)m, len, f) == 0 )
    return;

  printf("%s tag %d ", u9p_types[f->r_type-Tnop], f->r_tag);

  switch( f->r_type ) {
        default:
          return;

        case Tnop:
        case Tosession:
        case Toattach:
        case Tauth:
                break;

        case Tsession:
        case Rsession:
          printf("chal 0x%x 0x%x", *(u_int *)&f->r_chal[0], *(u_int *)&f->r_chal[4]);
                break;

        case Tflush:
          printf("oldtag %d", f->r_oldtag);
                break;

        case Tclone:
          printf("fid %d newfid %d", f->r_fid, f->r_newfid);
                break;

        case Twalk:
          printf("fid %d name %s", f->r_fid, f->r_name);
                break;

        case Topen:
          printf("fid %d %c", f->r_fid, f->r_mode);
                break;

        case Tcreate:
          printf("fid %d name %s perm 0x%x mode %c", f->r_fid,
                 f->r_name, f->r_perm, f->r_mode);
                break;

        case Tread:
        case Twrite:
          printf("fid %d offset 0x%llx count %d", f->r_fid,
                 f->r_offset, f->r_count);
                break;

        case Tattach:
        case Ttunnel:
        case Tclunk:
        case Tremove:
        case Tstat:
        case Twstat:
        case Rclone:
        case Rtunnel:
        case Rclunk:
        case Rremove:
        case Rstat:
        case Rwstat:
          printf("fid %d", f->r_fid);
                break;

        case Tclwalk:
          printf("fid %d ", f->r_fid);
          printf("newfid  %d ", f->r_newfid);
          printf("name %s", f->r_name);
                break;
/*
 */
        case Rnop:
        case Rosession:
        case Rflush:
        case Roattach:
        case Rauth:
                break;

        case Rerror:
          printf("ename %s", f->r_ename);
                break;

        case Rattach:
        case Rwalk:
        case Rclwalk:
        case Ropen:
        case Rcreate:
          printf("fid %d ", f->r_fid);
          printf("qid 0x%x 0x%x", f->r_qid.path, f->r_qid.vers);
                break;

        case Rread:
          printf("fid %d count %d ", f->r_fid, f->r_count);
          break;

        case Rwrite:
          printf("fid %d count %d", f->r_fid, f->r_count);
                break;
  }
}

int
u9p_s2m(struct u9fsreq *f, char *ap, int copydata)
{
        u_char *p;

        p = (u_char*)ap;
        H2NCHAR(f->r_type);
        H2NSHORT(f->r_tag);
        switch(f->r_type)
        {
        default:
                return 0;

        case Tosession:
        case Tnop:
                break;

        case Tsession:
                H2NSTRING(f->r_chal, sizeof(f->r_chal));
                break;

        case Tflush:
                H2NSHORT(f->r_oldtag);
                break;

        case Tattach:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_uname, sizeof(f->r_uname));
                H2NSTRING(f->r_aname, sizeof(f->r_aname));
                H2NSTRING(f->r_ticket, sizeof(f->r_ticket));
                H2NSTRING(f->r_auth, sizeof(f->r_auth));
                break;

        case Toattach:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_uname, sizeof(f->r_uname));
                H2NSTRING(f->r_aname, sizeof(f->r_aname));
                H2NSTRING(f->r_ticket, U9FS_NAMELEN);
                break;

        case Tauth:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_uname, sizeof(f->r_uname));
                H2NSTRING(f->r_ticket, 8+U9FS_NAMELEN);
                break;

        case Tclone:
                H2NSHORT(f->r_fid);
                H2NSHORT(f->r_newfid);
                break;

        case Twalk:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_name, sizeof(f->r_name));
                break;

        case Topen:
                H2NSHORT(f->r_fid);
                H2NCHAR(f->r_mode);
                break;

        case Tcreate:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_name, sizeof(f->r_name));
                H2NLONG(f->r_perm);
                H2NCHAR(f->r_mode);
                break;

        case Tread:
                H2NSHORT(f->r_fid);
                H2NQUAD(f->r_offset);
                H2NSHORT(f->r_count);
                break;

        case Twrite:
                H2NSHORT(f->r_fid);
                H2NQUAD(f->r_offset);
                H2NSHORT(f->r_count);
                p++;    /* pad(1) */
                if( copydata ) {
                  H2NSTRING(f->r_data, f->r_count);
                }
                break;

        case Ttunnel:
                H2NSHORT(f->r_fid);
                break;

        case Tclunk:
                H2NSHORT(f->r_fid);
                break;

        case Tremove:
                H2NSHORT(f->r_fid);
                break;

        case Tstat:
                H2NSHORT(f->r_fid);
                break;

        case Twstat:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_stat, sizeof(f->r_stat));
                break;

        case Tclwalk:
                H2NSHORT(f->r_fid);
                H2NSHORT(f->r_newfid);
                H2NSTRING(f->r_name, sizeof(f->r_name));
                break;
/*
 */
        case Rosession:
        case Rnop:
                break;

        case Rsession:
                H2NSTRING(f->r_chal, sizeof(f->r_chal));
                H2NSTRING(f->r_authid, sizeof(f->r_authid));
                H2NSTRING(f->r_authdom, sizeof(f->r_authdom));
                break;

        case Rerror:
                H2NSTRING(f->r_ename, sizeof(f->r_ename));
                break;

        case Rflush:
                break;

        case Rattach:
                H2NSHORT(f->r_fid);
                H2NLONG(f->r_qid.path);
                H2NLONG(f->r_qid.vers);
                H2NSTRING(f->r_rauth, sizeof(f->r_rauth));
                break;

        case Roattach:
                H2NSHORT(f->r_fid);
                H2NLONG(f->r_qid.path);
                H2NLONG(f->r_qid.vers);
                break;

        case Rauth:
                H2NSHORT(f->r_fid);
                H2NSTRING(f->r_ticket, 8+8+7+7);
                break;

        case Rclone:
                H2NSHORT(f->r_fid);
                break;

        case Rwalk:
        case Rclwalk:
                H2NSHORT(f->r_fid);
                H2NLONG(f->r_qid.path);
                H2NLONG(f->r_qid.vers);
                break;

        case Ropen:
                H2NSHORT(f->r_fid);
                H2NLONG(f->r_qid.path);
                H2NLONG(f->r_qid.vers);
                break;

        case Rcreate:
                H2NSHORT(f->r_fid);
                H2NLONG(f->r_qid.path);
                H2NLONG(f->r_qid.vers);
                break;

        case Rread:
                H2NSHORT(f->r_fid);
                H2NSHORT(f->r_count);
                p++;    /* pad(1) */
                if( copydata ) {
                  H2NSTRING(f->r_data, f->r_count);
                }
                break;

        case Rwrite:
                H2NSHORT(f->r_fid);
                H2NSHORT(f->r_count);
                break;

        case Rtunnel:
                H2NSHORT(f->r_fid);
                break;

        case Rclunk:
                H2NSHORT(f->r_fid);
                break;

        case Rremove:
                H2NSHORT(f->r_fid);
                break;

        case Rstat:
                H2NSHORT(f->r_fid);
                if( copydata )
                  H2NSTRING(f->r_stat, sizeof(f->r_stat));
                break;

        case Rwstat:
                H2NSHORT(f->r_fid);
                break;
        }
        return p - (u_char*)ap;
}

int
u9p_m2d(char *ap, struct u9fsdir *f)
{
        u_char *p;

        p = (u_char*)ap;
        N2HSTRING(f->dir_name, sizeof(f->dir_name));
        N2HSTRING(f->dir_uid, sizeof(f->dir_uid));
        N2HSTRING(f->dir_gid, sizeof(f->dir_gid));
        N2HLONG(f->dir_qid.path);
        N2HLONG(f->dir_qid.vers);
        N2HLONG(f->dir_mode);
        N2HLONG(f->dir_atime);
        N2HLONG(f->dir_mtime);
        N2HQUAD(f->dir_length);
        N2HSHORT(f->dir_type);
        N2HSHORT(f->dir_dev);
        return p - (u_char*)ap;
}

int
u9p_d2m(struct u9fsdir *f, char *ap)
{
        u_char *p;

        p = (u_char*)ap;
        H2NSTRING(f->dir_name, sizeof(f->dir_name));
        H2NSTRING(f->dir_uid, sizeof(f->dir_uid));
        H2NSTRING(f->dir_gid, sizeof(f->dir_gid));
        H2NLONG(f->dir_qid.path);
        H2NLONG(f->dir_qid.vers);
        H2NLONG(f->dir_mode);
        H2NLONG(f->dir_atime);
        H2NLONG(f->dir_mtime);
        H2NQUAD(f->dir_length);
        H2NSHORT(f->dir_type);
        H2NSHORT(f->dir_dev);
        return p - (u_char*)ap;
}

/* parse 9P types */
int u9p_type(char * t)
{
  int i;

  for(i = 0; i < sizeof(u9p_types)/sizeof(u9p_types[0]); i++) {
    if( strcmp(u9p_types[i], t) == 0 )
      return (i+Tnop);
  }
  return 0;
}

/* m is freed if shorter than s */
#if 1
#define U9P_PULLUP(m,s)  if( (*(m))->m_len < (s) && ((*(m)) = m_pullup((*(m)),(s))) == 0 ) return 1; p = mtod((*(m)), u_char *)
#else
#define U9P_PULLUP(m,s)  if( (*(m))->m_len < (s) && ((*(m)) = m_pullup((*(m)),(s))) == 0 ) panic("PULLUP"); p = mtod((*(m)), u_char *)
#endif

#define U9P_ADJ(m,s) (*(m))->m_len -= (s); (*(m))->m_data += (s)

u_short u9p_m_tag(struct mbuf ** m)
{
  char * p;
  u_short t;

  U9P_PULLUP(m,3);
  p = mtod(*m, char *);
  p++;
  N2HSHORT(t);

  return t;
}

int 
u9p_m_m2s(struct mbuf **m, struct u9fsreq *f)
{
  u_char *p;

  U9P_PULLUP(m,3);
  N2HCHAR(f->r_type);
  N2HSHORT(f->r_tag);
  U9P_ADJ(m, sizeof(f->r_type)+sizeof(f->r_tag));

  switch(f->r_type) {
  default:
    goto drop;

  case Tnop:
    break;

  case Tsession:
    U9P_PULLUP(m,sizeof(f->r_chal));
    N2HSTRING(f->r_chal, sizeof(f->r_chal));
    U9P_ADJ(m, sizeof(f->r_chal));
    break;

  case Tflush:
    U9P_PULLUP(m,sizeof(f->r_oldtag));
    N2HSHORT(f->r_oldtag);
    U9P_ADJ(m, f->r_oldtag);
    break;

  case Tattach:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_uname)+sizeof(f->r_aname));
    N2HSHORT(f->r_fid);
    N2HSTRING(f->r_uname, sizeof(f->r_uname));
    N2HSTRING(f->r_aname, sizeof(f->r_aname));
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_uname)+sizeof(f->r_aname));
    
    U9P_PULLUP(m, sizeof(f->r_ticket)+sizeof(f->r_auth));
    N2HSTRING(f->r_ticket, sizeof(f->r_ticket));
    N2HSTRING(f->r_auth, sizeof(f->r_auth));
    U9P_ADJ(m, sizeof(f->r_ticket)+sizeof(f->r_auth));
    break;

  case Tclone:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_newfid));
    N2HSHORT(f->r_fid);
    N2HSHORT(f->r_newfid);
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_newfid));
    break;

  case Twalk:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_name));
    N2HSHORT(f->r_fid);
    N2HSTRING(f->r_name, sizeof(f->r_name));
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_name));
    break;

  case Topen:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_mode));
    N2HSHORT(f->r_fid);
    N2HCHAR(f->r_mode);
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_mode));
    break;

  case Tcreate:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_name)
               +sizeof(f->r_perm)+sizeof(f->r_mode));
    N2HSHORT(f->r_fid);
    N2HSTRING(f->r_name, sizeof(f->r_name));
    N2HLONG(f->r_perm);
    N2HCHAR(f->r_mode);
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_name)
            +sizeof(f->r_perm)+sizeof(f->r_mode));
    break;

  case Tread:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count));
    N2HSHORT(f->r_fid);
    N2HQUAD(f->r_offset);
    N2HSHORT(f->r_count);
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count));
    break;

  case Twrite:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count));
    N2HSHORT(f->r_fid);
    N2HQUAD(f->r_offset);
    N2HSHORT(f->r_count);
    p++;        /* pad(1) */
    f->r_data = (char*)p; p += f->r_count;
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_offset)+sizeof(f->r_count)+1);
    break;

  case Tclunk:
  case Tremove:
  case Tstat: 
   U9P_PULLUP(m, sizeof(f->r_fid));
    N2HSHORT(f->r_fid);
    U9P_ADJ(m, sizeof(f->r_fid));
    break;

  case Twstat:
    U9P_PULLUP(m, sizeof(f->r_fid));
    N2HSHORT(f->r_fid);
    m_copydata(*m, sizeof(f->r_fid), sizeof(f->r_stat), f->r_stat);
    m_adj(*m, sizeof(f->r_fid)+sizeof(f->r_stat));
    break;

  case Tclwalk:
     U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_newfid)+sizeof(f->r_name));
     N2HSHORT(f->r_fid);
     N2HSHORT(f->r_newfid);
     N2HSTRING(f->r_name, sizeof(f->r_name));
     U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_newfid)+sizeof(f->r_name));
     break;
/*
 */
  case Rnop:
    break;

  case Rsession:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_authid)+sizeof(f->r_authdom));
    N2HSTRING(f->r_chal, sizeof(f->r_chal));
    N2HSTRING(f->r_authid, sizeof(f->r_authid));
    N2HSTRING(f->r_authdom, sizeof(f->r_authdom));
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_authid)+sizeof(f->r_authdom));
    break;

  case Rerror:
    U9P_PULLUP(m, sizeof(f->r_ename));
    N2HSTRING(f->r_ename, sizeof(f->r_ename));
    U9P_ADJ(m, sizeof(f->r_ename));
    break;

  case Rflush:
    break;

  case Rattach:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
               +sizeof(f->r_qid.vers)+sizeof(f->r_rauth));
    N2HSHORT(f->r_fid);
    N2HLONG(f->r_qid.path);
    N2HLONG(f->r_qid.vers);
    N2HSTRING(f->r_rauth, sizeof(f->r_rauth));
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
            +sizeof(f->r_qid.vers)+sizeof(f->r_rauth));
    break;

  case Rclone:
    U9P_PULLUP(m, sizeof(f->r_fid));
    N2HSHORT(f->r_fid);
    U9P_ADJ(m, sizeof(f->r_fid));
    break;

  case Rwalk:
  case Rclwalk:
  case Ropen:
  case Rcreate:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
               +sizeof(f->r_qid.vers));
    N2HSHORT(f->r_fid);
    N2HLONG(f->r_qid.path);
    N2HLONG(f->r_qid.vers);
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_qid.path)
            +sizeof(f->r_qid.vers));
    break;

  case Rread:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_count));
    N2HSHORT(f->r_fid);
    N2HSHORT(f->r_count);
    p++;        /* pad(1) */
    f->r_data = (char*)p; p += f->r_count;
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_count)+1);
    break;

  case Rwrite:
    U9P_PULLUP(m, sizeof(f->r_fid)+sizeof(f->r_count));
    N2HSHORT(f->r_fid);
    N2HSHORT(f->r_count);
    U9P_ADJ(m, sizeof(f->r_fid)+sizeof(f->r_count));
    break;

  case Rclunk:
  case Rremove:
  case Rwstat:
    U9P_PULLUP(m, sizeof(f->r_fid));
    N2HSHORT(f->r_fid);
    U9P_ADJ(m, sizeof(f->r_fid));
    break;

  case Rstat:
    U9P_PULLUP(m, sizeof(f->r_fid));
    N2HSHORT(f->r_fid);
    m_copydata(*m, sizeof(f->r_fid), sizeof(f->r_stat), f->r_stat);
    m_adj(*m, sizeof(f->r_fid)+sizeof(f->r_stat));
    break;
    
  }
  return 0;

 drop:
  m_freem(*m);
  return 1;
}

struct mbuf * 
u9p_m_s2m (struct u9fsreq *f)
{
  register struct mbuf * m;
  struct mbuf * m0;
  char * ap;
  int sz;
  
  /* we want one contiguous piece */
  if( f->r_type == Tattach || f->r_type == Rstat || f->r_type == Twstat )
    sz = 146; /* sizeof a Tattach */
  else
    sz = 87; /* sizeof a Tsession */
  
  MGETHDR(m, M_WAIT, MT_DATA);  
  if( sz > MHLEN )
    MCLGET(m, M_WAIT);
  m->m_len = 0;
  
  if ( M_TRAILINGSPACE(m) < sz )
    panic("u9p_m_s2m");
  
  ap = mtod(m, char *);
  m->m_len = u9p_s2m(f, ap, 0);
  m->m_pkthdr.len = m->m_len;
  
  /* append data mbufs  */
  switch ( f->r_type ) {
  default:
    break;
  case Twrite:
  case Rread:
    m0 = (struct mbuf *)f->r_data;
    m->m_next = m0;
    m->m_pkthdr.len += f->r_count;
    break;
  }

  return m;
}

int 
u9p_m_m2d (struct mbuf **m, struct u9fsdir *f)
{
  u_char *p;
  
  U9P_PULLUP(m, sizeof(f->dir_name)+sizeof(f->dir_uid)+sizeof(f->dir_gid));
  N2HSTRING(f->dir_name, sizeof(f->dir_name));
  N2HSTRING(f->dir_uid, sizeof(f->dir_uid));
  N2HSTRING(f->dir_gid, sizeof(f->dir_gid));
  U9P_ADJ(m, sizeof(f->dir_name)+sizeof(f->dir_uid)+sizeof(f->dir_gid));

  U9P_PULLUP(m, sizeof(f->dir_qid)+sizeof(f->dir_mode)
             +sizeof(f->dir_atime)+sizeof(f->dir_mtime)
             +sizeof(f->dir_length)+sizeof(f->dir_type)+sizeof(f->dir_dev));
  N2HLONG(f->dir_qid.path);
  N2HLONG(f->dir_qid.vers);
  N2HLONG(f->dir_mode);
  N2HLONG(f->dir_atime);
  N2HLONG(f->dir_mtime);
  N2HQUAD(f->dir_length);
  N2HSHORT(f->dir_type);
  N2HSHORT(f->dir_dev);
  U9P_ADJ(m, sizeof(f->dir_qid)+sizeof(f->dir_mode)
             +sizeof(f->dir_atime)+sizeof(f->dir_mtime)
             +sizeof(f->dir_length)+sizeof(f->dir_type)+sizeof(f->dir_dev));

  return 0;
}

struct mbuf * u9p_m_d2m (struct u9fsdir *f)
{
  char * ap;
  struct mbuf * m;
  MGET(m, M_WAIT, MT_DATA);
  MCLGET(m, M_WAIT);
  m->m_len = 0;

  if ( M_TRAILINGSPACE(m) < sizeof(struct u9fsdir) )
    panic("u9p_m_d2m");

  ap = mtod(m, char *);
  m->m_len = u9p_d2m(f, ap);  

  return m;
}