The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ip/devip.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 #include        "../ip/ip.h"
    8 
    9 enum
   10 {
   11         Qtopdir=        1,              /* top level directory */
   12         Qtopbase,
   13         Qarp=           Qtopbase,
   14         Qbootp,
   15         Qndb,
   16         Qiproute,
   17         Qipselftab,
   18         Qlog,
   19 
   20         Qprotodir,                      /* directory for a protocol */
   21         Qprotobase,
   22         Qclone=         Qprotobase,
   23         Qstats,
   24 
   25         Qconvdir,                       /* directory for a conversation */
   26         Qconvbase,
   27         Qctl=           Qconvbase,
   28         Qdata,
   29         Qerr,
   30         Qlisten,
   31         Qlocal,
   32         Qremote,
   33         Qstatus,
   34         Qsnoop,
   35 
   36         Logtype=        5,
   37         Masktype=       (1<<Logtype)-1,
   38         Logconv=        12,
   39         Maskconv=       (1<<Logconv)-1,
   40         Shiftconv=      Logtype,
   41         Logproto=       8,
   42         Maskproto=      (1<<Logproto)-1,
   43         Shiftproto=     Logtype + Logconv,
   44 
   45         Nfs=            128,
   46 };
   47 #define TYPE(x)         ( ((ulong)(x).path) & Masktype )
   48 #define CONV(x)         ( (((ulong)(x).path) >> Shiftconv) & Maskconv )
   49 #define PROTO(x)        ( (((ulong)(x).path) >> Shiftproto) & Maskproto )
   50 #define QID(p, c, y)    ( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )
   51 
   52 static char network[] = "network";
   53 
   54 QLock   fslock;
   55 Fs      *ipfs[Nfs];     /* attached fs's */
   56 Queue   *qlog;
   57 
   58 extern  void nullmediumlink(void);
   59 extern  void pktmediumlink(void);
   60         long ndbwrite(Fs *f, char *a, ulong off, int n);
   61 
   62 static int
   63 ip3gen(Chan *c, int i, Dir *dp)
   64 {
   65         Qid q;
   66         Conv *cv;
   67         char *p;
   68 
   69         cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
   70         if(cv->owner == nil)
   71                 kstrdup(&cv->owner, eve);
   72         mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
   73 
   74         switch(i) {
   75         default:
   76                 return -1;
   77         case Qctl:
   78                 devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
   79                 return 1;
   80         case Qdata:
   81                 devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp);
   82                 return 1;
   83         case Qerr:
   84                 devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp);
   85                 return 1;
   86         case Qlisten:
   87                 devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
   88                 return 1;
   89         case Qlocal:
   90                 p = "local";
   91                 break;
   92         case Qremote:
   93                 p = "remote";
   94                 break;
   95         case Qsnoop:
   96                 if(strcmp(cv->p->name, "ipifc") != 0)
   97                         return -1;
   98                 devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);
   99                 return 1;
  100         case Qstatus:
  101                 p = "status";
  102                 break;
  103         }
  104         devdir(c, q, p, 0, cv->owner, 0444, dp);
  105         return 1;
  106 }
  107 
  108 static int
  109 ip2gen(Chan *c, int i, Dir *dp)
  110 {
  111         Qid q;
  112 
  113         switch(i) {
  114         case Qclone:
  115                 mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
  116                 devdir(c, q, "clone", 0, network, 0666, dp);
  117                 return 1;
  118         case Qstats:
  119                 mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
  120                 devdir(c, q, "stats", 0, network, 0444, dp);
  121                 return 1;
  122         }
  123         return -1;
  124 }
  125 
  126 static int
  127 ip1gen(Chan *c, int i, Dir *dp)
  128 {
  129         Qid q;
  130         char *p;
  131         int prot;
  132         int len = 0;
  133         Fs *f;
  134         extern ulong    kerndate;
  135 
  136         f = ipfs[c->dev];
  137 
  138         prot = 0666;
  139         mkqid(&q, QID(0, 0, i), 0, QTFILE);
  140         switch(i) {
  141         default:
  142                 return -1;
  143         case Qarp:
  144                 p = "arp";
  145                 prot = 0664;
  146                 break;
  147         case Qbootp:
  148                 p = "bootp";
  149                 break;
  150         case Qndb:
  151                 p = "ndb";
  152                 len = strlen(f->ndb);
  153                 q.vers = f->ndbvers;
  154                 break;
  155         case Qiproute:
  156                 p = "iproute";
  157                 prot = 0664;
  158                 break;
  159         case Qipselftab:
  160                 p = "ipselftab";
  161                 prot = 0444;
  162                 break;
  163         case Qlog:
  164                 p = "log";
  165                 break;
  166         }
  167         devdir(c, q, p, len, network, prot, dp);
  168         if(i == Qndb && f->ndbmtime > kerndate)
  169                 dp->mtime = f->ndbmtime;
  170         return 1;
  171 }
  172 
  173 static int
  174 ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
  175 {
  176         Qid q;
  177         Conv *cv;
  178         Fs *f;
  179 
  180         f = ipfs[c->dev];
  181 
  182         switch(TYPE(c->qid)) {
  183         case Qtopdir:
  184                 if(s == DEVDOTDOT){
  185                         mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
  186                         sprint(up->genbuf, "#I%lud", c->dev);
  187                         devdir(c, q, up->genbuf, 0, network, 0555, dp);
  188                         return 1;
  189                 }
  190                 if(s < f->np) {
  191                         if(f->p[s]->connect == nil)
  192                                 return 0;       /* protocol with no user interface */
  193                         mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
  194                         devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
  195                         return 1;
  196                 }
  197                 s -= f->np;
  198                 return ip1gen(c, s+Qtopbase, dp);
  199         case Qarp:
  200         case Qbootp:
  201         case Qndb:
  202         case Qlog:
  203         case Qiproute:
  204         case Qipselftab:
  205                 return ip1gen(c, TYPE(c->qid), dp);
  206         case Qprotodir:
  207                 if(s == DEVDOTDOT){
  208                         mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
  209                         sprint(up->genbuf, "#I%lud", c->dev);
  210                         devdir(c, q, up->genbuf, 0, network, 0555, dp);
  211                         return 1;
  212                 }
  213                 if(s < f->p[PROTO(c->qid)]->ac) {
  214                         cv = f->p[PROTO(c->qid)]->conv[s];
  215                         sprint(up->genbuf, "%d", s);
  216                         mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
  217                         devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
  218                         return 1;
  219                 }
  220                 s -= f->p[PROTO(c->qid)]->ac;
  221                 return ip2gen(c, s+Qprotobase, dp);
  222         case Qclone:
  223         case Qstats:
  224                 return ip2gen(c, TYPE(c->qid), dp);
  225         case Qconvdir:
  226                 if(s == DEVDOTDOT){
  227                         s = PROTO(c->qid);
  228                         mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
  229                         devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
  230                         return 1;
  231                 }
  232                 return ip3gen(c, s+Qconvbase, dp);
  233         case Qctl:
  234         case Qdata:
  235         case Qerr:
  236         case Qlisten:
  237         case Qlocal:
  238         case Qremote:
  239         case Qstatus:
  240         case Qsnoop:
  241                 return ip3gen(c, TYPE(c->qid), dp);
  242         }
  243         return -1;
  244 }
  245 
  246 static void
  247 ipreset(void)
  248 {
  249         nullmediumlink();
  250         pktmediumlink();
  251 
  252         fmtinstall('i', eipfmt);
  253         fmtinstall('I', eipfmt);
  254         fmtinstall('E', eipfmt);
  255         fmtinstall('V', eipfmt);
  256         fmtinstall('M', eipfmt);
  257 }
  258 
  259 static Fs*
  260 ipgetfs(int dev)
  261 {
  262         extern void (*ipprotoinit[])(Fs*);
  263         Fs *f;
  264         int i;
  265 
  266         if(dev >= Nfs)
  267                 return nil;
  268 
  269         qlock(&fslock);
  270         if(ipfs[dev] == nil){
  271                 f = smalloc(sizeof(Fs));
  272                 ip_init(f);
  273                 arpinit(f);
  274                 netloginit(f);
  275                 for(i = 0; ipprotoinit[i]; i++)
  276                         ipprotoinit[i](f);
  277                 f->dev = dev;
  278                 ipfs[dev] = f;
  279         }
  280         qunlock(&fslock);
  281 
  282         return ipfs[dev];
  283 }
  284 
  285 IPaux*
  286 newipaux(char *owner, char *tag)
  287 {
  288         IPaux *a;
  289         int n;
  290 
  291         a = smalloc(sizeof(*a));
  292         kstrdup(&a->owner, owner);
  293         memset(a->tag, ' ', sizeof(a->tag));
  294         n = strlen(tag);
  295         if(n > sizeof(a->tag))
  296                 n = sizeof(a->tag);
  297         memmove(a->tag, tag, n);
  298         return a;
  299 }
  300 
  301 #define ATTACHER(c) (((IPaux*)((c)->aux))->owner)
  302 
  303 static Chan*
  304 ipattach(char* spec)
  305 {
  306         Chan *c;
  307         int dev;
  308 
  309         dev = atoi(spec);
  310         if(dev >= Nfs)
  311                 error("bad specification");
  312 
  313         ipgetfs(dev);
  314         c = devattach('I', spec);
  315         mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
  316         c->dev = dev;
  317 
  318         c->aux = newipaux(commonuser(), "none");
  319 
  320         return c;
  321 }
  322 
  323 static Walkqid*
  324 ipwalk(Chan* c, Chan *nc, char **name, int nname)
  325 {
  326         IPaux *a = c->aux;
  327         Walkqid* w;
  328 
  329         w = devwalk(c, nc, name, nname, nil, 0, ipgen);
  330         if(w != nil && w->clone != nil)
  331                 w->clone->aux = newipaux(a->owner, a->tag);
  332         return w;
  333 }
  334 
  335 
  336 static int
  337 ipstat(Chan* c, uchar* db, int n)
  338 {
  339         return devstat(c, db, n, nil, 0, ipgen);
  340 }
  341 
  342 static int
  343 incoming(void* arg)
  344 {
  345         Conv *conv;
  346 
  347         conv = arg;
  348         return conv->incall != nil;
  349 }
  350 
  351 static int m2p[] = {
  352         [OREAD]         4,
  353         [OWRITE]        2,
  354         [ORDWR]         6
  355 };
  356 
  357 static Chan*
  358 ipopen(Chan* c, int omode)
  359 {
  360         Conv *cv, *nc;
  361         Proto *p;
  362         int perm;
  363         Fs *f;
  364 
  365         perm = m2p[omode&3];
  366 
  367         f = ipfs[c->dev];
  368 
  369         switch(TYPE(c->qid)) {
  370         default:
  371                 break;
  372         case Qndb:
  373                 if(omode & (OWRITE|OTRUNC) && !iseve())
  374                         error(Eperm);
  375                 if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
  376                         f->ndb[0] = 0;
  377                 break;
  378         case Qlog:
  379                 netlogopen(f);
  380                 break;
  381         case Qiproute:
  382         case Qarp:
  383                 if(omode != OREAD && !iseve())
  384                         error(Eperm);
  385                 break;
  386         case Qtopdir:
  387         case Qprotodir:
  388         case Qconvdir:
  389         case Qstatus:
  390         case Qremote:
  391         case Qlocal:
  392         case Qstats:
  393         case Qbootp:
  394         case Qipselftab:
  395                 if(omode != OREAD)
  396                         error(Eperm);
  397                 break;
  398         case Qsnoop:
  399                 if(omode != OREAD)
  400                         error(Eperm);
  401                 p = f->p[PROTO(c->qid)];
  402                 cv = p->conv[CONV(c->qid)];
  403                 if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
  404                         error(Eperm);
  405                 incref(&cv->snoopers);
  406                 break;
  407         case Qclone:
  408                 p = f->p[PROTO(c->qid)];
  409                 qlock(p);
  410                 if(waserror()){
  411                         qunlock(p);
  412                         nexterror();
  413                 }
  414                 cv = Fsprotoclone(p, ATTACHER(c));
  415                 qunlock(p);
  416                 poperror();
  417                 if(cv == nil) {
  418                         error(Enodev);
  419                         break;
  420                 }
  421                 mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
  422                 break;
  423         case Qdata:
  424         case Qctl:
  425         case Qerr:
  426                 p = f->p[PROTO(c->qid)];
  427                 qlock(p);
  428                 cv = p->conv[CONV(c->qid)];
  429                 qlock(cv);
  430                 if(waserror()) {
  431                         qunlock(cv);
  432                         qunlock(p);
  433                         nexterror();
  434                 }
  435                 if((perm & (cv->perm>>6)) != perm) {
  436                         if(strcmp(ATTACHER(c), cv->owner) != 0)
  437                                 error(Eperm);
  438                         if((perm & cv->perm) != perm)
  439                                 error(Eperm);
  440 
  441                 }
  442                 cv->inuse++;
  443                 if(cv->inuse == 1){
  444                         kstrdup(&cv->owner, ATTACHER(c));
  445                         cv->perm = 0660;
  446                 }
  447                 qunlock(cv);
  448                 qunlock(p);
  449                 poperror();
  450                 break;
  451         case Qlisten:
  452                 cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
  453                 if((perm & (cv->perm>>6)) != perm) {
  454                         if(strcmp(ATTACHER(c), cv->owner) != 0)
  455                                 error(Eperm);
  456                         if((perm & cv->perm) != perm)
  457                                 error(Eperm);
  458 
  459                 }
  460 
  461                 if(cv->state != Announced)
  462                         error("not announced");
  463 
  464                 if(waserror()){
  465                         closeconv(cv);
  466                         nexterror();
  467                 }
  468                 qlock(cv);
  469                 cv->inuse++;
  470                 qunlock(cv);
  471 
  472                 nc = nil;
  473                 while(nc == nil) {
  474                         /* give up if we got a hangup */
  475                         if(qisclosed(cv->rq))
  476                                 error("listen hungup");
  477 
  478                         qlock(&cv->listenq);
  479                         if(waserror()) {
  480                                 qunlock(&cv->listenq);
  481                                 nexterror();
  482                         }
  483 
  484                         /* wait for a connect */
  485                         sleep(&cv->listenr, incoming, cv);
  486 
  487                         qlock(cv);
  488                         nc = cv->incall;
  489                         if(nc != nil){
  490                                 cv->incall = nc->next;
  491                                 mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
  492                                 kstrdup(&cv->owner, ATTACHER(c));
  493                         }
  494                         qunlock(cv);
  495 
  496                         qunlock(&cv->listenq);
  497                         poperror();
  498                 }
  499                 closeconv(cv);
  500                 poperror();
  501                 break;
  502         }
  503         c->mode = openmode(omode);
  504         c->flag |= COPEN;
  505         c->offset = 0;
  506         return c;
  507 }
  508 
  509 static void
  510 ipcreate(Chan*, char*, int, ulong)
  511 {
  512         error(Eperm);
  513 }
  514 
  515 static void
  516 ipremove(Chan*)
  517 {
  518         error(Eperm);
  519 }
  520 
  521 static int
  522 ipwstat(Chan *c, uchar *dp, int n)
  523 {
  524         Dir d;
  525         Conv *cv;
  526         Fs *f;
  527         Proto *p;
  528 
  529         f = ipfs[c->dev];
  530         switch(TYPE(c->qid)) {
  531         default:
  532                 error(Eperm);
  533                 break;
  534         case Qctl:
  535         case Qdata:
  536                 break;
  537         }
  538 
  539         n = convM2D(dp, n, &d, nil);
  540         if(n > 0){
  541                 p = f->p[PROTO(c->qid)];
  542                 cv = p->conv[CONV(c->qid)];
  543                 if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
  544                         error(Eperm);
  545                 if(d.uid[0])
  546                         kstrdup(&cv->owner, d.uid);
  547                 cv->perm = d.mode & 0777;
  548         }
  549         return n;
  550 }
  551 
  552 void
  553 closeconv(Conv *cv)
  554 {
  555         Conv *nc;
  556         Ipmulti *mp;
  557 
  558         qlock(cv);
  559 
  560         if(--cv->inuse > 0) {
  561                 qunlock(cv);
  562                 return;
  563         }
  564 
  565         /* close all incoming calls since no listen will ever happen */
  566         for(nc = cv->incall; nc; nc = cv->incall){
  567                 cv->incall = nc->next;
  568                 closeconv(nc);
  569         }
  570         cv->incall = nil;
  571 
  572         kstrdup(&cv->owner, network);
  573         cv->perm = 0660;
  574 
  575         while((mp = cv->multi) != nil)
  576                 ipifcremmulti(cv, mp->ma, mp->ia);
  577 
  578         cv->r = nil;
  579         cv->rgen = 0;
  580         cv->p->close(cv);
  581         cv->state = Idle;
  582         qunlock(cv);
  583 }
  584 
  585 static void
  586 ipclose(Chan* c)
  587 {
  588         Fs *f;
  589 
  590         f = ipfs[c->dev];
  591         switch(TYPE(c->qid)) {
  592         default:
  593                 break;
  594         case Qlog:
  595                 if(c->flag & COPEN)
  596                         netlogclose(f);
  597                 break;
  598         case Qdata:
  599         case Qctl:
  600         case Qerr:
  601                 if(c->flag & COPEN)
  602                         closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
  603                 break;
  604         case Qsnoop:
  605                 if(c->flag & COPEN)
  606                         decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
  607                 break;
  608         }
  609         free(((IPaux*)c->aux)->owner);
  610         free(c->aux);
  611 }
  612 
  613 enum
  614 {
  615         Statelen=       32*1024,
  616 };
  617 
  618 static long
  619 ipread(Chan *ch, void *a, long n, vlong off)
  620 {
  621         Conv *c;
  622         Proto *x;
  623         char *buf, *p;
  624         long rv;
  625         Fs *f;
  626         ulong offset = off;
  627 
  628         f = ipfs[ch->dev];
  629 
  630         p = a;
  631         switch(TYPE(ch->qid)) {
  632         default:
  633                 error(Eperm);
  634         case Qtopdir:
  635         case Qprotodir:
  636         case Qconvdir:
  637                 return devdirread(ch, a, n, 0, 0, ipgen);
  638         case Qarp:
  639                 return arpread(f->arp, a, offset, n);
  640         case Qbootp:
  641                 return bootpread(a, offset, n);
  642         case Qndb:
  643                 return readstr(offset, a, n, f->ndb);
  644         case Qiproute:
  645                 return routeread(f, a, offset, n);
  646         case Qipselftab:
  647                 return ipselftabread(f, a, offset, n);
  648         case Qlog:
  649                 return netlogread(f, a, offset, n);
  650         case Qctl:
  651                 buf = smalloc(16);
  652                 sprint(buf, "%lud", CONV(ch->qid));
  653                 rv = readstr(offset, p, n, buf);
  654                 free(buf);
  655                 return rv;
  656         case Qremote:
  657                 buf = smalloc(Statelen);
  658                 x = f->p[PROTO(ch->qid)];
  659                 c = x->conv[CONV(ch->qid)];
  660                 if(x->remote == nil) {
  661                         sprint(buf, "%I!%d\n", c->raddr, c->rport);
  662                 } else {
  663                         (*x->remote)(c, buf, Statelen-2);
  664                 }
  665                 rv = readstr(offset, p, n, buf);
  666                 free(buf);
  667                 return rv;
  668         case Qlocal:
  669                 buf = smalloc(Statelen);
  670                 x = f->p[PROTO(ch->qid)];
  671                 c = x->conv[CONV(ch->qid)];
  672                 if(x->local == nil) {
  673                         sprint(buf, "%I!%d\n", c->laddr, c->lport);
  674                 } else {
  675                         (*x->local)(c, buf, Statelen-2);
  676                 }
  677                 rv = readstr(offset, p, n, buf);
  678                 free(buf);
  679                 return rv;
  680         case Qstatus:
  681                 buf = smalloc(Statelen);
  682                 x = f->p[PROTO(ch->qid)];
  683                 c = x->conv[CONV(ch->qid)];
  684                 (*x->state)(c, buf, Statelen-2);
  685                 rv = readstr(offset, p, n, buf);
  686                 free(buf);
  687                 return rv;
  688         case Qdata:
  689                 c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
  690                 return qread(c->rq, a, n);
  691         case Qerr:
  692                 c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
  693                 return qread(c->eq, a, n);
  694         case Qsnoop:
  695                 c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
  696                 return qread(c->sq, a, n);
  697         case Qstats:
  698                 x = f->p[PROTO(ch->qid)];
  699                 if(x->stats == nil)
  700                         error("stats not implemented");
  701                 buf = smalloc(Statelen);
  702                 (*x->stats)(x, buf, Statelen);
  703                 rv = readstr(offset, p, n, buf);
  704                 free(buf);
  705                 return rv;
  706         }
  707 }
  708 
  709 static Block*
  710 ipbread(Chan* ch, long n, ulong offset)
  711 {
  712         Conv *c;
  713         Proto *x;
  714         Fs *f;
  715 
  716         switch(TYPE(ch->qid)){
  717         case Qdata:
  718                 f = ipfs[ch->dev];
  719                 x = f->p[PROTO(ch->qid)];
  720                 c = x->conv[CONV(ch->qid)];
  721                 return qbread(c->rq, n);
  722         default:
  723                 return devbread(ch, n, offset);
  724         }
  725 }
  726 
  727 /*
  728  *  set local address to be that of the ifc closest to remote address
  729  */
  730 static void
  731 setladdr(Conv* c)
  732 {
  733         findlocalip(c->p->f, c->laddr, c->raddr);
  734 }
  735 
  736 /*
  737  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
  738  */
  739 char*
  740 setluniqueport(Conv* c, int lport)
  741 {
  742         Proto *p;
  743         Conv *xp;
  744         int x;
  745 
  746         p = c->p;
  747 
  748         qlock(p);
  749         for(x = 0; x < p->nc; x++){
  750                 xp = p->conv[x];
  751                 if(xp == nil)
  752                         break;
  753                 if(xp == c)
  754                         continue;
  755                 if((xp->state == Connected || xp->state == Announced)
  756                 && xp->lport == lport
  757                 && xp->rport == c->rport
  758                 && ipcmp(xp->raddr, c->raddr) == 0
  759                 && ipcmp(xp->laddr, c->laddr) == 0){
  760                         qunlock(p);
  761                         return "address in use";
  762                 }
  763         }
  764         c->lport = lport;
  765         qunlock(p);
  766         return nil;
  767 }
  768 
  769 /*
  770  * is lport in use by anyone?
  771  */
  772 static int
  773 lportinuse(Proto *p, ushort lport)
  774 {
  775         int x;
  776 
  777         for(x = 0; x < p->nc && p->conv[x]; x++)
  778                 if(p->conv[x]->lport == lport)
  779                         return 1;
  780         return 0;
  781 }
  782 
  783 /*
  784  *  pick a local port and set it
  785  */
  786 char *
  787 setlport(Conv* c)
  788 {
  789         Proto *p;
  790         int i, port;
  791 
  792         p = c->p;
  793         qlock(p);
  794         if(c->restricted){
  795                 /* Restricted ports cycle between 600 and 1024. */
  796                 for(i=0; i<1024-600; i++){
  797                         if(p->nextrport >= 1024 || p->nextrport < 600)
  798                                 p->nextrport = 600;
  799                         port = p->nextrport++;
  800                         if(!lportinuse(p, port))
  801                                 goto chosen;
  802                 }
  803         }else{
  804                 /*
  805                  * Unrestricted ports are chosen randomly
  806                  * between 2^15 and 2^16.  There are at most
  807                  * 4*Nchan = 4096 ports in use at any given time,
  808                  * so even in the worst case, a random probe has a
  809                  * 1 - 4096/2^15 = 87% chance of success.
  810                  * If 64 successive probes fail, there is a bug somewhere
  811                  * (or a once in 10^58 event has happened, but that's
  812                  * less likely than a venti collision).
  813                  */
  814                 for(i=0; i<64; i++){
  815                         port = (1<<15) + nrand(1<<15);
  816                         if(!lportinuse(p, port))
  817                                 goto chosen;
  818                 }
  819         }
  820         qunlock(p);
  821         return "no ports available";
  822 
  823 chosen:
  824         c->lport = port;
  825         qunlock(p);
  826         return nil;
  827 }
  828 
  829 /*
  830  *  set a local address and port from a string of the form
  831  *      [address!]port[!r]
  832  */
  833 char*
  834 setladdrport(Conv* c, char* str, int announcing)
  835 {
  836         char *p;
  837         char *rv;
  838         ushort lport;
  839         uchar addr[IPaddrlen];
  840 
  841         /*
  842          *  ignore restricted part if it exists.  it's
  843          *  meaningless on local ports.
  844          */
  845         p = strchr(str, '!');
  846         if(p != nil){
  847                 *p++ = 0;
  848                 if(strcmp(p, "r") == 0)
  849                         p = nil;
  850         }
  851 
  852         c->lport = 0;
  853         if(p == nil){
  854                 if(announcing)
  855                         ipmove(c->laddr, IPnoaddr);
  856                 else
  857                         setladdr(c);
  858                 p = str;
  859         } else {
  860                 if(strcmp(str, "*") == 0)
  861                         ipmove(c->laddr, IPnoaddr);
  862                 else {
  863                         if(parseip(addr, str) == -1)
  864                                 return Ebadip;
  865                         if(ipforme(c->p->f, addr))
  866                                 ipmove(c->laddr, addr);
  867                         else
  868                                 return "not a local IP address";
  869                 }
  870         }
  871 
  872         /* one process can get all connections */
  873         if(announcing && strcmp(p, "*") == 0){
  874                 if(!iseve())
  875                         error(Eperm);
  876                 return setluniqueport(c, 0);
  877         }
  878 
  879         lport = atoi(p);
  880         if(lport <= 0)
  881                 rv = setlport(c);
  882         else
  883                 rv = setluniqueport(c, lport);
  884         return rv;
  885 }
  886 
  887 static char*
  888 setraddrport(Conv* c, char* str)
  889 {
  890         char *p;
  891 
  892         p = strchr(str, '!');
  893         if(p == nil)
  894                 return "malformed address";
  895         *p++ = 0;
  896         if (parseip(c->raddr, str) == -1)
  897                 return Ebadip;
  898         c->rport = atoi(p);
  899         p = strchr(p, '!');
  900         if(p){
  901                 if(strstr(p, "!r") != nil)
  902                         c->restricted = 1;
  903         }
  904         return nil;
  905 }
  906 
  907 /*
  908  *  called by protocol connect routine to set addresses
  909  */
  910 char*
  911 Fsstdconnect(Conv *c, char *argv[], int argc)
  912 {
  913         char *p;
  914 
  915         switch(argc) {
  916         default:
  917                 return "bad args to connect";
  918         case 2:
  919                 p = setraddrport(c, argv[1]);
  920                 if(p != nil)
  921                         return p;
  922                 setladdr(c);
  923                 p = setlport(c);
  924                 if (p != nil)
  925                         return p;
  926                 break;
  927         case 3:
  928                 p = setraddrport(c, argv[1]);
  929                 if(p != nil)
  930                         return p;
  931                 p = setladdrport(c, argv[2], 0);
  932                 if(p != nil)
  933                         return p;
  934         }
  935 
  936         if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
  937                 memcmp(c->laddr, v4prefix, IPv4off) == 0)
  938                 || ipcmp(c->raddr, IPnoaddr) == 0)
  939                 c->ipversion = V4;
  940         else
  941                 c->ipversion = V6;
  942 
  943         return nil;
  944 }
  945 /*
  946  *  initiate connection and sleep till its set up
  947  */
  948 static int
  949 connected(void* a)
  950 {
  951         return ((Conv*)a)->state == Connected;
  952 }
  953 static void
  954 connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
  955 {
  956         char *p;
  957 
  958         if(c->state != 0)
  959                 error(Econinuse);
  960         c->state = Connecting;
  961         c->cerr[0] = '\0';
  962         if(x->connect == nil)
  963                 error("connect not supported");
  964         p = x->connect(c, cb->f, cb->nf);
  965         if(p != nil)
  966                 error(p);
  967 
  968         qunlock(c);
  969         if(waserror()){
  970                 qlock(c);
  971                 nexterror();
  972         }
  973         sleep(&c->cr, connected, c);
  974         qlock(c);
  975         poperror();
  976 
  977         if(c->cerr[0] != '\0')
  978                 error(c->cerr);
  979 }
  980 
  981 /*
  982  *  called by protocol announce routine to set addresses
  983  */
  984 char*
  985 Fsstdannounce(Conv* c, char* argv[], int argc)
  986 {
  987         memset(c->raddr, 0, sizeof(c->raddr));
  988         c->rport = 0;
  989         switch(argc){
  990         default:
  991                 break;
  992         case 2:
  993                 return setladdrport(c, argv[1], 1);
  994         }
  995         return "bad args to announce";
  996 }
  997 
  998 /*
  999  *  initiate announcement and sleep till its set up
 1000  */
 1001 static int
 1002 announced(void* a)
 1003 {
 1004         return ((Conv*)a)->state == Announced;
 1005 }
 1006 static void
 1007 announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
 1008 {
 1009         char *p;
 1010 
 1011         if(c->state != 0)
 1012                 error(Econinuse);
 1013         c->state = Announcing;
 1014         c->cerr[0] = '\0';
 1015         if(x->announce == nil)
 1016                 error("announce not supported");
 1017         p = x->announce(c, cb->f, cb->nf);
 1018         if(p != nil)
 1019                 error(p);
 1020 
 1021         qunlock(c);
 1022         if(waserror()){
 1023                 qlock(c);
 1024                 nexterror();
 1025         }
 1026         sleep(&c->cr, announced, c);
 1027         qlock(c);
 1028         poperror();
 1029 
 1030         if(c->cerr[0] != '\0')
 1031                 error(c->cerr);
 1032 }
 1033 
 1034 /*
 1035  *  called by protocol bind routine to set addresses
 1036  */
 1037 char*
 1038 Fsstdbind(Conv* c, char* argv[], int argc)
 1039 {
 1040         switch(argc){
 1041         default:
 1042                 break;
 1043         case 2:
 1044                 return setladdrport(c, argv[1], 0);
 1045         }
 1046         return "bad args to bind";
 1047 }
 1048 
 1049 static void
 1050 bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
 1051 {
 1052         char *p;
 1053 
 1054         if(x->bind == nil)
 1055                 p = Fsstdbind(c, cb->f, cb->nf);
 1056         else
 1057                 p = x->bind(c, cb->f, cb->nf);
 1058         if(p != nil)
 1059                 error(p);
 1060 }
 1061 
 1062 static void
 1063 tosctlmsg(Conv *c, Cmdbuf *cb)
 1064 {
 1065         if(cb->nf < 2)
 1066                 c->tos = 0;
 1067         else
 1068                 c->tos = atoi(cb->f[1]);
 1069 }
 1070 
 1071 static void
 1072 ttlctlmsg(Conv *c, Cmdbuf *cb)
 1073 {
 1074         if(cb->nf < 2)
 1075                 c->ttl = MAXTTL;
 1076         else
 1077                 c->ttl = atoi(cb->f[1]);
 1078 }
 1079 
 1080 static long
 1081 ipwrite(Chan* ch, void *v, long n, vlong off)
 1082 {
 1083         Conv *c;
 1084         Proto *x;
 1085         char *p;
 1086         Cmdbuf *cb;
 1087         uchar ia[IPaddrlen], ma[IPaddrlen];
 1088         Fs *f;
 1089         char *a;
 1090         ulong offset = off;
 1091 
 1092         a = v;
 1093         f = ipfs[ch->dev];
 1094 
 1095         switch(TYPE(ch->qid)){
 1096         default:
 1097                 error(Eperm);
 1098         case Qdata:
 1099                 x = f->p[PROTO(ch->qid)];
 1100                 c = x->conv[CONV(ch->qid)];
 1101 
 1102                 if(c->wq == nil)
 1103                         error(Eperm);
 1104 
 1105                 qwrite(c->wq, a, n);
 1106                 break;
 1107         case Qarp:
 1108                 return arpwrite(f, a, n);
 1109         case Qiproute:
 1110                 return routewrite(f, ch, a, n);
 1111         case Qlog:
 1112                 netlogctl(f, a, n);
 1113                 return n;
 1114         case Qndb:
 1115                 return ndbwrite(f, a, offset, n);
 1116                 break;
 1117         case Qctl:
 1118                 x = f->p[PROTO(ch->qid)];
 1119                 c = x->conv[CONV(ch->qid)];
 1120                 cb = parsecmd(a, n);
 1121 
 1122                 qlock(c);
 1123                 if(waserror()) {
 1124                         qunlock(c);
 1125                         free(cb);
 1126                         nexterror();
 1127                 }
 1128                 if(cb->nf < 1)
 1129                         error("short control request");
 1130                 if(strcmp(cb->f[0], "connect") == 0)
 1131                         connectctlmsg(x, c, cb);
 1132                 else if(strcmp(cb->f[0], "announce") == 0)
 1133                         announcectlmsg(x, c, cb);
 1134                 else if(strcmp(cb->f[0], "bind") == 0)
 1135                         bindctlmsg(x, c, cb);
 1136                 else if(strcmp(cb->f[0], "ttl") == 0)
 1137                         ttlctlmsg(c, cb);
 1138                 else if(strcmp(cb->f[0], "tos") == 0)
 1139                         tosctlmsg(c, cb);
 1140                 else if(strcmp(cb->f[0], "ignoreadvice") == 0)
 1141                         c->ignoreadvice = 1;
 1142                 else if(strcmp(cb->f[0], "addmulti") == 0){
 1143                         if(cb->nf < 2)
 1144                                 error("addmulti needs interface address");
 1145                         if(cb->nf == 2){
 1146                                 if(!ipismulticast(c->raddr))
 1147                                         error("addmulti for a non multicast address");
 1148                                 if (parseip(ia, cb->f[1]) == -1)
 1149                                         error(Ebadip);
 1150                                 ipifcaddmulti(c, c->raddr, ia);
 1151                         } else {
 1152                                 if (parseip(ia, cb->f[1]) == -1 ||
 1153                                     parseip(ma, cb->f[2]) == -1)
 1154                                         error(Ebadip);
 1155                                 if(!ipismulticast(ma))
 1156                                         error("addmulti for a non multicast address");
 1157                                 ipifcaddmulti(c, ma, ia);
 1158                         }
 1159                 } else if(strcmp(cb->f[0], "remmulti") == 0){
 1160                         if(cb->nf < 2)
 1161                                 error("remmulti needs interface address");
 1162                         if(!ipismulticast(c->raddr))
 1163                                 error("remmulti for a non multicast address");
 1164                         if (parseip(ia, cb->f[1]) == -1)
 1165                                 error(Ebadip);
 1166                         ipifcremmulti(c, c->raddr, ia);
 1167                 } else if(strcmp(cb->f[0], "maxfragsize") == 0){
 1168                         if(cb->nf < 2)
 1169                                 error("maxfragsize needs size");
 1170 
 1171                         c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
 1172                         
 1173                 } else if(x->ctl != nil) {
 1174                         p = x->ctl(c, cb->f, cb->nf);
 1175                         if(p != nil)
 1176                                 error(p);
 1177                 } else
 1178                         error("unknown control request");
 1179                 qunlock(c);
 1180                 free(cb);
 1181                 poperror();
 1182         }
 1183         return n;
 1184 }
 1185 
 1186 static long
 1187 ipbwrite(Chan* ch, Block* bp, ulong offset)
 1188 {
 1189         Conv *c;
 1190         Proto *x;
 1191         Fs *f;
 1192         int n;
 1193 
 1194         switch(TYPE(ch->qid)){
 1195         case Qdata:
 1196                 f = ipfs[ch->dev];
 1197                 x = f->p[PROTO(ch->qid)];
 1198                 c = x->conv[CONV(ch->qid)];
 1199 
 1200                 if(c->wq == nil)
 1201                         error(Eperm);
 1202 
 1203                 if(bp->next)
 1204                         bp = concatblock(bp);
 1205                 n = BLEN(bp);
 1206                 qbwrite(c->wq, bp);
 1207                 return n;
 1208         default:
 1209                 return devbwrite(ch, bp, offset);
 1210         }
 1211 }
 1212 
 1213 Dev ipdevtab = {
 1214         'I',
 1215         "ip",
 1216 
 1217         ipreset,
 1218         devinit,
 1219         devshutdown,
 1220         ipattach,
 1221         ipwalk,
 1222         ipstat,
 1223         ipopen,
 1224         ipcreate,
 1225         ipclose,
 1226         ipread,
 1227         ipbread,
 1228         ipwrite,
 1229         ipbwrite,
 1230         ipremove,
 1231         ipwstat,
 1232 };
 1233 
 1234 int
 1235 Fsproto(Fs *f, Proto *p)
 1236 {
 1237         if(f->np >= Maxproto)
 1238                 return -1;
 1239 
 1240         p->f = f;
 1241 
 1242         if(p->ipproto > 0){
 1243                 if(f->t2p[p->ipproto] != nil)
 1244                         return -1;
 1245                 f->t2p[p->ipproto] = p;
 1246         }
 1247 
 1248         p->qid.type = QTDIR;
 1249         p->qid.path = QID(f->np, 0, Qprotodir);
 1250         p->conv = malloc(sizeof(Conv*)*(p->nc+1));
 1251         if(p->conv == nil)
 1252                 panic("Fsproto");
 1253 
 1254         p->x = f->np;
 1255         p->nextrport = 600;
 1256         f->p[f->np++] = p;
 1257 
 1258         return 0;
 1259 }
 1260 
 1261 /*
 1262  *  return true if this protocol is
 1263  *  built in
 1264  */
 1265 int
 1266 Fsbuiltinproto(Fs* f, uchar proto)
 1267 {
 1268         return f->t2p[proto] != nil;
 1269 }
 1270 
 1271 /*
 1272  *  called with protocol locked
 1273  */
 1274 Conv*
 1275 Fsprotoclone(Proto *p, char *user)
 1276 {
 1277         Conv *c, **pp, **ep;
 1278 
 1279 retry:
 1280         c = nil;
 1281         ep = &p->conv[p->nc];
 1282         for(pp = p->conv; pp < ep; pp++) {
 1283                 c = *pp;
 1284                 if(c == nil){
 1285                         c = malloc(sizeof(Conv));
 1286                         if(c == nil)
 1287                                 error(Enomem);
 1288                         qlock(c);
 1289                         c->p = p;
 1290                         c->x = pp - p->conv;
 1291                         if(p->ptclsize != 0){
 1292                                 c->ptcl = malloc(p->ptclsize);
 1293                                 if(c->ptcl == nil) {
 1294                                         free(c);
 1295                                         error(Enomem);
 1296                                 }
 1297                         }
 1298                         *pp = c;
 1299                         p->ac++;
 1300                         c->eq = qopen(1024, Qmsg, 0, 0);
 1301                         (*p->create)(c);
 1302                         break;
 1303                 }
 1304                 if(canqlock(c)){
 1305                         /*
 1306                          *  make sure both processes and protocol
 1307                          *  are done with this Conv
 1308                          */
 1309                         if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
 1310                                 break;
 1311 
 1312                         qunlock(c);
 1313                 }
 1314         }
 1315         if(pp >= ep) {
 1316                 if(p->gc != nil && (*p->gc)(p))
 1317                         goto retry;
 1318                 return nil;
 1319         }
 1320 
 1321         c->inuse = 1;
 1322         kstrdup(&c->owner, user);
 1323         c->perm = 0660;
 1324         c->state = Idle;
 1325         ipmove(c->laddr, IPnoaddr);
 1326         ipmove(c->raddr, IPnoaddr);
 1327         c->r = nil;
 1328         c->rgen = 0;
 1329         c->lport = 0;
 1330         c->rport = 0;
 1331         c->restricted = 0;
 1332         c->maxfragsize = 0;
 1333         c->ttl = MAXTTL;
 1334         qreopen(c->rq);
 1335         qreopen(c->wq);
 1336         qreopen(c->eq);
 1337 
 1338         qunlock(c);
 1339         return c;
 1340 }
 1341 
 1342 int
 1343 Fsconnected(Conv* c, char* msg)
 1344 {
 1345         if(msg != nil && *msg != '\0')
 1346                 strncpy(c->cerr, msg, ERRMAX-1);
 1347 
 1348         switch(c->state){
 1349 
 1350         case Announcing:
 1351                 c->state = Announced;
 1352                 break;
 1353 
 1354         case Connecting:
 1355                 c->state = Connected;
 1356                 break;
 1357         }
 1358 
 1359         wakeup(&c->cr);
 1360         return 0;
 1361 }
 1362 
 1363 Proto*
 1364 Fsrcvpcol(Fs* f, uchar proto)
 1365 {
 1366         if(f->ipmux)
 1367                 return f->ipmux;
 1368         else
 1369                 return f->t2p[proto];
 1370 }
 1371 
 1372 Proto*
 1373 Fsrcvpcolx(Fs *f, uchar proto)
 1374 {
 1375         return f->t2p[proto];
 1376 }
 1377 
 1378 /*
 1379  *  called with protocol locked
 1380  */
 1381 Conv*
 1382 Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
 1383 {
 1384         Conv *nc;
 1385         Conv **l;
 1386         int i;
 1387 
 1388         qlock(c);
 1389         i = 0;
 1390         for(l = &c->incall; *l; l = &(*l)->next)
 1391                 i++;
 1392         if(i >= Maxincall) {
 1393                 qunlock(c);
 1394                 return nil;
 1395         }
 1396 
 1397         /* find a free conversation */
 1398         nc = Fsprotoclone(c->p, network);
 1399         if(nc == nil) {
 1400                 qunlock(c);
 1401                 return nil;
 1402         }
 1403         ipmove(nc->raddr, raddr);
 1404         nc->rport = rport;
 1405         ipmove(nc->laddr, laddr);
 1406         nc->lport = lport;
 1407         nc->next = nil;
 1408         *l = nc;
 1409         nc->state = Connected;
 1410         nc->ipversion = version;
 1411 
 1412         qunlock(c);
 1413 
 1414         wakeup(&c->listenr);
 1415 
 1416         return nc;
 1417 }
 1418 
 1419 long
 1420 ndbwrite(Fs *f, char *a, ulong off, int n)
 1421 {
 1422         if(off > strlen(f->ndb))
 1423                 error(Eio);
 1424         if(off+n >= sizeof(f->ndb))
 1425                 error(Eio);
 1426         memmove(f->ndb+off, a, n);
 1427         f->ndb[off+n] = 0;
 1428         f->ndbvers++;
 1429         f->ndbmtime = seconds();
 1430         return n;
 1431 }
 1432 
 1433 ulong
 1434 scalednconv(void)
 1435 {
 1436         if(cpuserver && conf.npage*BY2PG >= 128*MB)
 1437                 return Nchans*4;
 1438         return Nchans;
 1439 }

Cache object: e3daaabe0dca6d2ae48e1bb8fd47c64b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.