nbss.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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 <libc.h>
  11. #include <ip.h>
  12. #include <thread.h>
  13. #include "netbios.h"
  14. static struct {
  15. int thread;
  16. QLock qlock;
  17. char adir[NETPATHLEN];
  18. int acfd;
  19. char ldir[NETPATHLEN];
  20. int lcfd;
  21. } tcp = { -1 };
  22. typedef struct Session Session;
  23. enum { NeedSessionRequest, Connected, Dead };
  24. struct Session {
  25. NbSession nbs;
  26. int thread;
  27. Session *next;
  28. int state;
  29. NBSSWRITEFN *write;
  30. };
  31. static struct {
  32. QLock qlock;
  33. Session *head;
  34. } sessions;
  35. typedef struct Listen Listen;
  36. struct Listen {
  37. NbName to;
  38. NbName from;
  39. int (*accept)(void *magic, NbSession *s, NBSSWRITEFN **writep);
  40. void *magic;
  41. Listen *next;
  42. };
  43. static struct {
  44. QLock qlock;
  45. Listen *head;
  46. } listens;
  47. static void
  48. deletesession(Session *s)
  49. {
  50. Session **sp;
  51. close(s->nbs.fd);
  52. qlock(&sessions.qlock);
  53. for (sp = &sessions.head; *sp && *sp != s; sp = &(*sp)->next)
  54. ;
  55. if (*sp)
  56. *sp = s->next;
  57. qunlock(&sessions.qlock);
  58. free(s);
  59. }
  60. static void
  61. tcpreader(void *a)
  62. {
  63. Session *s = a;
  64. uint8_t *buf;
  65. int buflen = 0x1ffff + 4;
  66. buf = nbemalloc(buflen);
  67. for (;;) {
  68. int n;
  69. uint8_t flags;
  70. uint16_t length;
  71. n = readn(s->nbs.fd, buf, 4);
  72. if (n != 4) {
  73. die:
  74. free(buf);
  75. if (s->state == Connected)
  76. (*s->write)(&s->nbs, nil, -1);
  77. deletesession(s);
  78. return;
  79. }
  80. flags = buf[1];
  81. length = nhgets(buf + 2) | ((flags & 1) << 16);
  82. n = readn(s->nbs.fd, buf + 4, length);
  83. if (n != length)
  84. goto die;
  85. if (flags & 0xfe) {
  86. print("nbss: invalid flags field 0x%.2x\n", flags);
  87. goto die;
  88. }
  89. switch (buf[0]) {
  90. case 0: /* session message */
  91. if (s->state != Connected && s->state != Dead) {
  92. print("nbss: unexpected session message\n");
  93. goto die;
  94. }
  95. if (s->state == Connected) {
  96. if ((*s->write)(&s->nbs, buf + 4, length) != 0) {
  97. s->state = Dead;
  98. goto die;
  99. }
  100. }
  101. break;
  102. case 0x81: /* session request */ {
  103. uint8_t *p, *ep;
  104. Listen *l;
  105. int k;
  106. int called_found;
  107. uint8_t error_code;
  108. if (s->state == Connected) {
  109. print("nbss: unexpected session request\n");
  110. goto die;
  111. }
  112. p = buf + 4;
  113. ep = p + length;
  114. k = nbnamedecode(p, p, ep, s->nbs.to);
  115. if (k == 0) {
  116. print("nbss: malformed called name in session request\n");
  117. goto die;
  118. }
  119. p += k;
  120. k = nbnamedecode(p, p, ep, s->nbs.from);
  121. if (k == 0) {
  122. print("nbss: malformed calling name in session request\n");
  123. goto die;
  124. }
  125. /*
  126. p += k;
  127. if (p != ep) {
  128. print("nbss: extra data at end of session request\n");
  129. goto die;
  130. }
  131. */
  132. called_found = 0;
  133. //print("nbss: called %B calling %B\n", s->to, s->from);
  134. qlock(&listens.qlock);
  135. for (l = listens.head; l; l = l->next)
  136. if (nbnameequal(l->to, s->nbs.to)) {
  137. called_found = 1;
  138. if (nbnameequal(l->from, s->nbs.from))
  139. break;
  140. }
  141. if (l == nil) {
  142. qunlock(&listens.qlock);
  143. error_code = called_found ? 0x81 : 0x80;
  144. replydie:
  145. buf[0] = 0x83;
  146. buf[1] = 0;
  147. hnputs(buf + 2, 1);
  148. buf[4] = error_code;
  149. write(s->nbs.fd, buf, 5);
  150. goto die;
  151. }
  152. if (!(*l->accept)(l->magic, &s->nbs, &s->write)) {
  153. qunlock(&listens.qlock);
  154. error_code = 0x83;
  155. goto replydie;
  156. }
  157. buf[0] = 0x82;
  158. buf[1] = 0;
  159. hnputs(buf + 2, 0);
  160. if (write(s->nbs.fd, buf, 4) != 4) {
  161. qunlock(&listens.qlock);
  162. goto die;
  163. }
  164. s->state = Connected;
  165. qunlock(&listens.qlock);
  166. break;
  167. }
  168. case 0x85: /* keep awake */
  169. break;
  170. default:
  171. print("nbss: opcode 0x%.2x unexpected\n", buf[0]);
  172. goto die;
  173. }
  174. }
  175. }
  176. static NbSession *
  177. createsession(int fd)
  178. {
  179. Session *s;
  180. s = nbemalloc(sizeof(Session));
  181. s->nbs.fd = fd;
  182. s->state = NeedSessionRequest;
  183. qlock(&sessions.qlock);
  184. s->thread = procrfork(tcpreader, s, 32768, RFNAMEG);
  185. if (s->thread < 0) {
  186. qunlock(&sessions.qlock);
  187. free(s);
  188. return nil;
  189. }
  190. s->next = sessions.head;
  191. sessions.head = s;
  192. qunlock(&sessions.qlock);
  193. return &s->nbs;
  194. }
  195. static void
  196. tcplistener(void *v)
  197. {
  198. for (;;) {
  199. int dfd;
  200. char ldir[NETPATHLEN];
  201. int lcfd;
  202. //print("tcplistener: listening\n");
  203. lcfd = listen(tcp.adir, ldir);
  204. //print("tcplistener: contact\n");
  205. if (lcfd < 0) {
  206. die:
  207. qlock(&tcp.qlock);
  208. close(tcp.acfd);
  209. tcp.thread = -1;
  210. qunlock(&tcp.qlock);
  211. return;
  212. }
  213. dfd = accept(lcfd, ldir);
  214. close(lcfd);
  215. if (dfd < 0)
  216. goto die;
  217. if (createsession(dfd) == nil)
  218. close(dfd);
  219. }
  220. }
  221. int
  222. nbsslisten(NbName to, NbName from,int (*accept)(void *magic, NbSession *s, NBSSWRITEFN **writep), void *magic)
  223. {
  224. Listen *l;
  225. qlock(&tcp.qlock);
  226. if (tcp.thread < 0) {
  227. fmtinstall('B', nbnamefmt);
  228. tcp.acfd = announce("tcp!*!netbios", tcp.adir);
  229. if (tcp.acfd < 0) {
  230. print("nbsslisten: can't announce: %r\n");
  231. qunlock(&tcp.qlock);
  232. return -1;
  233. }
  234. tcp.thread = proccreate(tcplistener, nil, 16384);
  235. }
  236. qunlock(&tcp.qlock);
  237. l = nbemalloc(sizeof(Listen));
  238. nbnamecpy(l->to, to);
  239. nbnamecpy(l->from, from);
  240. l->accept = accept;
  241. l->magic = magic;
  242. qlock(&listens.qlock);
  243. l->next = listens.head;
  244. listens.head = l;
  245. qunlock(&listens.qlock);
  246. return 0;
  247. }
  248. void
  249. nbssfree(NbSession *s)
  250. {
  251. deletesession((Session *)s);
  252. }
  253. int
  254. nbssgatherwrite(NbSession *s, NbScatterGather *a)
  255. {
  256. uint8_t hdr[4];
  257. NbScatterGather *ap;
  258. int32_t l = 0;
  259. for (ap = a; ap->p; ap++)
  260. l += ap->l;
  261. //print("nbssgatherwrite %ld bytes\n", l);
  262. hnputl(hdr, l);
  263. //nbdumpdata(hdr, sizeof(hdr));
  264. if (write(s->fd, hdr, sizeof(hdr)) != sizeof(hdr))
  265. return -1;
  266. for (ap = a; ap->p; ap++) {
  267. //nbdumpdata(ap->p, ap->l);
  268. if (write(s->fd, ap->p, ap->l) != ap->l)
  269. return -1;
  270. }
  271. return 0;
  272. }
  273. NbSession *
  274. nbssconnect(NbName to, NbName from)
  275. {
  276. Session *s;
  277. uint8_t ipaddr[IPaddrlen];
  278. char dialaddress[100];
  279. char dir[NETPATHLEN];
  280. uint8_t msg[576];
  281. int fd;
  282. int32_t o;
  283. uint8_t flags;
  284. int32_t length;
  285. if (!nbnameresolve(to, ipaddr))
  286. return nil;
  287. fmtinstall('I', eipfmt);
  288. snprint(dialaddress, sizeof(dialaddress), "tcp!%I!netbios", ipaddr);
  289. fd = dial(dialaddress, nil, dir, nil);
  290. if (fd < 0)
  291. return nil;
  292. msg[0] = 0x81;
  293. msg[1] = 0;
  294. o = 4;
  295. o += nbnameencode(msg + o, msg + sizeof(msg) - o, to);
  296. o += nbnameencode(msg + o, msg + sizeof(msg) - o, from);
  297. hnputs(msg + 2, o - 4);
  298. if (write(fd, msg, o) != o) {
  299. close(fd);
  300. return nil;
  301. }
  302. if (readn(fd, msg, 4) != 4) {
  303. close(fd);
  304. return nil;
  305. }
  306. flags = msg[1];
  307. length = nhgets(msg + 2) | ((flags & 1) << 16);
  308. switch (msg[0]) {
  309. default:
  310. close(fd);
  311. werrstr("unexpected session message code 0x%.2x", msg[0]);
  312. return nil;
  313. case 0x82:
  314. if (length != 0) {
  315. close(fd);
  316. werrstr("length not 0 in positive session response");
  317. return nil;
  318. }
  319. break;
  320. case 0x83:
  321. if (length != 1) {
  322. close(fd);
  323. werrstr("length not 1 in negative session response");
  324. return nil;
  325. }
  326. if (readn(fd, msg + 4, 1) != 1) {
  327. close(fd);
  328. return nil;
  329. }
  330. close(fd);
  331. werrstr("negative session response 0x%.2x", msg[4]);
  332. return nil;
  333. }
  334. s = nbemalloc(sizeof(Session));
  335. s->nbs.fd = fd;
  336. s->state = Connected;
  337. qlock(&sessions.qlock);
  338. s->next = sessions.head;
  339. sessions.head = s;
  340. qunlock(&sessions.qlock);
  341. return &s->nbs;
  342. }
  343. int32_t
  344. nbssscatterread(NbSession *nbs, NbScatterGather *a)
  345. {
  346. uint8_t hdr[4];
  347. uint8_t flags;
  348. int32_t length, total;
  349. NbScatterGather *ap;
  350. Session *s = (Session *)nbs;
  351. int32_t l = 0;
  352. for (ap = a; ap->p; ap++)
  353. l += ap->l;
  354. //print("nbssscatterread %ld bytes\n", l);
  355. again:
  356. if (readn(s->nbs.fd, hdr, 4) != 4) {
  357. dead:
  358. s->state = Dead;
  359. return -1;
  360. }
  361. flags = hdr[1];
  362. length = nhgets(hdr + 2) | ((flags & 1) << 16);
  363. //print("%.2x: %d\n", hdr[0], length);
  364. switch (hdr[0]) {
  365. case 0x85:
  366. if (length != 0) {
  367. werrstr("length in keepalive not 0");
  368. goto dead;
  369. }
  370. goto again;
  371. case 0x00:
  372. break;
  373. default:
  374. werrstr("unexpected session message code 0x%.2x", hdr[0]);
  375. goto dead;
  376. }
  377. if (length > l) {
  378. werrstr("message too big (%ld)", length);
  379. goto dead;
  380. }
  381. total = length;
  382. for (ap = a; length && ap->p; ap++) {
  383. int32_t thistime;
  384. int32_t n;
  385. thistime = length;
  386. if (thistime > ap->l)
  387. thistime = ap->l;
  388. //print("reading %d\n", length);
  389. n = readn(s->nbs.fd, ap->p, thistime);
  390. if (n != thistime)
  391. goto dead;
  392. length -= thistime;
  393. }
  394. return total;
  395. }
  396. int
  397. nbsswrite(NbSession *s, void *buf, int32_t maxlen)
  398. {
  399. NbScatterGather a[2];
  400. a[0].l = maxlen;
  401. a[0].p = buf;
  402. a[1].p = nil;
  403. return nbssgatherwrite(s, a);
  404. }
  405. int32_t
  406. nbssread(NbSession *s, void *buf, int32_t maxlen)
  407. {
  408. NbScatterGather a[2];
  409. a[0].l = maxlen;
  410. a[0].p = buf;
  411. a[1].p = nil;
  412. return nbssscatterread(s, a);
  413. }