netif.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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 "../port/netif.h"
  8. static int netown(Netfile*, char*, int);
  9. static int openfile(Netif*, int);
  10. static char* matchtoken(char*, char*);
  11. static char* netmulti(Netif*, Netfile*, uchar*, int);
  12. static int parseaddr(uchar*, char*, int);
  13. /*
  14. * set up a new network interface
  15. */
  16. void
  17. netifinit(Netif *nif, char *name, int nfile, ulong limit)
  18. {
  19. strncpy(nif->name, name, KNAMELEN-1);
  20. nif->name[KNAMELEN-1] = 0;
  21. nif->nfile = nfile;
  22. nif->f = xalloc(nfile*sizeof(Netfile*));
  23. memset(nif->f, 0, nfile*sizeof(Netfile*));
  24. nif->limit = limit;
  25. }
  26. /*
  27. * generate a 3 level directory
  28. */
  29. static int
  30. netifgen(Chan *c, char*, Dirtab *vp, int, int i, Dir *dp)
  31. {
  32. Qid q;
  33. Netif *nif = (Netif*)vp;
  34. Netfile *f;
  35. int t;
  36. int perm;
  37. char *o;
  38. q.type = QTFILE;
  39. q.vers = 0;
  40. /* top level directory contains the name of the network */
  41. if(c->qid.path == 0){
  42. switch(i){
  43. case DEVDOTDOT:
  44. q.path = 0;
  45. q.type = QTDIR;
  46. devdir(c, q, ".", 0, eve, 0555, dp);
  47. break;
  48. case 0:
  49. q.path = N2ndqid;
  50. q.type = QTDIR;
  51. strcpy(up->genbuf, nif->name);
  52. devdir(c, q, up->genbuf, 0, eve, 0555, dp);
  53. break;
  54. default:
  55. return -1;
  56. }
  57. return 1;
  58. }
  59. /* second level contains clone plus all the conversations */
  60. t = NETTYPE(c->qid.path);
  61. if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
  62. switch(i) {
  63. case DEVDOTDOT:
  64. q.type = QTDIR;
  65. q.path = 0;
  66. devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
  67. break;
  68. case 0:
  69. q.path = Ncloneqid;
  70. devdir(c, q, "clone", 0, eve, 0666, dp);
  71. break;
  72. case 1:
  73. q.path = Naddrqid;
  74. devdir(c, q, "addr", 0, eve, 0666, dp);
  75. break;
  76. default:
  77. i -= 2;
  78. if(i >= nif->nfile)
  79. return -1;
  80. if(nif->f[i] == 0)
  81. return 0;
  82. q.type = QTDIR;
  83. q.path = NETQID(i, N3rdqid);
  84. sprint(up->genbuf, "%d", i);
  85. devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
  86. break;
  87. }
  88. return 1;
  89. }
  90. /* third level */
  91. f = nif->f[NETID(c->qid.path)];
  92. if(f == 0)
  93. return 0;
  94. if(*f->owner){
  95. o = f->owner;
  96. perm = f->mode;
  97. } else {
  98. o = eve;
  99. perm = 0666;
  100. }
  101. switch(i){
  102. case DEVDOTDOT:
  103. q.type = QTDIR;
  104. q.path = N2ndqid;
  105. strcpy(up->genbuf, nif->name);
  106. devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
  107. break;
  108. case 0:
  109. q.path = NETQID(NETID(c->qid.path), Ndataqid);
  110. devdir(c, q, "data", 0, o, perm, dp);
  111. break;
  112. case 1:
  113. q.path = NETQID(NETID(c->qid.path), Nctlqid);
  114. devdir(c, q, "ctl", 0, o, perm, dp);
  115. break;
  116. case 2:
  117. q.path = NETQID(NETID(c->qid.path), Nstatqid);
  118. devdir(c, q, "stats", 0, eve, 0444, dp);
  119. break;
  120. case 3:
  121. q.path = NETQID(NETID(c->qid.path), Ntypeqid);
  122. devdir(c, q, "type", 0, eve, 0444, dp);
  123. break;
  124. case 4:
  125. q.path = NETQID(NETID(c->qid.path), Nifstatqid);
  126. devdir(c, q, "ifstats", 0, eve, 0444, dp);
  127. break;
  128. default:
  129. return -1;
  130. }
  131. return 1;
  132. }
  133. Walkqid*
  134. netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
  135. {
  136. return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
  137. }
  138. Chan*
  139. netifopen(Netif *nif, Chan *c, int omode)
  140. {
  141. int id;
  142. Netfile *f;
  143. id = 0;
  144. if(c->qid.type & QTDIR){
  145. if(omode != OREAD)
  146. error(Eperm);
  147. } else {
  148. switch(NETTYPE(c->qid.path)){
  149. case Ndataqid:
  150. case Nctlqid:
  151. id = NETID(c->qid.path);
  152. openfile(nif, id);
  153. break;
  154. case Ncloneqid:
  155. id = openfile(nif, -1);
  156. c->qid.path = NETQID(id, Nctlqid);
  157. break;
  158. default:
  159. if(omode != OREAD)
  160. error(Ebadarg);
  161. }
  162. switch(NETTYPE(c->qid.path)){
  163. case Ndataqid:
  164. case Nctlqid:
  165. f = nif->f[id];
  166. if(netown(f, up->user, omode&7) < 0)
  167. error(Eperm);
  168. break;
  169. }
  170. }
  171. c->mode = openmode(omode);
  172. c->flag |= COPEN;
  173. c->offset = 0;
  174. c->iounit = qiomaxatomic;
  175. return c;
  176. }
  177. long
  178. netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
  179. {
  180. int i, j;
  181. Netfile *f;
  182. char *p;
  183. if(c->qid.type&QTDIR)
  184. return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
  185. switch(NETTYPE(c->qid.path)){
  186. case Ndataqid:
  187. f = nif->f[NETID(c->qid.path)];
  188. return qread(f->in, a, n);
  189. case Nctlqid:
  190. return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
  191. case Nstatqid:
  192. p = malloc(READSTR);
  193. j = snprint(p, READSTR, "in: %d\n", nif->inpackets);
  194. j += snprint(p+j, READSTR-j, "out: %d\n", nif->outpackets);
  195. j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
  196. j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
  197. j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
  198. j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
  199. j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
  200. j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
  201. j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
  202. j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
  203. j += snprint(p+j, READSTR-j, "addr: ");
  204. for(i = 0; i < nif->alen; i++)
  205. j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
  206. snprint(p+j, READSTR-j, "\n");
  207. n = readstr(offset, a, n, p);
  208. free(p);
  209. return n;
  210. case Naddrqid:
  211. p = malloc(READSTR);
  212. j = 0;
  213. for(i = 0; i < nif->alen; i++)
  214. j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
  215. n = readstr(offset, a, n, p);
  216. free(p);
  217. return n;
  218. case Ntypeqid:
  219. f = nif->f[NETID(c->qid.path)];
  220. return readnum(offset, a, n, f->type, NUMSIZE);
  221. case Nifstatqid:
  222. return 0;
  223. }
  224. error(Ebadarg);
  225. return -1; /* not reached */
  226. }
  227. Block*
  228. netifbread(Netif *nif, Chan *c, long n, ulong offset)
  229. {
  230. if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
  231. return devbread(c, n, offset);
  232. return qbread(nif->f[NETID(c->qid.path)]->in, n);
  233. }
  234. /*
  235. * make sure this type isn't already in use on this device
  236. */
  237. static int
  238. typeinuse(Netif *nif, int type)
  239. {
  240. Netfile *f, **fp, **efp;
  241. if(type <= 0)
  242. return 0;
  243. efp = &nif->f[nif->nfile];
  244. for(fp = nif->f; fp < efp; fp++){
  245. f = *fp;
  246. if(f == 0)
  247. continue;
  248. if(f->type == type)
  249. return 1;
  250. }
  251. return 0;
  252. }
  253. /*
  254. * the devxxx.c that calls us handles writing data, it knows best
  255. */
  256. long
  257. netifwrite(Netif *nif, Chan *c, void *a, long n)
  258. {
  259. Netfile *f;
  260. int type;
  261. char *p, buf[64];
  262. uchar binaddr[Nmaxaddr];
  263. if(NETTYPE(c->qid.path) != Nctlqid)
  264. error(Eperm);
  265. if(n >= sizeof(buf))
  266. n = sizeof(buf)-1;
  267. memmove(buf, a, n);
  268. buf[n] = 0;
  269. if(waserror()){
  270. qunlock(nif);
  271. nexterror();
  272. }
  273. qlock(nif);
  274. f = nif->f[NETID(c->qid.path)];
  275. if((p = matchtoken(buf, "connect")) != 0){
  276. type = atoi(p);
  277. if(typeinuse(nif, type))
  278. error(Einuse);
  279. f->type = type;
  280. if(f->type < 0)
  281. nif->all++;
  282. } else if(matchtoken(buf, "promiscuous")){
  283. if(f->prom == 0){
  284. if(nif->prom == 0 && nif->promiscuous != nil)
  285. nif->promiscuous(nif->arg, 1);
  286. f->prom = 1;
  287. nif->prom++;
  288. }
  289. } else if((p = matchtoken(buf, "scanbs")) != 0){
  290. /* scan for base stations */
  291. if(f->scan == 0){
  292. type = atoi(p);
  293. if(type < 5)
  294. type = 5;
  295. if(nif->scanbs != nil)
  296. nif->scanbs(nif->arg, type);
  297. f->scan = type;
  298. nif->scan++;
  299. }
  300. } else if(matchtoken(buf, "bridge")){
  301. f->bridge = 1;
  302. } else if(matchtoken(buf, "headersonly")){
  303. f->headersonly = 1;
  304. } else if((p = matchtoken(buf, "addmulti")) != 0){
  305. if(parseaddr(binaddr, p, nif->alen) < 0)
  306. error("bad address");
  307. p = netmulti(nif, f, binaddr, 1);
  308. if(p)
  309. error(p);
  310. } else if((p = matchtoken(buf, "remmulti")) != 0){
  311. if(parseaddr(binaddr, p, nif->alen) < 0)
  312. error("bad address");
  313. p = netmulti(nif, f, binaddr, 0);
  314. if(p)
  315. error(p);
  316. } else
  317. n = -1;
  318. qunlock(nif);
  319. poperror();
  320. return n;
  321. }
  322. int
  323. netifwstat(Netif *nif, Chan *c, uchar *db, int n)
  324. {
  325. Dir *dir;
  326. Netfile *f;
  327. int m;
  328. f = nif->f[NETID(c->qid.path)];
  329. if(f == 0)
  330. error(Enonexist);
  331. if(netown(f, up->user, OWRITE) < 0)
  332. error(Eperm);
  333. dir = smalloc(sizeof(Dir)+n);
  334. m = convM2D(db, n, &dir[0], (char*)&dir[1]);
  335. if(m == 0){
  336. free(dir);
  337. error(Eshortstat);
  338. }
  339. if(!emptystr(dir[0].uid))
  340. strncpy(f->owner, dir[0].uid, KNAMELEN);
  341. if(dir[0].mode != ~0UL)
  342. f->mode = dir[0].mode;
  343. free(dir);
  344. return m;
  345. }
  346. int
  347. netifstat(Netif *nif, Chan *c, uchar *db, int n)
  348. {
  349. return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
  350. }
  351. void
  352. netifclose(Netif *nif, Chan *c)
  353. {
  354. Netfile *f;
  355. int t;
  356. Netaddr *ap;
  357. if((c->flag & COPEN) == 0)
  358. return;
  359. t = NETTYPE(c->qid.path);
  360. if(t != Ndataqid && t != Nctlqid)
  361. return;
  362. f = nif->f[NETID(c->qid.path)];
  363. qlock(f);
  364. if(--(f->inuse) == 0){
  365. if(f->prom){
  366. qlock(nif);
  367. if(--(nif->prom) == 0 && nif->promiscuous != nil)
  368. nif->promiscuous(nif->arg, 0);
  369. qunlock(nif);
  370. f->prom = 0;
  371. }
  372. if(f->scan){
  373. qlock(nif);
  374. if(--(nif->scan) == 0 && nif->scanbs != nil)
  375. nif->scanbs(nif->arg, 0);
  376. qunlock(nif);
  377. f->prom = 0;
  378. f->scan = 0;
  379. }
  380. if(f->nmaddr){
  381. qlock(nif);
  382. t = 0;
  383. for(ap = nif->maddr; ap; ap = ap->next){
  384. if(f->maddr[t/8] & (1<<(t%8)))
  385. netmulti(nif, f, ap->addr, 0);
  386. }
  387. qunlock(nif);
  388. f->nmaddr = 0;
  389. }
  390. if(f->type < 0){
  391. qlock(nif);
  392. --(nif->all);
  393. qunlock(nif);
  394. }
  395. f->owner[0] = 0;
  396. f->type = 0;
  397. f->bridge = 0;
  398. f->headersonly = 0;
  399. qclose(f->in);
  400. }
  401. qunlock(f);
  402. }
  403. Lock netlock;
  404. static int
  405. netown(Netfile *p, char *o, int omode)
  406. {
  407. static int access[] = { 0400, 0200, 0600, 0100 };
  408. int mode;
  409. int t;
  410. lock(&netlock);
  411. if(*p->owner){
  412. if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */
  413. mode = p->mode;
  414. else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */
  415. mode = p->mode<<3;
  416. else
  417. mode = p->mode<<6; /* Other */
  418. t = access[omode&3];
  419. if((t & mode) == t){
  420. unlock(&netlock);
  421. return 0;
  422. } else {
  423. unlock(&netlock);
  424. return -1;
  425. }
  426. }
  427. strncpy(p->owner, o, KNAMELEN);
  428. p->mode = 0660;
  429. unlock(&netlock);
  430. return 0;
  431. }
  432. /*
  433. * Increment the reference count of a network device.
  434. * If id < 0, return an unused ether device.
  435. */
  436. static int
  437. openfile(Netif *nif, int id)
  438. {
  439. Netfile *f, **fp, **efp;
  440. if(id >= 0){
  441. f = nif->f[id];
  442. if(f == 0)
  443. error(Enodev);
  444. qlock(f);
  445. qreopen(f->in);
  446. f->inuse++;
  447. qunlock(f);
  448. return id;
  449. }
  450. qlock(nif);
  451. if(waserror()){
  452. qunlock(nif);
  453. nexterror();
  454. }
  455. efp = &nif->f[nif->nfile];
  456. for(fp = nif->f; fp < efp; fp++){
  457. f = *fp;
  458. if(f == 0){
  459. f = malloc(sizeof(Netfile));
  460. if(f == 0)
  461. exhausted("memory");
  462. f->in = qopen(nif->limit, Qmsg, 0, 0);
  463. if(f->in == nil){
  464. free(f);
  465. exhausted("memory");
  466. }
  467. *fp = f;
  468. qlock(f);
  469. } else {
  470. qlock(f);
  471. if(f->inuse){
  472. qunlock(f);
  473. continue;
  474. }
  475. }
  476. f->inuse = 1;
  477. qreopen(f->in);
  478. netown(f, up->user, 0);
  479. qunlock(f);
  480. qunlock(nif);
  481. poperror();
  482. return fp - nif->f;
  483. }
  484. error(Enodev);
  485. return -1; /* not reached */
  486. }
  487. /*
  488. * look for a token starting a string,
  489. * return a pointer to first non-space char after it
  490. */
  491. static char*
  492. matchtoken(char *p, char *token)
  493. {
  494. int n;
  495. n = strlen(token);
  496. if(strncmp(p, token, n))
  497. return 0;
  498. p += n;
  499. if(*p == 0)
  500. return p;
  501. if(*p != ' ' && *p != '\t' && *p != '\n')
  502. return 0;
  503. while(*p == ' ' || *p == '\t' || *p == '\n')
  504. p++;
  505. return p;
  506. }
  507. void
  508. hnputv(void *p, vlong v)
  509. {
  510. uchar *a;
  511. a = p;
  512. hnputl(a, v>>32);
  513. hnputl(a+4, v);
  514. }
  515. void
  516. hnputl(void *p, ulong v)
  517. {
  518. uchar *a;
  519. a = p;
  520. a[0] = v>>24;
  521. a[1] = v>>16;
  522. a[2] = v>>8;
  523. a[3] = v;
  524. }
  525. void
  526. hnputs(void *p, ushort v)
  527. {
  528. uchar *a;
  529. a = p;
  530. a[0] = v>>8;
  531. a[1] = v;
  532. }
  533. vlong
  534. nhgetv(void *p)
  535. {
  536. uchar *a;
  537. a = p;
  538. return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
  539. }
  540. ulong
  541. nhgetl(void *p)
  542. {
  543. uchar *a;
  544. a = p;
  545. return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
  546. }
  547. ushort
  548. nhgets(void *p)
  549. {
  550. uchar *a;
  551. a = p;
  552. return (a[0]<<8)|(a[1]<<0);
  553. }
  554. static ulong
  555. hash(uchar *a, int len)
  556. {
  557. ulong sum = 0;
  558. while(len-- > 0)
  559. sum = (sum << 1) + *a++;
  560. return sum%Nmhash;
  561. }
  562. int
  563. activemulti(Netif *nif, uchar *addr, int alen)
  564. {
  565. Netaddr *hp;
  566. for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
  567. if(memcmp(addr, hp->addr, alen) == 0){
  568. if(hp->ref)
  569. return 1;
  570. else
  571. break;
  572. }
  573. return 0;
  574. }
  575. static int
  576. parseaddr(uchar *to, char *from, int alen)
  577. {
  578. char nip[4];
  579. char *p;
  580. int i;
  581. p = from;
  582. for(i = 0; i < alen; i++){
  583. if(*p == 0)
  584. return -1;
  585. nip[0] = *p++;
  586. if(*p == 0)
  587. return -1;
  588. nip[1] = *p++;
  589. nip[2] = 0;
  590. to[i] = strtoul(nip, 0, 16);
  591. if(*p == ':')
  592. p++;
  593. }
  594. return 0;
  595. }
  596. /*
  597. * keep track of multicast addresses
  598. */
  599. static char*
  600. netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
  601. {
  602. Netaddr **l, *ap;
  603. int i;
  604. ulong h;
  605. if(nif->multicast == nil)
  606. return "interface does not support multicast";
  607. l = &nif->maddr;
  608. i = 0;
  609. for(ap = *l; ap; ap = *l){
  610. if(memcmp(addr, ap->addr, nif->alen) == 0)
  611. break;
  612. i++;
  613. l = &ap->next;
  614. }
  615. if(add){
  616. if(ap == 0){
  617. *l = ap = smalloc(sizeof(*ap));
  618. memmove(ap->addr, addr, nif->alen);
  619. ap->next = 0;
  620. ap->ref = 1;
  621. h = hash(addr, nif->alen);
  622. ap->hnext = nif->mhash[h];
  623. nif->mhash[h] = ap;
  624. } else {
  625. ap->ref++;
  626. }
  627. if(ap->ref == 1){
  628. nif->nmaddr++;
  629. nif->multicast(nif->arg, addr, 1);
  630. }
  631. if(i < 8*sizeof(f->maddr)){
  632. if((f->maddr[i/8] & (1<<(i%8))) == 0)
  633. f->nmaddr++;
  634. f->maddr[i/8] |= 1<<(i%8);
  635. }
  636. } else {
  637. if(ap == 0 || ap->ref == 0)
  638. return 0;
  639. ap->ref--;
  640. if(ap->ref == 0){
  641. nif->nmaddr--;
  642. nif->multicast(nif->arg, addr, 0);
  643. }
  644. if(i < 8*sizeof(f->maddr)){
  645. if((f->maddr[i/8] & (1<<(i%8))) != 0)
  646. f->nmaddr--;
  647. f->maddr[i/8] &= ~(1<<(i%8));
  648. }
  649. }
  650. return 0;
  651. }