Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <ip.h>
#include <thread.h>
#include "netbios.h"

static int
decodehex(char c)
{
        if (c >= '0' && c <= '9')
                return c - '0';
        else if (c >= 'A' && c <= 'F')
                return c - 'A' + 10;
        else if (c >= 'a' && c <= 'f')
                return c - 'a' + 10;
        return 0;
}

static char
encodehex(int n)
{
        if (n >= 0 && n <= 9)
                return '0' + n;
        if (n >= 10 && n <= 15)
                return 'a' + (n - 10);
        return '?';
}

static int
_nameextract(uchar *base, uchar *p, uchar *ep, int k, uchar *outbuf, int outbufmaxlen, int *outbuflenp)
{
        uchar *op, *oep, *savep;
        savep = p;
        op = outbuf;
        oep = outbuf + outbufmaxlen;
        for (;;) {
                uchar b;
                int n;
                if (p >= ep)
                        return 0;
                b = *p++;
                if (b == 0)
                        break;
                if (k) {
                        if (op >= oep)
                                return 0;
                        *op++ = '.';
                }
                if ((b & 0xc0) == 0xc0) {
                        ushort off;
                        if (ep - p < 2)
                                return 0;
                        off = nhgets(p - 1) & 0x3fff; p++;
                        if (_nameextract(base, base + off, p, k, op, oep - ep, &n) == 0)
                                return 0;
                        op += n;
                }
                else if ((b & 0xc0) != 0x00)
                        return 0;
                else if (b != 0x20)
                        return 0;
                else {
                        int x;
                        if (p + b > ep)
                                return 0;
                        if (op + b / 2 > oep)
                                return 0;
                        for (x = 0; x < b; x += 2) {
                                uchar hn, ln;
                                if (*p < 'A' || *p >= 'A' + 16)
                                        return 0;
                                hn = *p++ - 'A';
                                if (*p < 'A' || *p >= 'A' + 16)
                                        return 0;
                                ln = *p++ - 'A';
                                *op++ = (hn << 4) | ln;
                        }
                }
                k++;
        }
        *outbuflenp = op - outbuf;
        return p - savep;
}

int
nbnamedecode(uchar *base, uchar *p, uchar *ep, NbName nbname)
{
        int n;
        int rv = _nameextract(base, p, ep, 0, nbname, NbNameLen, &n);
        if (rv == 0)
                return rv;
        if (n != NbNameLen)
                return 0;
        return rv;
}

int
nbnameencode(uchar *ap, uchar *ep, NbName name)
{
        uchar *p = ap;
        int i;
        if (p + 1 + 2 * NbNameLen + 1 > ep)
                return 0;
        *p++ = NbNameLen * 2;
        for (i = 0; i < NbNameLen; i++) {
                *p++ = 'A' + ((name[i] >> 4) & 0xf);
                *p++ = 'A' + (name[i] & 0xf);
        }
        *p++ = 0;
        return p - ap;
}

void
nbnamecpy(NbName n1, NbName n2)
{
        memcpy(n1, n2, NbNameLen);
}

void
nbmknamefromstring(NbName nbname, char *s)
{
        int i;
        memset(nbname, ' ', NbNameLen - 1);
        nbname[NbNameLen - 1] = 0;
        i = 0;
        while (*s) {
                if (*s == '\\' && *(s + 1) == 'x') {
                        s += 2;
                        if (*s == 0 || *(s + 1) == 0)
                                return;
                        nbname[NbNameLen - 1] = (decodehex(s[0]) << 4) | decodehex(s[1]);
                        return;
                } else {
                        if (i < NbNameLen - 1)
                                nbname[i++] = toupper(*s);
                        s++;
                }
        }
}

void
nbmknamefromstringandtype(NbName nbname, char *s, uchar type)
{
        nbmknamefromstring(nbname, s);
        nbname[NbNameLen - 1] = type;
}

