1 #include "dat.h"
2 #include "fns.h"
3 #include "error.h"
4 #include "ip.h"
5
6 enum
7 {
8 Qtopdir = 1, /* top level directory */
9 Qtopbase,
10 Qarp= Qtopbase,
11 /* Qiproute, */
12 /* Qipselftab, */
13 Qndb,
14
15 Qprotodir, /* directory for a protocol */
16 Qprotobase,
17 Qclone= Qprotobase,
18 Qstats,
19
20 Qconvdir, /* directory for a conversation */
21 Qconvbase,
22 Qctl= Qconvbase,
23 Qdata,
24 Qlisten,
25 Qlocal,
26 Qremote,
27 Qstatus,
28
29 Logtype= 5,
30 Masktype= (1<<Logtype)-1,
31 Logconv= 12,
32 Maskconv= (1<<Logconv)-1,
33 Shiftconv= Logtype,
34 Logproto= 8,
35 Maskproto= (1<<Logproto)-1,
36 Shiftproto= Logtype + Logconv,
37
38 Statelen = 256,
39
40 Nfs= 1,
41
42 Maxproto = 4,
43 MAXCONV = 4096
44 };
45 #define TYPE(x) ( ((ulong)(x).path) & Masktype )
46 #define CONV(x) ( (((ulong)(x).path) >> Shiftconv) & Maskconv )
47 #define PROTO(x) ( (((ulong)(x).path) >> Shiftproto) & Maskproto )
48 #define QID(p, c, y) ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )
49
50 enum
51 {
52 Idle= 0,
53 Announcing= 1,
54 Announced= 2,
55 Connecting= 3,
56 Connected= 4,
57 Hungup= 5,
58 };
59
60 struct Conv
61 {
62 QLock l;
63
64 int x; /* conversation index */
65 Proto* p;
66
67 uchar laddr[IPaddrlen]; /* local IP address */
68 uchar raddr[IPaddrlen]; /* remote IP address */
69 int restricted; /* remote port is restricted */
70 ushort lport; /* local port number */
71 ushort rport; /* remote port number */
72
73 char* owner; /* protections */
74 int perm;
75 int inuse; /* opens of listen/data/ctl */
76 int state;
77
78 /* udp specific */
79 int headers; /* data src/dst headers in udp */
80
81 char cerr[ERRMAX];
82
83 QLock listenq;
84
85 void* ptcl; /* protocol specific stuff */
86
87 int sfd;
88 QLock wlock; /* prevent data from being split by concurrent writes */
89 };
90
91 struct Proto
92 {
93 QLock l;
94 int x;
95 int ipproto;
96 int stype;
97 char* name;
98 int maxconv;
99 Fs* f; /* file system this proto is part of */
100 Conv** conv; /* array of conversations */
101 int pctlsize; /* size of per protocol ctl block */
102 int nc; /* number of conversations */
103 int ac;
104 Qid qid; /* qid for protocol directory */
105 /* port allocation isn't done here when hosted */
106
107 void* priv;
108 };
109
110 /*
111 * one per IP protocol stack
112 */
113 struct Fs
114 {
115 RWlock l;
116 int dev;
117
118 int np;
119 Proto* p[Maxproto+1]; /* list of supported protocols */
120 Proto* t2p[256]; /* vector of all protocols */
121
122 char ndb[1024]; /* an ndb entry for this interface */
123 int ndbvers;
124 long ndbmtime;
125 };
126
127 static Fs *ipfs[Nfs]; /* attached fs's */
128 static char network[] = "network";
129 static char* ipstates[] = {
130 "Closed", /* Idle */
131 "Announcing",
132 "Announced",
133 "Connecting",
134 "Established", /* Connected */
135 "Closed", /* Hungup */
136 };
137
138 static Conv* protoclone(Proto*, char*, int);
139 static Conv* newconv(Proto*, Conv **);
140 static void setladdr(Conv*);
141
142 static int
ip3gen(Chan * c,int i,Dir * dp)143 ip3gen(Chan *c, int i, Dir *dp)
144 {
145 Qid q;
146 Conv *cv;
147 char *p;
148
149 cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
150 if(cv->owner == nil)
151 kstrdup(&cv->owner, eve);
152 mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
153
154 switch(i) {
155 default:
156 return -1;
157 case Qctl:
158 devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
159 return 1;
160 case Qdata:
161 devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
162 return 1;
163 case Qlisten:
164 devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
165 return 1;
166 case Qlocal:
167 p = "local";
168 break;
169 case Qremote:
170 p = "remote";
171 break;
172 case Qstatus:
173 p = "status";
174 break;
175 }
176 devdir(c, q, p, 0, cv->owner, 0444, dp);
177 return 1;
178 }
179
180 static int
ip2gen(Chan * c,int i,Dir * dp)181 ip2gen(Chan *c, int i, Dir *dp)
182 {
183 Qid q;
184
185 switch(i) {
186 case Qclone:
187 mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
188 devdir(c, q, "clone", 0, network, 0666, dp);
189 return 1;
190 case Qstats:
191 mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
192 devdir(c, q, "stats", 0, network, 0444, dp);
193 return 1;
194 }
195 return -1;
196 }
197
198 static int
ip1gen(Chan * c,int i,Dir * dp)199 ip1gen(Chan *c, int i, Dir *dp)
200 {
201 Qid q;
202 char *p;
203 int prot;
204 int len = 0;
205 Fs *f;
206 extern ulong kerndate;
207
208 f = ipfs[c->dev];
209
210 prot = 0664;
211 mkqid(&q, QID(0, 0, i), 0, QTFILE);
212 switch(i) {
213 default:
214 return -1;
215 case Qarp:
216 p = "arp";
217 break;
218 case Qndb:
219 p = "ndb";
220 len = strlen(ipfs[c->dev]->ndb);
221 break;
222 /* case Qiproute:
223 p = "iproute";
224 break;
225 case Qipselftab:
226 p = "ipselftab";
227 prot = 0444;
228 break;
229 case Qiprouter:
230 p = "iprouter";
231 break;
232 case Qlog:
233 p = "log";
234 break;
235 */
236 }
237 devdir(c, q, p, len, network, prot, dp);
238 if(i == Qndb && f->ndbmtime > kerndate)
239 dp->mtime = f->ndbmtime;
240 return 1;
241 }
242
243 static int
ipgen(Chan * c,char * name,Dirtab * tab,int x,int s,Dir * dp)244 ipgen(Chan *c, char *name, Dirtab *tab, int x, int s, Dir *dp)
245 {
246 Qid q;
247 Conv *cv;
248 Fs *f;
249
250 USED(name);
251 USED(tab);
252 USED(x);
253 f = ipfs[c->dev];
254
255 switch(TYPE(c->qid)) {
256 case Qtopdir:
257 if(s == DEVDOTDOT){
258 mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
259 sprint(up->genbuf, "#I%lud", c->dev);
260 devdir(c, q, up->genbuf, 0, network, 0555, dp);
261 return 1;
262 }
263 if(s < f->np) {
264 /* if(f->p[s]->connect == nil)
265 return 0; /* protocol with no user interface */
266 mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
267 devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
268 return 1;
269 }
270 s -= f->np;
271 return ip1gen(c, s+Qtopbase, dp);
272 case Qarp:
273 case Qndb:
274 /* case Qiproute:
275 case Qiprouter:
276 case Qipselftab: */
277 return ip1gen(c, TYPE(c->qid), dp);
278 case Qprotodir:
279 if(s == DEVDOTDOT){
280 mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
281 sprint(up->genbuf, "#I%lud", c->dev);
282 devdir(c, q, up->genbuf, 0, network, 0555, dp);
283 return 1;
284 }
285 if(s < f->p[PROTO(c->qid)]->ac) {
286 cv = f->p[PROTO(c->qid)]->conv[s];
287 sprint(up->genbuf, "%d", s);
288 mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
289 devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
290 return 1;
291 }
292 s -= f->p[PROTO(c->qid)]->ac;
293 return ip2gen(c, s+Qprotobase, dp);
294 case Qclone:
295 case Qstats:
296 return ip2gen(c, TYPE(c->qid), dp);
297 case Qconvdir:
298 if(s == DEVDOTDOT){
299 s = PROTO(c->qid);
300 mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
301 devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
302 return 1;
303 }
304 return ip3gen(c, s+Qconvbase, dp);
305 case Qctl:
306 case Qdata:
307 case Qlisten:
308 case Qlocal:
309 case Qremote:
310 case Qstatus:
311 return ip3gen(c, TYPE(c->qid), dp);
312 }
313 return -1;
314 }
315
316 static void
newproto(char * name,int type,int maxconv)317 newproto(char *name, int type, int maxconv)
318 {
319 Proto *p;
320
321 p = smalloc(sizeof(*p));
322 p->name = name;
323 p->stype = type;
324 p->ipproto = type+1; /* temporary */
325 p->nc = maxconv;
326 if(Fsproto(ipfs[0], p))
327 panic("can't newproto %s", name);
328 }
329
330 void
ipinit(void)331 ipinit(void)
332 {
333 ipfs[0] = malloc(sizeof(Fs));
334 if(ipfs[0] == nil)
335 panic("no memory for IP stack");
336
337 newproto("udp", S_UDP, 64);
338 newproto("tcp", S_TCP, 2048);
339
340 fmtinstall('i', eipfmt);
341 fmtinstall('I', eipfmt);
342 fmtinstall('E', eipfmt);
343 fmtinstall('V', eipfmt);
344 fmtinstall('M', eipfmt);
345 }
346
347 Chan *
ipattach(char * spec)348 ipattach(char *spec)
349 {
350 Chan *c;
351
352 if(atoi(spec) != 0)
353 error("bad specification");
354
355 c = devattach('I', spec);
356 mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
357 c->dev = 0;
358
359 return c;
360 }
361
362 static Walkqid*
ipwalk(Chan * c,Chan * nc,char ** name,int nname)363 ipwalk(Chan* c, Chan *nc, char **name, int nname)
364 {
365 return devwalk(c, nc, name, nname, nil, 0, ipgen);
366 }
367
368 static int
ipstat(Chan * c,uchar * db,int n)369 ipstat(Chan *c, uchar *db, int n)
370 {
371 return devstat(c, db, n, 0, 0, ipgen);
372 }
373
374 static int m2p[] = {
375 4,
376 2,
377 6,
378 };
379
380 static Chan *
ipopen(Chan * c,int omode)381 ipopen(Chan *c, int omode)
382 {
383 Conv *cv, *nc;
384 Proto *p;
385 uchar raddr[IPaddrlen];
386 ushort rport;
387 int perm, sfd;
388 Fs *f;
389
390 perm = m2p[omode&3];
391
392 f = ipfs[c->dev];
393
394 switch(TYPE(c->qid)) {
395 default:
396 break;
397 case Qtopdir:
398 case Qprotodir:
399 case Qconvdir:
400 case Qstatus:
401 case Qremote:
402 case Qlocal:
403 case Qstats:
404 /* case Qipselftab: */
405 if(omode != OREAD)
406 error(Eperm);
407 break;
408 case Qndb:
409 if(omode & (OWRITE|OTRUNC) && !iseve())
410 error(Eperm);
411 if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){
412 f->ndb[0] = 0;
413 f->ndbvers++;
414 }
415 break;
416 case Qclone:
417 p = f->p[PROTO(c->qid)];
418 cv = protoclone(p, up->env->user, -1);
419 if(cv == 0)
420 error(Enodev);
421 mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
422 break;
423 case Qdata:
424 case Qctl:
425 p = f->p[PROTO(c->qid)];
426 qlock(&p->l);
427 cv = p->conv[CONV(c->qid)];
428 qlock(&cv->l);
429 if(waserror()){
430 qunlock(&cv->l);
431 qunlock(&p->l);
432 nexterror();
433 }
434 if((perm & (cv->perm>>6)) != perm) {
435 if(strcmp(up->env->user, cv->owner) != 0)
436 error(Eperm);
437 if((perm & cv->perm) != perm)
438 error(Eperm);
439 }
440 cv->inuse++;
441 if(cv->inuse == 1) {
442 kstrdup(&cv->owner, up->env->user);
443 cv->perm = 0660;
444 if(cv->sfd < 0)
445 cv->sfd = so_socket(p->stype);
446 }
447 poperror();
448 qunlock(&cv->l);
449 qunlock(&p->l);
450 break;
451 case Qlisten:
452 p = f->p[PROTO(c->qid)];
453 cv = p->conv[CONV(c->qid)];
454 if((perm & (cv->perm>>6)) != perm){
455 if(strcmp(up->env->user, cv->owner) != 0)
456 error(Eperm);
457 if((perm & cv->perm) != perm)
458 error(Eperm);
459 }
460
461 if(cv->state != Announced)
462 error("not announced");
463
464 qlock(&cv->listenq);
465 if(waserror()){
466 qunlock(&cv->listenq);
467 nexterror();
468 }
469
470 sfd = so_accept(cv->sfd, raddr, &rport);
471
472 nc = protoclone(p, up->env->user, sfd);
473 if(nc == 0) {
474 so_close(sfd);
475 error(Enodev);
476 }
477 memmove(nc->raddr, raddr, IPaddrlen);
478 nc->rport = rport;
479 setladdr(nc);
480 nc->state = Connected;
481 mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
482
483 poperror();
484 qunlock(&cv->listenq);
485 break;
486 }
487 c->mode = openmode(omode);
488 c->flag |= COPEN;
489 c->offset = 0;
490 return c;
491 }
492
493 static void
closeconv(Conv * cv)494 closeconv(Conv *cv)
495 {
496 int fd;
497
498 qlock(&cv->l);
499
500 if(--cv->inuse > 0) {
501 qunlock(&cv->l);
502 return;
503 }
504
505 if(waserror()){
506 qunlock(&cv->l);
507 return;
508 }
509 kstrdup(&cv->owner, network);
510 cv->perm = 0660;
511 /* cv->p->close(cv); */
512 cv->state = Idle;
513 cv->restricted = 0;
514 fd = cv->sfd;
515 cv->sfd = -1;
516 if(fd >= 0)
517 so_close(fd);
518 poperror();
519 qunlock(&cv->l);
520 }
521
522 static void
ipclose(Chan * c)523 ipclose(Chan *c)
524 {
525 Fs *f;
526
527 f = ipfs[c->dev];
528 switch(TYPE(c->qid)) {
529 case Qdata:
530 case Qctl:
531 if(c->flag & COPEN)
532 closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
533 break;
534 }
535 }
536
537 static long
ipread(Chan * ch,void * a,long n,vlong off)538 ipread(Chan *ch, void *a, long n, vlong off)
539 {
540 int r;
541 Conv *c;
542 Proto *x;
543 char *p, *s;
544 Fs *f;
545 ulong offset = off;
546
547 f = ipfs[ch->dev];
548
549 p = a;
550 switch(TYPE(ch->qid)) {
551 default:
552 error(Eperm);
553 case Qprotodir:
554 case Qtopdir:
555 case Qconvdir:
556 return devdirread(ch, a, n, 0, 0, ipgen);
557 case Qarp:
558 error(Eperm); /* TO DO */
559 case Qndb:
560 return readstr(off, a, n, f->ndb);
561 case Qctl:
562 sprint(up->genbuf, "%lud", CONV(ch->qid));
563 return readstr(offset, p, n, up->genbuf);
564 case Qremote:
565 x = f->p[PROTO(ch->qid)];
566 c = x->conv[CONV(ch->qid)];
567 sprint(up->genbuf, "%I!%d\n", c->raddr, c->rport);
568 return readstr(offset, p, n, up->genbuf);
569 case Qlocal:
570 x = f->p[PROTO(ch->qid)];
571 c = x->conv[CONV(ch->qid)];
572 sprint(up->genbuf, "%I!%d\n", c->laddr, c->lport);
573 return readstr(offset, p, n, up->genbuf);
574 case Qstatus:
575 x = f->p[PROTO(ch->qid)];
576 c = x->conv[CONV(ch->qid)];
577 s = smalloc(Statelen);
578 if(waserror()){
579 free(s);
580 nexterror();
581 }
582 snprint(s, Statelen, "%s\n", ipstates[c->state]);
583 n = readstr(offset, p, n, s);
584 poperror();
585 free(s);
586 return n;
587 case Qdata:
588 x = f->p[PROTO(ch->qid)];
589 c = x->conv[CONV(ch->qid)];
590 if(c->sfd < 0)
591 error(Ehungup);
592 if(c->headers) {
593 if(n < c->headers)
594 error(Ebadarg);
595 p = a;
596 r = so_recv(c->sfd, p + c->headers, n - c->headers, p, c->headers);
597 if(r >= 0)
598 r += c->headers;
599 } else
600 r = so_recv(c->sfd, a, n, nil, 0);
601 if(r < 0)
602 oserror();
603 return r;
604 case Qstats:
605 error("stats not implemented");
606 return n;
607 }
608 }
609
610 static void
setladdr(Conv * c)611 setladdr(Conv *c)
612 {
613 /* TO DO: this can't be right for hosts with several addresses before connect/accept */
614 so_getsockname(c->sfd, c->laddr, &c->lport);
615 }
616
617 /*
618 * pick a local port and set it
619 */
620 static void
setlport(Conv * c)621 setlport(Conv *c)
622 {
623 uchar laddr[IPaddrlen];
624 ushort p;
625
626 so_bind(c->sfd, c->restricted, c->laddr, c->lport);
627 if(c->lport == 0 || ipcmp(c->laddr, IPnoaddr) == 0){
628 so_getsockname(c->sfd, laddr, &p);
629 if(c->lport == 0)
630 c->lport = p;
631 if(ipcmp(c->laddr, IPnoaddr) == 0)
632 memmove(c->laddr, laddr, sizeof laddr);
633 }
634 }
635
636 static int
portno(char * p)637 portno(char *p)
638 {
639 long n;
640 char *e;
641
642 n = strtoul(p, &e, 0);
643 if(p == e)
644 error("non-numeric port number");
645 return n;
646 }
647
648 /*
649 * set a local address and port from a string of the form
650 * [address!]port[!r]
651 */
652 static void
setladdrport(Conv * c,char * str,int announcing)653 setladdrport(Conv *c, char *str, int announcing)
654 {
655 char *p;
656 int lport;
657
658 /*
659 * ignore restricted part if it exists. it's
660 * meaningless on local ports.
661 */
662 p = strchr(str, '!');
663 if(p != nil){
664 *p++ = 0;
665 if(strcmp(p, "r") == 0)
666 p = nil;
667 }
668
669 c->lport = 0;
670 if(p == nil){
671 if(announcing)
672 ipmove(c->laddr, IPnoaddr);
673 else if(0)
674 setladdr(c);
675 p = str;
676 } else {
677 if(strcmp(str, "*") == 0)
678 ipmove(c->laddr, IPnoaddr);
679 else if(parseip(c->laddr, str) == 0)
680 error("invalid IP address");
681 }
682
683 if(announcing && strcmp(p, "*") == 0){
684 if(!iseve())
685 error(Eperm);
686 c->lport = 0;
687 setlport(c);
688 return;
689 }
690
691 lport = portno(p);
692 if(lport <= 0)
693 c->lport = 0;
694 else
695 c->lport = lport;
696
697 setlport(c);
698 }
699
700 static char*
setraddrport(Conv * c,char * str)701 setraddrport(Conv *c, char *str)
702 {
703 char *p;
704
705 p = strchr(str, '!');
706 if(p == nil)
707 return "malformed address";
708 *p++ = 0;
709 if(parseip(c->raddr, str) == 0)
710 return "invalid IP address";
711 c->rport = portno(p);
712 p = strchr(p, '!');
713 if(p){
714 if(strstr(p, "!r") != nil)
715 c->restricted = 1;
716 }
717 return nil;
718 }
719
720 static void
connectctlmsg(Proto * x,Conv * c,Cmdbuf * cb)721 connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
722 {
723 char *p;
724
725 USED(x);
726 if(c->state != Idle)
727 error(Econinuse);
728 c->state = Connecting;
729 c->cerr[0] = '\0';
730 switch(cb->nf) {
731 default:
732 error("bad args to connect");
733 case 2:
734 p = setraddrport(c, cb->f[1]);
735 if(p != nil)
736 error(p);
737 break;
738 case 3:
739 p = setraddrport(c, cb->f[1]);
740 if(p != nil)
741 error(p);
742 c->lport = portno(cb->f[2]);
743 setlport(c);
744 break;
745 }
746 qunlock(&c->l);
747 if(waserror()){
748 qlock(&c->l);
749 c->state = Connected; /* sic */
750 nexterror();
751 }
752 /* p = x->connect(c, cb->f, cb->nf); */
753 so_connect(c->sfd, c->raddr, c->rport);
754 qlock(&c->l);
755 poperror();
756 setladdr(c);
757 c->state = Connected;
758 }
759
760 static void
announcectlmsg(Proto * x,Conv * c,Cmdbuf * cb)761 announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
762 {
763 if(c->state != Idle)
764 error(Econinuse);
765 c->state = Announcing;
766 c->cerr[0] = '\0';
767 ipmove(c->raddr, IPnoaddr);
768 c->rport = 0;
769 switch(cb->nf){
770 default:
771 error("bad args to announce");
772 case 2:
773 setladdrport(c, cb->f[1], 1);
774 break;
775 }
776 USED(x);
777 /* p = x->announce(c, cb->f, cb->nf); */
778 if(c->p->stype != S_UDP){
779 qunlock(&c->l);
780 if(waserror()){
781 c->state = Announced; /* sic */
782 qlock(&c->l);
783 nexterror();
784 }
785 so_listen(c->sfd);
786 qlock(&c->l);
787 poperror();
788 }
789 c->state = Announced;
790 }
791
792 static void
bindctlmsg(Proto * x,Conv * c,Cmdbuf * cb)793 bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
794 {
795 USED(x);
796 switch(cb->nf){
797 default:
798 error("bad args to bind");
799 case 2:
800 setladdrport(c, cb->f[1], 0);
801 break;
802 }
803 }
804
805 static long
ipwrite(Chan * ch,void * a,long n,vlong off)806 ipwrite(Chan *ch, void *a, long n, vlong off)
807 {
808 Conv *c;
809 Proto *x;
810 char *p;
811 Cmdbuf *cb;
812 Fs *f;
813
814 f = ipfs[ch->dev];
815
816 switch(TYPE(ch->qid)) {
817 default:
818 error(Eperm);
819 case Qdata:
820 x = f->p[PROTO(ch->qid)];
821 c = x->conv[CONV(ch->qid)];
822 if(c->sfd < 0)
823 error(Ehungup);
824 qlock(&c->wlock);
825 if(waserror()){
826 qunlock(&c->wlock);
827 nexterror();
828 }
829 if(c->headers) {
830 if(n < c->headers)
831 error(Eshort);
832 p = a;
833 n = so_send(c->sfd, p + c->headers, n - c->headers, p, c->headers);
834 if(n >= 0)
835 n += c->headers;
836 } else
837 n = so_send(c->sfd, a, n, nil, 0);
838 poperror();
839 qunlock(&c->wlock);
840 if(n < 0)
841 oserror();
842 break;
843 case Qarp:
844 return arpwrite(a, n);
845 case Qndb:
846 if(off > strlen(f->ndb))
847 error(Eio);
848 if(off+n >= sizeof(f->ndb)-1)
849 error(Eio);
850 memmove(f->ndb+off, a, n);
851 f->ndb[off+n] = 0;
852 f->ndbvers++;
853 f->ndbmtime = seconds();
854 break;
855 case Qctl:
856 x = f->p[PROTO(ch->qid)];
857 c = x->conv[CONV(ch->qid)];
858 cb = parsecmd(a, n);
859 qlock(&c->l);
860 if(waserror()){
861 qunlock(&c->l);
862 free(cb);
863 nexterror();
864 }
865 if(cb->nf < 1)
866 error("short control request");
867 if(strcmp(cb->f[0], "connect") == 0)
868 connectctlmsg(x, c, cb);
869 else if(strcmp(cb->f[0], "announce") == 0)
870 announcectlmsg(x, c, cb);
871 else if(strcmp(cb->f[0], "bind") == 0)
872 bindctlmsg(x, c, cb);
873 else if(strcmp(cb->f[0], "ttl") == 0){
874 /* ignored */
875 } else if(strcmp(cb->f[0], "tos") == 0){
876 /* ignored */
877 } else if(strcmp(cb->f[0], "ignoreadvice") == 0){
878 /* ignored */
879 } else if(strcmp(cb->f[0], "headers4") == 0){
880 if(c->p->stype != S_UDP)
881 error(Enoctl);
882 c->headers = OUdphdrlenv4;
883 } else if(strcmp(cb->f[0], "oldheaders") == 0){
884 if(c->p->stype != S_UDP)
885 error(Enoctl);
886 c->headers = OUdphdrlen;
887 } else if(strcmp(cb->f[0], "headers") == 0){
888 if(c->p->stype != S_UDP)
889 error(Enoctl);
890 c->headers = Udphdrlen;
891 } else if(strcmp(cb->f[0], "hangup") == 0){
892 if(c->p->stype != S_TCP)
893 error(Enoctl);
894 qunlock(&c->l);
895 if(waserror()){
896 qlock(&c->l);
897 nexterror();
898 }
899 /* TO DO: check fd status if socket close/hangup interrupted */
900 if(c->sfd >= 0 && so_hangup(c->sfd, 1) < 0)
901 oserror();
902 qlock(&c->l);
903 poperror();
904 c->sfd = -1;
905 c->state = Hungup;
906 } else if(strcmp(cb->f[0], "keepalive") == 0){
907 if(c->p->stype != S_TCP)
908 error(Enoctl);
909 if(c->sfd < 0)
910 error("not connected");
911 so_keepalive(c->sfd, cb->nf>1? atoi(cb->f[1]): 0);
912 } else
913 error(Enoctl);
914 poperror();
915 qunlock(&c->l);
916 free(cb);
917 break;
918 }
919 return n;
920 }
921
922 static int
ipwstat(Chan * c,uchar * dp,int n)923 ipwstat(Chan *c, uchar *dp, int n)
924 {
925 Dir *d;
926 Conv *cv;
927 Proto *p;
928 Fs *f;
929
930 f = ipfs[c->dev];
931 switch(TYPE(c->qid)) {
932 default:
933 error(Eperm);
934 break;
935 case Qctl:
936 case Qdata:
937 break;
938 }
939
940 d = smalloc(sizeof(*d)+n);
941 if(waserror()){
942 free(d);
943 nexterror();
944 }
945 n = convM2D(dp, n, d, (char*)&d[1]);
946 if(n == 0)
947 error(Eshortstat);
948 p = f->p[PROTO(c->qid)];
949 cv = p->conv[CONV(c->qid)];
950 if(!iseve() && strcmp(up->env->user, cv->owner) != 0)
951 error(Eperm);
952 if(!emptystr(d->uid))
953 kstrdup(&cv->owner, d->uid);
954 if(d->mode != ~0UL)
955 cv->perm = d->mode & 0777;
956 poperror();
957 free(d);
958 return n;
959 }
960
961 static Conv*
protoclone(Proto * p,char * user,int nfd)962 protoclone(Proto *p, char *user, int nfd)
963 {
964 Conv *c, **pp, **ep, **np;
965 int maxconv;
966
967 c = 0;
968 qlock(&p->l);
969 if(waserror()) {
970 qunlock(&p->l);
971 nexterror();
972 }
973 ep = &p->conv[p->nc];
974 for(pp = p->conv; pp < ep; pp++) {
975 c = *pp;
976 if(c == 0) {
977 c = newconv(p, pp);
978 break;
979 }
980 if(canqlock(&c->l)){
981 if(c->inuse == 0)
982 break;
983 qunlock(&c->l);
984 }
985 }
986 if(pp >= ep) {
987 if(p->nc >= MAXCONV) {
988 qunlock(&p->l);
989 poperror();
990 return 0;
991 }
992 maxconv = 2 * p->nc;
993 if(maxconv > MAXCONV)
994 maxconv = MAXCONV;
995 np = realloc(p->conv, sizeof(Conv*) * maxconv);
996 if(np == nil)
997 error(Enomem);
998 p->conv = np;
999 pp = &p->conv[p->nc];
1000 memset(pp, 0, sizeof(Conv*)*(maxconv - p->nc));
1001 p->nc = maxconv;
1002 c = newconv(p, pp);
1003 }
1004
1005 c->inuse = 1;
1006 kstrdup(&c->owner, user);
1007 c->perm = 0660;
1008 c->state = Idle;
1009 ipmove(c->laddr, IPnoaddr);
1010 ipmove(c->raddr, IPnoaddr);
1011 c->lport = 0;
1012 c->rport = 0;
1013 c->restricted = 0;
1014 c->headers = 0;
1015 c->sfd = nfd;
1016 if(nfd == -1)
1017 c->sfd = so_socket(p->stype);
1018
1019 qunlock(&c->l);
1020 qunlock(&p->l);
1021 poperror();
1022 return c;
1023 }
1024
1025 static Conv*
newconv(Proto * p,Conv ** pp)1026 newconv(Proto *p, Conv **pp)
1027 {
1028 Conv *c;
1029
1030 *pp = c = malloc(sizeof(Conv));
1031 if(c == 0)
1032 error(Enomem);
1033 qlock(&c->l);
1034 c->inuse = 1;
1035 c->p = p;
1036 c->x = pp - p->conv;
1037 p->ac++;
1038 return c;
1039 }
1040
1041 int
arpwrite(char * s,int len)1042 arpwrite(char *s, int len)
1043 {
1044 int n;
1045 char *f[4], buf[256];
1046
1047 if(len >= sizeof(buf))
1048 len = sizeof(buf)-1;
1049 memmove(buf, s, len);
1050 buf[len] = 0;
1051 if(len > 0 && buf[len-1] == '\n')
1052 buf[len-1] = 0;
1053
1054 n = getfields(buf, f, 4, 1, " ");
1055 if(strcmp(f[0], "add") == 0) {
1056 if(n == 3) {
1057 arpadd(f[1], f[2], n);
1058 return len;
1059 }
1060 }
1061 error("bad arp request");
1062
1063 return len;
1064 }
1065
1066 Dev ipdevtab = {
1067 'I',
1068 "ip",
1069
1070 ipinit,
1071 ipattach,
1072 ipwalk,
1073 ipstat,
1074 ipopen,
1075 devcreate,
1076 ipclose,
1077 ipread,
1078 devbread,
1079 ipwrite,
1080 devbwrite,
1081 devremove,
1082 ipwstat
1083 };
1084
1085 int
Fsproto(Fs * f,Proto * p)1086 Fsproto(Fs *f, Proto *p)
1087 {
1088 if(f->np >= Maxproto)
1089 return -1;
1090
1091 p->f = f;
1092
1093 if(p->ipproto > 0){
1094 if(f->t2p[p->ipproto] != nil)
1095 return -1;
1096 f->t2p[p->ipproto] = p;
1097 }
1098
1099 p->qid.type = QTDIR;
1100 p->qid.path = QID(f->np, 0, Qprotodir);
1101 p->conv = malloc(sizeof(Conv*)*(p->nc+1));
1102 if(p->conv == nil)
1103 panic("Fsproto");
1104
1105 p->x = f->np;
1106 f->p[f->np++] = p;
1107
1108 return 0;
1109 }
1110
1111 /*
1112 * return true if this protocol is
1113 * built in
1114 */
1115 int
Fsbuiltinproto(Fs * f,uchar proto)1116 Fsbuiltinproto(Fs* f, uchar proto)
1117 {
1118 return f->t2p[proto] != nil;
1119 }
1120