netif.c 14 KB

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