1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <thread.h>
5 #include "netbios.h"
6
7 static int
decodehex(char c)8 decodehex(char c)
9 {
10 if (c >= '0' && c <= '9')
11 return c - '0';
12 else if (c >= 'A' && c <= 'F')
13 return c - 'A' + 10;
14 else if (c >= 'a' && c <= 'f')
15 return c - 'a' + 10;
16 return 0;
17 }
18
19 static char
encodehex(int n)20 encodehex(int n)
21 {
22 if (n >= 0 && n <= 9)
23 return '0' + n;
24 if (n >= 10 && n <= 15)
25 return 'a' + (n - 10);
26 return '?';
27 }
28
29 static int
_nameextract(uchar * base,uchar * p,uchar * ep,int k,uchar * outbuf,int outbufmaxlen,int * outbuflenp)30 _nameextract(uchar *base, uchar *p, uchar *ep, int k, uchar *outbuf, int outbufmaxlen, int *outbuflenp)
31 {
32 uchar *op, *oep, *savep;
33 savep = p;
34 op = outbuf;
35 oep = outbuf + outbufmaxlen;
36 for (;;) {
37 uchar b;
38 int n;
39 if (p >= ep)
40 return 0;
41 b = *p++;
42 if (b == 0)
43 break;
44 if (k) {
45 if (op >= oep)
46 return 0;
47 *op++ = '.';
48 }
49 if ((b & 0xc0) == 0xc0) {
50 ushort off;
51 if (ep - p < 2)
52 return 0;
53 off = nhgets(p - 1) & 0x3fff; p++;
54 if (_nameextract(base, base + off, p, k, op, oep - ep, &n) == 0)
55 return 0;
56 op += n;
57 }
58 else if ((b & 0xc0) != 0x00)
59 return 0;
60 else if (b != 0x20)
61 return 0;
62 else {
63 int x;
64 if (p + b > ep)
65 return 0;
66 if (op + b / 2 > oep)
67 return 0;
68 for (x = 0; x < b; x += 2) {
69 uchar hn, ln;
70 if (*p < 'A' || *p >= 'A' + 16)
71 return 0;
72 hn = *p++ - 'A';
73 if (*p < 'A' || *p >= 'A' + 16)
74 return 0;
75 ln = *p++ - 'A';
76 *op++ = (hn << 4) | ln;
77 }
78 }
79 k++;
80 }
81 *outbuflenp = op - outbuf;
82 return p - savep;
83 }
84
85 int
nbnamedecode(uchar * base,uchar * p,uchar * ep,NbName nbname)86 nbnamedecode(uchar *base, uchar *p, uchar *ep, NbName nbname)
87 {
88 int n;
89 int rv = _nameextract(base, p, ep, 0, nbname, NbNameLen, &n);
90 if (rv == 0)
91 return rv;
92 if (n != NbNameLen)
93 return 0;
94 return rv;
95 }
96
97 int
nbnameencode(uchar * ap,uchar * ep,NbName name)98 nbnameencode(uchar *ap, uchar *ep, NbName name)
99 {
100 uchar *p = ap;
101 int i;
102 if (p + 1 + 2 * NbNameLen + 1 > ep)
103 return 0;
104 *p++ = NbNameLen * 2;
105 for (i = 0; i < NbNameLen; i++) {
106 *p++ = 'A' + ((name[i] >> 4) & 0xf);
107 *p++ = 'A' + (name[i] & 0xf);
108 }
109 *p++ = 0;
110 return p - ap;
111 }
112
113 void
nbnamecpy(NbName n1,NbName n2)114 nbnamecpy(NbName n1, NbName n2)
115 {
116 memcpy(n1, n2, NbNameLen);
117 }
118
119 void
nbmknamefromstring(NbName nbname,char * s)120 nbmknamefromstring(NbName nbname, char *s)
121 {
122 int i;
123 memset(nbname, ' ', NbNameLen - 1);
124 nbname[NbNameLen - 1] = 0;
125 i = 0;
126 while (*s) {
127 if (*s == '\\' && *(s + 1) == 'x') {
128 s += 2;
129 if (*s == 0 || *(s + 1) == 0)
130 return;
131 nbname[NbNameLen - 1] = (decodehex(s[0]) << 4) | decodehex(s[1]);
132 return;
133 } else {
134 if (i < NbNameLen - 1)
135 nbname[i++] = toupper(*s);
136 s++;
137 }
138 }
139 }
140
141 void
nbmknamefromstringandtype(NbName nbname,char * s,uchar type)142 nbmknamefromstringandtype(NbName nbname, char *s, uchar type)
143 {
144 nbmknamefromstring(nbname, s);
145 nbname[NbNameLen - 1] = type;
146 }
147
148 void
nbmkstringfromname(char * buf,int buflen,NbName name)149 nbmkstringfromname(char *buf, int buflen, NbName name)
150 {
151 int x;
152 for (x = 0; x < NbNameLen - 1; x++) {
153 if (name[x] == ' ')
154 break;
155 if (buflen > 1) {
156 *buf++ = tolower(name[x]);
157 buflen--;
158 }
159 }
160 if (name[NbNameLen - 1] != 0) {
161 if (buflen > 1) {
162 *buf++ = '\\';
163 buflen--;
164 }
165 if (buflen > 1) {
166 *buf++ = 'x';
167 buflen--;
168 }
169 if (buflen > 1) {
170 *buf++ = encodehex(name[NbNameLen - 1] >> 4);
171 buflen--;
172 }
173 if (buflen > 1)
174 *buf++ = encodehex(name[NbNameLen - 1] & 0x0f);
175 }
176 *buf = 0;
177 }
178
179 int
nbnameisany(NbName name)180 nbnameisany(NbName name)
181 {
182 return name[0] == '*';
183 }
184
185 int
nbnameequal(NbName name1,NbName name2)186 nbnameequal(NbName name1, NbName name2)
187 {
188 if (name1[NbNameLen - 1] != name2[NbNameLen - 1])
189 return 0;
190 if (nbnameisany(name1))
191 return 1;
192 if (nbnameisany(name2))
193 return 1;
194 return memcmp(name1, name2, NbNameLen - 1) == 0;
195 }
196
197 int
nbnamefmt(Fmt * f)198 nbnamefmt(Fmt *f)
199 {
200 uchar *n;
201 char buf[100];
202 n = va_arg(f->args, uchar *);
203 nbmkstringfromname(buf, sizeof(buf), n);
204 return fmtstrcpy(f, buf);
205 }
206
207 typedef struct NbNameTableEntry NbNameTableEntry;
208 struct NbNameTableEntry {
209 NbName name;
210 NbNameTableEntry *next;
211 };
212
213 static struct {
214 QLock;
215 NbNameTableEntry *head;
216 } nbnametable;
217
218 int
nbnametablefind(NbName name,int add)219 nbnametablefind(NbName name, int add)
220 {
221 int rv;
222 NbNameTableEntry *p;
223 qlock(&nbnametable);
224 for (p = nbnametable.head; p; p = p->next) {
225 if (nbnameequal(p->name, name)) {
226 qunlock(&nbnametable);
227 return 1;
228 }
229 }
230 if (add) {
231 p = nbemalloc(sizeof(*p));
232 nbnamecpy(p->name, name);
233 p->next = nbnametable.head;
234 nbnametable.head = p;
235 rv = 1;
236 }
237 else
238 rv = 0;
239 qunlock(&nbnametable);
240 return rv;
241 }
242
243 typedef struct NbRemoteNameTableEntry NbRemoteNameTableEntry;
244 struct NbRemoteNameTableEntry {
245 NbName name;
246 char ipaddr[IPaddrlen];
247 long expire;
248 NbRemoteNameTableEntry *next;
249 };
250
251 static struct {
252 QLock;
253 NbRemoteNameTableEntry *head;
254 } nbremotenametable;
255
256 int
nbremotenametablefind(NbName name,uchar * ipaddr)257 nbremotenametablefind(NbName name, uchar *ipaddr)
258 {
259 NbRemoteNameTableEntry *p, **pp;
260 long now = time(nil);
261 qlock(&nbremotenametable);
262 for (pp = &nbremotenametable.head; (p = *pp) != nil;) {
263 if (p->expire <= now) {
264 //print("nbremotenametablefind: expired %B\n", p->name);
265 *pp = p->next;
266 free(p);
267 continue;
268 }
269 if (nbnameequal(p->name, name)) {
270 ipmove(ipaddr, p->ipaddr);
271 qunlock(&nbremotenametable);
272 return 1;
273 }
274 pp = &p->next;
275 }
276 qunlock(&nbremotenametable);
277 return 0;
278 }
279
280 int
nbremotenametableadd(NbName name,uchar * ipaddr,ulong ttl)281 nbremotenametableadd(NbName name, uchar *ipaddr, ulong ttl)
282 {
283 NbRemoteNameTableEntry *p;
284 qlock(&nbremotenametable);
285 for (p = nbremotenametable.head; p; p = p->next)
286 if (nbnameequal(p->name, name))
287 break;
288 if (p == nil) {
289 p = nbemalloc(sizeof(*p));
290 p->next = nbremotenametable.head;
291 nbremotenametable.head = p;
292 nbnamecpy(p->name, name);
293 }
294 ipmove(p->ipaddr, ipaddr);
295 p->expire = time(nil) + ttl;
296 //print("nbremotenametableadd: %B ttl %lud expire %ld\n", p->name, ttl, p->expire);
297 qunlock(&nbremotenametable);
298 return 1;
299 }
300