void
nbmkstringfromname(char *buf, int buflen, NbName name)
{
        int x;
        for (x = 0; x < NbNameLen - 1; x++) {
                if (name[x] == ' ')
                        break;
                if (buflen > 1) {
                        *buf++ = tolower(name[x]);
                        buflen--;
                }
        }
        if (name[NbNameLen - 1] != 0) {
                if (buflen > 1) {
                        *buf++ = '\\';
                        buflen--;
                }
                if (buflen > 1) {
                        *buf++ = 'x';
                        buflen--;
                }
                if (buflen > 1) {
                        *buf++ = encodehex(name[NbNameLen - 1] >> 4);
                        buflen--;
                }
                if (buflen > 1)
                        *buf++ = encodehex(name[NbNameLen - 1] & 0x0f);
        }
        *buf = 0;
}

int
nbnameisany(NbName name)
{
        return name[0] == '*';
}

int
nbnameequal(NbName name1, NbName name2)
{
        if (name1[NbNameLen - 1] != name2[NbNameLen - 1])
                return 0;
        if (nbnameisany(name1))
                return 1;
        if (nbnameisany(name2))
                return 1;
        return memcmp(name1, name2, NbNameLen - 1) == 0;
}

int
nbnamefmt(Fmt *f)
{
        uchar *n;
        char buf[100];
        n = va_arg(f->args, uchar *);
        nbmkstringfromname(buf, sizeof(buf), n);
        return fmtstrcpy(f, buf);
}

typedef struct NbNameTableEntry NbNameTableEntry;
struct NbNameTableEntry {
        NbName name;
        NbNameTableEntry *next;
};

static struct {
        QLock;
        NbNameTableEntry *head;
} nbnametable;

int
nbnametablefind(NbName name, int add)
{
        int rv;
        NbNameTableEntry *p;
        qlock(&nbnametable);
        for (p = nbnametable.head; p; p = p->next) {
                if (nbnameequal(p->name, name)) {
                        qunlock(&nbnametable);
                        return 1;
                }
        }
        if (add) {
                p = nbemalloc(sizeof(*p));
                nbnamecpy(p->name, name);
                p->next = nbnametable.head;
                nbnametable.head = p;
                rv = 1;
        }
        else
                rv = 0;
        qunlock(&nbnametable);
        return rv;
}

typedef struct NbRemoteNameTableEntry NbRemoteNameTableEntry;
struct NbRemoteNameTableEntry {
        NbName name;
        char ipaddr[IPaddrlen];
        long expire;
        NbRemoteNameTableEntry *next;
};

static struct {
        QLock;
        NbRemoteNameTableEntry *head;
} nbremotenametable;

int
nbremotenametablefind(NbName name, uchar *ipaddr)
{
        NbRemoteNameTableEntry *p, **pp;
        long now = time(nil);
        qlock(&nbremotenametable);
        for (pp = &nbremotenametable.head; (p = *pp) != nil;) {
                if (p->expire <= now) {
//print("nbremotenametablefind: expired %B\n", p->name);
                        *pp = p->next;
                        free(p);
                        continue;
                }
                if (nbnameequal(p->name, name)) {
                        ipmove(ipaddr, p->ipaddr);
                        qunlock(&nbremotenametable);
                        return 1;
                }
                pp = &p->next;
        }
        qunlock(&nbremotenametable);
        return 0;
}

int
nbremotenametableadd(NbName name, uchar *ipaddr, ulong ttl)
{
        NbRemoteNameTableEntry *p;
        qlock(&nbremotenametable);
        for (p = nbremotenametable.head; p; p = p->next)
                if (nbnameequal(p->name, name))
                        break;
        if (p == nil) {
                p = nbemalloc(sizeof(*p));
                p->next = nbremotenametable.head;
                nbremotenametable.head = p;
                nbnamecpy(p->name, name);
        }
        ipmove(p->ipaddr, ipaddr);
        p->expire = time(nil) + ttl;
//print("nbremotenametableadd: %B ttl %lud expire %ld\n", p->name, ttl, p->expire);
        qunlock(&nbremotenametable);
        return 1;
}