#include <linux/module.h>
#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
#include "protocol.h"
static int
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
+#ifdef CONFIG_NET_9P_DEBUG
+void
+p9pdu_dump(int way, struct p9_fcall *pdu)
+{
+ int i, n;
+ u8 *data = pdu->sdata;
+ int datalen = pdu->size;
+ char buf[255];
+ int buflen = 255;
+
+ i = n = 0;
+ if (datalen > (buflen-16))
+ datalen = buflen-16;
+ while (i < datalen) {
+ n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
+ if (i%4 == 3)
+ n += scnprintf(buf + n, buflen - n, " ");
+ if (i%32 == 31)
+ n += scnprintf(buf + n, buflen - n, "\n");
+
+ i++;
+ }
+ n += scnprintf(buf + n, buflen - n, "\n");
+
+ if (way)
+ P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
+ else
+ P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
+}
+#else
+void
+p9pdu_dump(int way, struct p9_fcall *pdu)
+{
+}
+#endif
+EXPORT_SYMBOL(p9pdu_dump);
+
void p9stat_free(struct p9_wstat *stbuf)
{
kfree(stbuf->name);
return size - len;
}
+static size_t
+pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
+{
+ size_t len = MIN(pdu->capacity - pdu->size, size);
+ int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
+ if (err)
+ printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
+
+ pdu->size += len;
+ return size - len;
+}
+
/*
b - int8_t
w - int16_t
}
break;
case 's':{
- char **ptr = va_arg(ap, char **);
+ char **sptr = va_arg(ap, char **);
int16_t len;
int size;
size = MAX(len, 0);
- *ptr = kmalloc(size + 1, GFP_KERNEL);
- if (*ptr == NULL) {
+ *sptr = kmalloc(size + 1, GFP_KERNEL);
+ if (*sptr == NULL) {
errcode = -EFAULT;
break;
}
- if (pdu_read(pdu, *ptr, size)) {
+ if (pdu_read(pdu, *sptr, size)) {
errcode = -EFAULT;
- kfree(*ptr);
- *ptr = NULL;
+ kfree(*sptr);
+ *sptr = NULL;
} else
- (*ptr)[size] = 0;
+ (*sptr)[size] = 0;
}
break;
case 'Q':{
struct p9_wstat *stbuf =
va_arg(ap, struct p9_wstat *);
- stbuf->extension = NULL;
+ memset(stbuf, 0, sizeof(struct p9_wstat));
stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
- -1;
-
+ -1;
errcode =
p9pdu_readf(pdu, optional,
"wwdQdddqssss?sddd",
}
break;
case 's':{
- const char *ptr = va_arg(ap, const char *);
+ const char *sptr = va_arg(ap, const char *);
int16_t len = 0;
-
- if (ptr)
- len = MIN(strlen(ptr), USHORT_MAX);
+ if (sptr)
+ len = MIN(strlen(sptr), USHORT_MAX);
errcode = p9pdu_writef(pdu, optional, "w", len);
- if (!errcode && pdu_write(pdu, ptr, len))
+ if (!errcode && pdu_write(pdu, sptr, len))
errcode = -EFAULT;
}
break;
p9pdu_writef(pdu, optional,
"wwdQdddqssss?sddd",
stbuf->size, stbuf->type,
- stbuf->dev, stbuf->qid,
+ stbuf->dev, &stbuf->qid,
stbuf->mode, stbuf->atime,
stbuf->mtime, stbuf->length,
stbuf->name, stbuf->uid,
errcode = -EFAULT;
}
break;
+ case 'U':{
+ int32_t count = va_arg(ap, int32_t);
+ const char __user *udata =
+ va_arg(ap, const void __user *);
+ errcode =
+ p9pdu_writef(pdu, optional, "d", count);
+ if (!errcode && pdu_write_u(pdu, udata, count))
+ errcode = -EFAULT;
+ }
+ break;
case 'T':{
int16_t nwname = va_arg(ap, int);
const char **wnames = va_arg(ap, const char **);
return ret;
}
+
+int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
+{
+ struct p9_fcall fake_pdu;
+ int ret;
+
+ fake_pdu.size = len;
+ fake_pdu.capacity = len;
+ fake_pdu.sdata = buf;
+ fake_pdu.offset = 0;
+
+ ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
+ if (ret) {
+ P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
+ p9pdu_dump(1, &fake_pdu);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(p9stat_read);
+
+int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
+{
+ return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
+}
+
+int p9pdu_finalize(struct p9_fcall *pdu)
+{
+ int size = pdu->size;
+ int err;
+
+ pdu->size = 0;
+ err = p9pdu_writef(pdu, 0, "d", size);
+ pdu->size = size;
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
+ p9pdu_dump(0, pdu);
+#endif
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
+ pdu->id, pdu->tag);
+
+ return err;
+}
+
+void p9pdu_reset(struct p9_fcall *pdu)
+{
+ pdu->offset = 0;
+ pdu->size = 0;
+}