M alphapc/devfloppy.c => alphapc/devfloppy.c +1 -1
@@ 911,7 911,7 @@ floppyformat(FDrive *dp, char *params)
/*
* set the type
*/
- if(getfields(params, f, 3, 1, " ") > 1){
+ if(tokenize(params, f, 3) > 1){
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
dp->t = t;
M alphapc/devvga.c => alphapc/devvga.c +1 -1
@@ 173,7 173,7 @@ vgactl(char* a)
extern VGAcur *vgacur[];
Rectangle r;
- n = getfields(a, field, nelem(field), 1, " ");
+ n = tokenize(a, field, nelem(field));
if(n < 1)
error(Ebadarg);
M bitsy/devpenmouse.c => bitsy/devpenmouse.c +1 -1
@@ 341,7 341,7 @@ penmousewrite(Chan *c, void *va, long n, vlong)
buf[n-1] = 0;
else
buf[n] = 0;
- nf = getfields(buf, field, 5, 1, " ");
+ nf = tokenize(buf, field, 5);
if(strcmp(field[0], "swap") == 0){
if(mouseswap)
setbuttonmap("123");
M bitsy/devuda1341.c => bitsy/devuda1341.c +1 -1
@@ 1270,7 1270,7 @@ audiowrite(Chan *c, void *vp, long n, vlong)
memmove(buf, p, n);
buf[n] = '\0';
- nf = getfields(buf, field, Ncmd, 1, " \t\n");
+ nf = tokenize(buf, field, Ncmd);
for(i = 0; i < nf; i++){
/*
* a number is volume
M boot/boot.c => boot/boot.c +1 -1
@@ 232,7 232,7 @@ rootserver(char *arg)
outin(prompt, reply, sizeof(reply));
mp = findmethod(reply);
if(mp){
- bargc = getfields(reply, bargv, Nbarg-1, 1, " ");
+ bargc = tokenize(reply, bargv, Nbarg-1);
cp = strchr(reply, '!');
if(cp)
strcpy(sys, cp+1);
M boot/bootcache.c => boot/bootcache.c +1 -1
@@ 17,7 17,7 @@ cache(int fd)
readfile("#e/cfs", buf, sizeof(buf));
if(*buf){
- argc = getfields(buf, argv, 4, 1, " ");
+ argc = tokenize(buf, argv, 4);
for(i = 0; i < argc; i++){
if(strcmp(argv[i], "off") == 0)
return fd;
M ip/arp.c => ip/arp.c +1 -1
@@ 271,7 271,7 @@ arpwrite(Fs *fs, char *s, int len)
if(len > 0 && buf[len-1] == '\n')
buf[len-1] = 0;
- n = getfields(buf, f, 4, 1, " ");
+ n = tokenize(buf, f, 4);
if(strcmp(f[0], "flush") == 0){
qlock(arp);
for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
M ip/icmp.c => ip/icmp.c +25 -3
@@ 28,6 28,7 @@ typedef struct Icmp {
enum { /* Packet Types */
EchoReply = 0,
+ UnreachableV6 = 1,
Unreachable = 3,
SrcQuench = 4,
Redirect = 5,
@@ 51,6 52,7 @@ enum
char *icmpnames[Maxtype+1] =
{
+[UnreachableV6] "UnreachableV6",
[EchoReply] "EchoReply",
[Unreachable] "Unreachable",
[SrcQuench] "SrcQuench",
@@ 293,7 295,7 @@ static char *unreachcode[] =
[1] "host unreachable",
[2] "protocol unreachable",
[3] "port unreachable",
-[4] "fragmentation needed and DF set",
+[4] "unfragmentable",
[5] "source route failed",
};
@@ 307,6 309,9 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
char *msg;
char m2[128];
Icmppriv *ipriv;
+ int code;
+ ushort x;
+ uchar dst[IPaddrlen];
ipriv = icmp->priv;
@@ 344,10 349,23 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
ipoput(icmp->f, r, 0, MAXTTL, DFLTTOS);
break;
case Unreachable:
- if(p->code > 5 || p->code < 0)
+ code = p->code;
+ switch(code){
+ default:
msg = unreachcode[1];
- else
+ break;
+ case 5:
+ x = nhgets(p->seq);
+ msg = unreachcode[p->code];
+ break;
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
msg = unreachcode[p->code];
+ break;
+ }
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
if(blocklen(bp) < MinAdvise){
@@ 355,6 373,10 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
goto raise;
}
p = (Icmp *)bp->rp;
+ if(code == 5){
+ v4tov6(dst, p->dst);
+ update_mtucache(dst, x);
+ }
pr = Fsrcvpcolx(icmp->f, p->proto);
if(pr != nil && pr->advise != nil) {
(*pr->advise)(pr, bp, msg);
M ip/ip.c => ip/ip.c +83 -2
@@ 432,6 432,20 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
freeblist(bp);
return;
}
+
+ /* reassemble if the interface expects it */
+ if(r->ifc->reassemble){
+ frag = nhgets(h->frag);
+ if(frag) {
+ h->tos = 0;
+ if(frag & IP_MF)
+ h->tos = 1;
+ bp = ipreassemble(ip, frag, bp, h);
+ if(bp == nil)
+ return;
+ h = (Iphdr *)(bp->rp);
+ }
+ }
ip->stats[ForwDatagrams]++;
ipoput(f, bp, 1, h->ttl - 1, h->tos);
@@ 439,8 453,7 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
return;
}
-
-
+ /* reassemble */
frag = nhgets(h->frag);
if(frag) {
h->tos = 0;
@@ 716,3 729,71 @@ ipcsum(uchar *addr)
return (sum^0xffff);
}
+
+enum
+{
+ Nmtucache= 128,
+};
+
+typedef struct MTUcache MTUcache;
+
+struct MTUcache
+{
+ uchar ip[IPaddrlen];
+ ulong mtu;
+ ulong ms;
+};
+
+static struct {
+ Lock;
+ MTUcache c[Nmtucache];
+} mc;
+
+void
+update_mtucache(uchar *ip, ulong mtu)
+{
+ MTUcache *oldest, *p;
+
+ if(mtu < 512)
+ return;
+
+ lock(&mc);
+ oldest = mc.c;
+ for(p = mc.c; p < &mc.c[Nmtucache]; p++){
+ if(ipcmp(ip, p->ip) == 0){
+ p->mtu = mtu;
+ p->ms = msec;
+ break;
+ }
+ if(p->ms < oldest->ms)
+ oldest = p;
+ }
+ if(p == &mc.c[Nmtucache]){
+ ipmove(oldest->ip, ip);
+ oldest->mtu = mtu;
+ oldest->ms = msec;
+ }
+ unlock(&mc);
+}
+
+ulong
+restrict_mtu(uchar *ip, ulong mtu)
+{
+ MTUcache *p;
+
+ lock(&mc);
+ for(p = mc.c; p < &mc.c[Nmtucache]; p++){
+ if(p->ms + 1000*10*60 < msec){
+ memset(p->ip, 0, sizeof(p->ip));
+ p->ms = 0;
+ }
+ if(ipcmp(ip, p->ip) == 0){
+ if(p->mtu < mtu)
+ mtu = p->mtu;
+ break;
+ }
+ }
+ unlock(&mc);
+
+ return mtu;
+}
M ip/ip.h => ip/ip.h +3 -0
@@ 174,6 174,7 @@ struct Ipifc
int maxmtu; /* Maximum transfer unit */
int minmtu; /* Minumum tranfer unit */
void *arg; /* medium specific */
+ int reassemble; /* reassemble IP packets before forwarding */
/* these are used so that we can unbind on the fly */
Lock idlock;
@@ 543,6 544,8 @@ extern int ipstats(Fs*, char*, int);
extern ushort ptclbsum(uchar*, int);
extern ushort ptclcsum(Block*, int, int);
extern void ip_init(Fs*);
+extern void update_mtucache(uchar*, ulong);
+extern ulong restrict_mtu(uchar*, ulong);
/*
* bootp.c
M ip/ipifc.c => ip/ipifc.c +6 -1
@@ 173,6 173,7 @@ ipifcunbind(Ipifc *ifc)
(*ifc->m->unbind)(ifc);
memset(ifc->dev, 0, sizeof(ifc->dev));
ifc->arg = nil;
+ ifc->reassemble = 0;
/* hangup queues to stop queuing of packets */
qhangup(ifc->conv->rq, "unbind");
@@ 288,6 289,7 @@ ipifccreate(Conv *c)
ifc->conv = c;
ifc->unbinding = 0;
ifc->m = nil;
+ ifc->reassemble = 0;
}
/*
@@ 636,7 638,10 @@ ipifcctl(Conv* c, char**argv, int argc)
return ipifcleavemulti(ifc, argv, argc);
else if(strcmp(argv[0], "mtu") == 0)
return ipifcsetmtu(ifc, argv, argc);
- else if(strcmp(argv[0], "iprouting") == 0){
+ else if(strcmp(argv[0], "reassemble") == 0){
+ ifc->reassemble = 1;
+ return nil;
+ } else if(strcmp(argv[0], "iprouting") == 0){
i = 1;
if(argc > 1)
i = atoi(argv[1]);
M ip/netlog.c => ip/netlog.c +1 -1
@@ 167,7 167,7 @@ netlogctl(Fs *f, char* s, int len)
if(len > 0 && buf[len-1] == '\n')
buf[len-1] = 0;
- n = getfields(buf, fields, 10, 1, " ");
+ n = tokenize(buf, fields, 10);
if(n < 2)
return Ebadnetctl;
M ip/tcp.c => ip/tcp.c +39 -18
@@ 649,7 649,7 @@ tcpmtu(Conv *s)
mtu = ifc->maxmtu - ifc->m->hsize - (TCP_PKT + TCP_HDRSIZE);
if(mtu < 4)
mtu = DEF_MSS;
- return mtu;
+ return restrict_mtu(s->raddr, mtu);
}
void
@@ 2183,24 2183,45 @@ tcpadvise(Proto *tcp, Block *bp, char *msg)
/* Look for a connection */
qlock(tcp);
- for(p = tcp->conv; *p; p++) {
- s = *p;
- tcb = (Tcpctl*)s->ptcl;
- if(s->rport == pdest)
- if(s->lport == psource)
- if(tcb->state != Closed)
- if(ipcmp(s->raddr, dest) == 0)
- if(ipcmp(s->laddr, source) == 0){
- qlock(s);
- qunlock(tcp);
- switch(tcb->state){
- case Syn_sent:
- localclose(s, msg);
- break;
+ if(strcmp(msg, "unfragmentable") == 0){
+ for(p = tcp->conv; *p; p++) {
+ s = *p;
+ tcb = (Tcpctl*)s->ptcl;
+ if(tcb->state != Closed)
+ if(ipcmp(s->raddr, dest) == 0)
+ if(ipcmp(s->laddr, source) == 0){
+ qlock(s);
+ qunlock(tcp);
+ switch(tcb->state){
+ case Syn_sent:
+ localclose(s, msg);
+ break;
+ }
+ qunlock(s);
+ freeblist(bp);
+ return;
+ }
+ }
+ } else {
+ for(p = tcp->conv; *p; p++) {
+ s = *p;
+ tcb = (Tcpctl*)s->ptcl;
+ if(s->rport == pdest)
+ if(s->lport == psource)
+ if(tcb->state != Closed)
+ if(ipcmp(s->raddr, dest) == 0)
+ if(ipcmp(s->laddr, source) == 0){
+ qlock(s);
+ qunlock(tcp);
+ switch(tcb->state){
+ case Syn_sent:
+ localclose(s, msg);
+ break;
+ }
+ qunlock(s);
+ freeblist(bp);
+ return;
}
- qunlock(s);
- freeblist(bp);
- return;
}
}
qunlock(tcp);
M pc/devfloppy.c => pc/devfloppy.c +1 -1
@@ 904,7 904,7 @@ floppyformat(FDrive *dp, char *params)
/*
* set the type
*/
- if(getfields(params, f, 3, 1, " ") > 1){
+ if(tokenize(params, f, 3) > 1){
for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
dp->t = t;
M pc/devpccard.c => pc/devpccard.c +1 -1
@@ 1326,7 1326,7 @@ pccardwrite(Chan *c, void *v, long n, vlong)
memmove(buf, v, n);
buf[n] = '\0';
- nf = getfields(buf, field, Ncmd, 1, " \t\n");
+ nf = tokenize(buf, field, Ncmd);
for (i = 0; i != nf; i++) {
if (!strcmp(field[i], "down")) {
M pc/devusb.c => pc/devusb.c +2 -2
@@ 2014,7 2014,7 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
n = sizeof(cmd)-1;
memmove(cmd, a, n);
cmd[n] = 0;
- nf = getfields(cmd, fields, nelem(fields), 0, " \t\n");
+ nf = tokenize(cmd, fields, nelem(fields));
if(nf < 2)
error(Ebadarg);
id = strtol(fields[1], nil, 0);
@@ 2038,7 2038,7 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
n = sizeof(cmd)-1;
memmove(cmd, a, n);
cmd[n] = 0;
- nf = getfields(cmd, fields, nelem(fields), 0, " \t\n");
+ nf = tokenize(cmd, fields, nelem(fields));
if(nf > 1 && strcmp(fields[0], "speed") == 0){
d->ls = strtoul(fields[1], nil, 0) == 0;
} else if(nf > 3 && strcmp(fields[0], "class") == 0){
M pc/devvga.c => pc/devvga.c +1 -1
@@ 184,7 184,7 @@ vgactl(char* a)
extern VGAdev *vgadev[];
extern VGAcur *vgacur[];
- n = getfields(a, field, nelem(field), 1, " \t\n");
+ n = tokenize(a, field, nelem(field));
if(n < 1)
error(Ebadarg);
M pc/vgamach64xx.c => pc/vgamach64xx.c +1 -1
@@ 1174,7 1174,7 @@ mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int)
if (!mach64type->m64_vtgt)
error(Enodev);
- nfields = getfields(a, field, nelem(field), 1, "\t\n\r ");
+ nfields = tokenize(a, field, nelem(field));
if (nfields < 1)
error(Ebadarg);
M port/devaudio.c => port/devaudio.c +1 -1
@@ 1090,7 1090,7 @@ audiowrite(Chan *c, void *vp, long n, vlong)
memmove(buf, a, n);
buf[n] = '\0';
- nf = getfields(buf, field, Ncmd, 1, " \t\n");
+ nf = tokenize(buf, field, Ncmd);
for(i = 0; i < nf; i++){
/*
* a number is volume
M port/devdraw.c => port/devdraw.c +1 -1
@@ 1159,7 1159,7 @@ drawwrite(Chan *c, void *a, long n, vlong)
a = (char*)a + i;
m -= i;
*q = 0;
- if(getfields(buf, fields, nelem(fields), 1, " ") != 4)
+ if(tokenize(buf, fields, nelem(fields)) != 4)
error(Ebadarg);
i = strtoul(fields[0], 0, 0);
red = strtoul(fields[1], 0, 0);
M port/devmouse.c => port/devmouse.c +1 -1
@@ 343,7 343,7 @@ mousewrite(Chan *c, void *va, long n, vlong)
buf[n-1] = 0;
else
buf[n] = 0;
- nf = getfields(buf, field, 3, 1, " ");
+ nf = tokenize(buf, field, 3);
if(strcmp(field[0], "swap") == 0){
if(mouseswap)
setbuttonmap("123");
M port/devproc.c => port/devproc.c +9 -6
@@ 240,11 240,14 @@ procopen(Chan *c, int omode)
error(Eperm);
break;
+ case Qmem:
+ if(p->privatemem)
+ error(Eperm);
+ /* fall through */
case Qargs:
case Qctl:
case Qnote:
case Qnoteid:
- case Qmem:
case Qstatus:
case Qwait:
case Qregs:
@@ 507,17 510,14 @@ procread(Chan *c, void *va, long n, vlong off)
|| (offset >= USTKTOP-USTKSIZE && offset < USTKTOP))
return procctlmemio(p, offset, n, va, 1);
- /* Protect crypt key memory */
- if(offset+n >= palloc.cmembase && offset < palloc.cmemtop)
- error(Eperm);
-
- /* validate physical kernel addresses */
+ /* validate kernel addresses */
if(offset < (ulong)end) {
if(offset+n > (ulong)end)
n = (ulong)end - offset;
memmove(a, (char*)offset, n);
return n;
}
+ /* conf.base* and conf.npage* are set by xinit to refer to kernel allocation, not user pages */
if(offset >= conf.base0 && offset < conf.npage0){
if(offset+n > conf.npage0)
n = conf.npage0 - offset;
@@ 1070,6 1070,9 @@ procctlreq(Proc *p, char *va, int n)
error(Ebadctl);
procctlclosefiles(p, 0, atoi(buf+6));
}else
+ if(strncmp(buf, "private", 7) == 0)
+ p->privatemem = 1;
+ else
if(strncmp(buf, "pri", 3) == 0) {
if(n < 4)
error(Ebadctl);
M port/devsd.c => port/devsd.c +2 -2
@@ 205,7 205,7 @@ sdinitpart(SDunit* unit)
for(p = getconf(buf); p != nil; p = q){
if(q = strchr(p, '/'))
*q++ = '\0';
- nf = getfields(p, f, nelem(f), 1, " \t\r");
+ nf = tokenize(p, f, nelem(f));
if(nf < 3)
continue;
@@ 1100,7 1100,7 @@ sdwrite(Chan *c, void *a, long n, vlong off)
cd.o_spec = '\0';
memset(&cd.o_cf, 0, sizeof(DevConf));
- nf = getfields(buf, field, Ncmd, 1, " \t\n");
+ nf = tokenize(buf, field, Ncmd);
for (i = 0; i < nf; i++) {
char *opt = field[i++];
if (i >= nf)
M port/devuart.c => port/devuart.c +1 -1
@@ 318,7 318,7 @@ uartctl(Uart *p, char *cmd)
char *f[16];
int i, n, nf;
- nf = getfields(cmd, f, nelem(f), 1, " \t\n");
+ nf = tokenize(cmd, f, nelem(f));
for(i = 0; i < nf; i++){
if(strncmp(f[i], "break", 5) == 0){
(*p->phys->dobreak)(p, 0);
M port/parse.c => port/parse.c +34 -7
@@ 6,6 6,31 @@
#include "../port/error.h"
/*
+ * Generous estimate of number of fields, including terminal nil pointer
+ */
+static int
+ncmdfield(char *p, int n)
+{
+ int white, nwhite;
+ char *ep;
+ int nf;
+
+ if(p == nil)
+ return 1;
+
+ nf = 0;
+ ep = p+n;
+ white = 1; /* first text will start field */
+ while(p < ep){
+ nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
+ if(white && !nwhite) /* beginning of field */
+ nf++;
+ white = nwhite;
+ }
+ return nf+1; /* +1 for nil */
+}
+
+/*
* parse a command written to a device
*/
Cmdbuf*
@@ 15,13 40,13 @@ parsecmd(char *p, int n)
int nf;
char *sp;
- /* count fields and allocate a big enough cmdbuf */
- for(nf = 1, sp = p; sp != nil && *sp; nf++, sp = strchr(sp+1, ' '))
- ;
- sp = smalloc(sizeof(*cb) + n + 1 + nf*sizeof(char*));
+ nf = ncmdfield(p, n);
+
+ /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
+ sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
cb = (Cmdbuf*)sp;
- cb->buf = sp+sizeof(*cb);
- cb->f = (char**)(cb->buf + n + 1);
+ cb->f = (char**)(&cb[1]);
+ cb->buf = (char*)(&cb->f[nf]);
if(up!=nil && waserror()){
free(cb);
@@ 36,7 61,9 @@ parsecmd(char *p, int n)
n--;
cb->buf[n] = '\0';
- cb->nf = getfields(cb->buf, cb->f, nf, 1, " ");
+ cb->nf = tokenize(cb->buf, cb->f, nf-1);
+ cb->f[cb->nf] = nil;
+
return cb;
}
M port/portdat.h => port/portdat.h +6 -2
@@ 470,8 470,6 @@ struct Palloc
Lock hashlock;
Rendez r; /* Sleep for free mem */
QLock pwait; /* Queue of procs waiting for memory */
- ulong cmembase; /* Key memory */
- ulong cmemtop;
};
struct Waitq
@@ 582,6 580,7 @@ struct Proc
QLock debug; /* to access debugging elements of User */
Proc *pdbg; /* the debugging process */
ulong procmode; /* proc device file mode */
+ ulong privatemem; /* proc does not let anyone read mem */
int hang; /* hang at next exec for debug */
int procctl; /* Control for /proc debugging */
ulong pc; /* DEBUG only */
@@ 710,6 709,11 @@ struct Logflag {
int mask;
};
+enum
+{
+ NCMDFIELD = 128
+};
+
struct Cmdbuf
{
char *buf;
M port/proc.c => port/proc.c +1 -0
@@ 338,6 338,7 @@ newproc(void)
p->movetime = 0;
p->wired = 0;
p->ureg = 0;
+ p->privatemem = 0;
p->errstr = p->errbuf0;
p->syserrstr = p->errbuf1;
p->errbuf0[0] = '\0';
M port/sysproc.c => port/sysproc.c +1 -0
@@ 471,6 471,7 @@ sysexec(ulong *arg)
up->nnote = 0;
up->notify = 0;
up->notified = 0;
+ up->privatemem = 0;
procsetup(up);
qunlock(&up->debug);
if(up->hang)