blob: e47eb8804474f907dae63eaddbf2b11afb27e449 [file] [log] [blame]
#include <vfs.h>
#include <kfs.h>
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
enum {
Nlog = 16 * 1024,
};
/*
* action log
*/
struct netlog {
spinlock_t rwlock;
int opens;
char *buf;
char *end;
char *rptr;
int len;
int logmask; /* mask of things to debug */
uint8_t iponly[IPaddrlen]; /* ip address to print debugging for */
int iponlyset;
qlock_t qlock;
struct rendez rv;
};
struct netlogflag {
char *name;
int mask;
};
static struct netlogflag flags[] = {
{"ppp", Logppp,},
{"ip", Logip,},
{"fs", Logfs,},
{"tcp", Logtcp,},
{"icmp", Logicmp,},
{"udp", Logudp,},
{"compress", Logcompress,},
{"gre", Loggre,},
{"tcpwin", Logtcp | Logtcpwin,},
{"tcprxmt", Logtcp | Logtcprxmt,},
{"udpmsg", Logudp | Logudpmsg,},
{"ipmsg", Logip | Logipmsg,},
{"esp", Logesp,},
{NULL, 0,},
};
char Ebadnetctl[] = "too few arguments for netlog control message";
enum {
CMset,
CMclear,
CMonly,
};
static
struct cmdtab routecmd[] = {
{CMset, "set", 0},
{CMclear, "clear", 0},
{CMonly, "only", 0},
};
void netloginit(struct fs *f)
{
f->alog = kzmalloc(sizeof(struct netlog), 0);
rendez_init(&f->alog->rv);
qlock_init(&f->alog->qlock);
}
void netlogopen(struct fs *f)
{
ERRSTACK(2);
spin_lock(&f->alog->rwlock);
if (waserror()) {
spin_unlock(&f->alog->rwlock);
nexterror();
}
if (f->alog->opens == 0) {
if (f->alog->buf == NULL)
f->alog->buf = kzmalloc(Nlog, 0);
if (f->alog->buf == NULL)
error(Enomem);
f->alog->rptr = f->alog->buf;
f->alog->end = f->alog->buf + Nlog;
}
f->alog->opens++;
spin_unlock(&f->alog->rwlock);
poperror();
}
void netlogclose(struct fs *f)
{
ERRSTACK(2);
spin_lock(&f->alog->rwlock);
if (waserror()) {
spin_unlock(&f->alog->rwlock);
nexterror();
}
f->alog->opens--;
if (f->alog->opens == 0) {
kfree(f->alog->buf);
f->alog->buf = NULL;
}
spin_unlock(&f->alog->rwlock);
poperror();
}
static int netlogready(void *a)
{
struct fs *f = a;
return f->alog->len;
}
long netlogread(struct fs *f, void *a, uint32_t unused_len, long n)
{
ERRSTACK(2);
int i, d;
char *p, *rptr;
qlock(&f->alog->qlock);
if (waserror()) {
qunlock(&f->alog->qlock);
nexterror();
}
for (;;) {
spin_lock(&f->alog->rwlock);
if (f->alog->len) {
if (n > f->alog->len)
n = f->alog->len;
d = 0;
rptr = f->alog->rptr;
f->alog->rptr += n;
if (f->alog->rptr >= f->alog->end) {
d = f->alog->rptr - f->alog->end;
f->alog->rptr = f->alog->buf + d;
}
f->alog->len -= n;
spin_unlock(&f->alog->rwlock);
i = n - d;
p = a;
memmove(p, rptr, i);
memmove(p + i, f->alog->buf, d);
break;
} else
spin_unlock(&f->alog->rwlock);
rendez_sleep(&f->alog->rv, netlogready, f);
}
qunlock(&f->alog->qlock);
poperror();
return n;
}
void netlogctl(struct fs *f, char *s, int n)
{
ERRSTACK(2);
int i, set = 0;
struct netlogflag *fp;
struct cmdbuf *cb;
struct cmdtab *ct;
cb = parsecmd(s, n);
if (waserror()) {
kfree(cb);
nexterror();
}
if (cb->nf < 2)
error(Ebadnetctl);
ct = lookupcmd(cb, routecmd, ARRAY_SIZE(routecmd));
switch (ct->index) {
case CMset:
set = 1;
break;
case CMclear:
set = 0;
break;
case CMonly:
parseip(f->alog->iponly, cb->f[1]);
if (ipcmp(f->alog->iponly, IPnoaddr) == 0)
f->alog->iponlyset = 0;
else
f->alog->iponlyset = 1;
kfree(cb);
poperror();
return;
default:
cmderror(cb, "unknown netlog control message");
}
for (i = 1; i < cb->nf; i++) {
for (fp = flags; fp->name; fp++)
if (strcmp(fp->name, cb->f[i]) == 0)
break;
if (fp->name == NULL)
continue;
if (set)
f->alog->logmask |= fp->mask;
else
f->alog->logmask &= ~fp->mask;
}
kfree(cb);
poperror();
}
void netlog(struct fs *f, int mask, char *fmt, ...)
{
char buf[256], *t, *fp;
int i, n;
va_list arg;
if (!(f->alog->logmask & mask))
return;
if (f->alog->opens == 0)
return;
va_start(arg, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, arg);
va_end(arg);
spin_lock(&f->alog->rwlock);
i = f->alog->len + n - Nlog;
if (i > 0) {
f->alog->len -= i;
f->alog->rptr += i;
if (f->alog->rptr >= f->alog->end)
f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
}
t = f->alog->rptr + f->alog->len;
fp = buf;
f->alog->len += n;
while (n-- > 0) {
if (t >= f->alog->end)
t = f->alog->buf + (t - f->alog->end);
*t++ = *fp++;
}
spin_unlock(&f->alog->rwlock);
rendez_wakeup(&f->alog->rv);
}