int nbsslisten(NbName to, NbName from,int (*accept)(void *magic, NbSession *s, NBSSWRITEFN **writep), void *magic) { Listen *l; qlock(&tcp); if (tcp.thread < 0) { fmtinstall('B', nbnamefmt); tcp.acfd = announce("tcp!*!netbios", tcp.adir); if (tcp.acfd < 0) { print("nbsslisten: can't announce: %r\n"); qunlock(&tcp); return -1; } tcp.thread = proccreate(tcplistener, nil, 16384); } qunlock(&tcp); l = nbemalloc(sizeof(Listen)); nbnamecpy(l->to, to); nbnamecpy(l->from, from); l->accept = accept; l->magic = magic; qlock(&listens); l->next = listens.head; listens.head = l; qunlock(&listens); return 0; }
void * smbemallocz(ulong size, int clear) { void *p = nbemalloc(size); if (clear && p) memset(p, 0, size); return p; }
static NbSession * createsession(int fd) { Session *s; s = nbemalloc(sizeof(Session)); s->fd = fd; s->state = NeedSessionRequest; qlock(&sessions); s->thread = procrfork(tcpreader, s, 32768, RFNAMEG); if (s->thread < 0) { qunlock(&sessions); free(s); return nil; } s->next = sessions.head; sessions.head = s; qunlock(&sessions); return s; }
char * nbdgramlisten(NbName to, int (*deliver)(void *magic, NbDgram *s), void *magic) { Listen *l; char *e; nbnametablefind(to, 1); e = startlistener(); if (e) return e; l = nbemalloc(sizeof(Listen)); nbnamecpy(l->to, to); l->deliver = deliver; l->magic = magic; qlock(&listens); l->next = listens.head; listens.head = l; qunlock(&listens); return 0; }
static void tcpreader(void *a) { Session *s = a; uint8_t *buf; int buflen = smbglobals.maxreceive + 4; buf = nbemalloc(buflen); for (;;) { int n; uint8_t flags; uint16_t length; n = readn(s->fd, buf, 4); if (n != 4) { die: free(buf); if (s->state == Connected) (*s->write)(s, nil, -1); deletesession(s); return; } flags = buf[1]; length = nhgets(buf + 2) | ((flags & 1) << 16); if (length > buflen - 4) { print("nbss: too much data (%ud)\n", length); goto die; } n = readn(s->fd, buf + 4, length); if (n != length) goto die; if (s->state == Connected) { if ((*s->write)(s, buf + 4, length) != 0) { s->state = Dead; goto die; } } } }
static void tcpreader(void *a) { Session *s = a; uchar *buf; int buflen = 0x1ffff + 4; buf = nbemalloc(buflen); for (;;) { int n; uchar flags; ushort length; n = readn(s->fd, buf, 4); if (n != 4) { die: free(buf); if (s->state == Connected) (*s->write)(s, nil, -1); deletesession(s); return; } flags = buf[1]; length = nhgets(buf + 2) | ((flags & 1) << 16); n = readn(s->fd, buf + 4, length); if (n != length) goto die; if (flags & 0xfe) { print("nbss: invalid flags field 0x%.2ux\n", flags); goto die; } switch (buf[0]) { case 0: /* session message */ if (s->state != Connected && s->state != Dead) { print("nbss: unexpected session message\n"); goto die; } if (s->state == Connected) { if ((*s->write)(s, buf + 4, length) != 0) { s->state = Dead; goto die; } } break; case 0x81: /* session request */ { uchar *p, *ep; Listen *l; int k; int called_found; uchar error_code; if (s->state == Connected) { print("nbss: unexpected session request\n"); goto die; } p = buf + 4; ep = p + length; k = nbnamedecode(p, p, ep, s->to); if (k == 0) { print("nbss: malformed called name in session request\n"); goto die; } p += k; k = nbnamedecode(p, p, ep, s->from); if (k == 0) { print("nbss: malformed calling name in session request\n"); goto die; } /* p += k; if (p != ep) { print("nbss: extra data at end of session request\n"); goto die; } */ called_found = 0; //print("nbss: called %B calling %B\n", s->to, s->from); qlock(&listens); for (l = listens.head; l; l = l->next) if (nbnameequal(l->to, s->to)) { called_found = 1; if (nbnameequal(l->from, s->from)) break; } if (l == nil) { qunlock(&listens); error_code = called_found ? 0x81 : 0x80; replydie: buf[0] = 0x83; buf[1] = 0; hnputs(buf + 2, 1); buf[4] = error_code; write(s->fd, buf, 5); goto die; } if (!(*l->accept)(l->magic, s, &s->write)) { qunlock(&listens); error_code = 0x83; goto replydie; } buf[0] = 0x82; buf[1] = 0; hnputs(buf + 2, 0); if (write(s->fd, buf, 4) != 4) { qunlock(&listens); goto die; } s->state = Connected; qunlock(&listens); break; } case 0x85: /* keep awake */ break; default: print("nbss: opcode 0x%.2ux unexpected\n", buf[0]); goto die; } } }
NbSession * nbssconnect(NbName to, NbName from) { Session *s; uchar ipaddr[IPaddrlen]; char dialaddress[100]; char dir[NETPATHLEN]; uchar msg[576]; int fd; long o; uchar flags; long length; if (!nbnameresolve(to, ipaddr)) return nil; fmtinstall('I', eipfmt); snprint(dialaddress, sizeof(dialaddress), "tcp!%I!netbios", ipaddr); fd = dial(dialaddress, nil, dir, nil); if (fd < 0) return nil; msg[0] = 0x81; msg[1] = 0; o = 4; o += nbnameencode(msg + o, msg + sizeof(msg) - o, to); o += nbnameencode(msg + o, msg + sizeof(msg) - o, from); hnputs(msg + 2, o - 4); if (write(fd, msg, o) != o) { close(fd); return nil; } if (readn(fd, msg, 4) != 4) { close(fd); return nil; } flags = msg[1]; length = nhgets(msg + 2) | ((flags & 1) << 16); switch (msg[0]) { default: close(fd); werrstr("unexpected session message code 0x%.2ux", msg[0]); return nil; case 0x82: if (length != 0) { close(fd); werrstr("length not 0 in positive session response"); return nil; } break; case 0x83: if (length != 1) { close(fd); werrstr("length not 1 in negative session response"); return nil; } if (readn(fd, msg + 4, 1) != 1) { close(fd); return nil; } close(fd); werrstr("negative session response 0x%.2ux", msg[4]); return nil; } s = nbemalloc(sizeof(Session)); s->fd = fd; s->state = Connected; qlock(&sessions); s->next = sessions.head; sessions.head = s; qunlock(&sessions); return s; }