1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <ip.h>
4*8ccd4a63SDavid du Colombier #include <thread.h>
5*8ccd4a63SDavid du Colombier #include "netbios.h"
6*8ccd4a63SDavid du Colombier
7*8ccd4a63SDavid du Colombier void
nbnsmessagequestionfree(NbnsMessageQuestion ** qp)8*8ccd4a63SDavid du Colombier nbnsmessagequestionfree(NbnsMessageQuestion **qp)
9*8ccd4a63SDavid du Colombier {
10*8ccd4a63SDavid du Colombier NbnsMessageQuestion *q = *qp;
11*8ccd4a63SDavid du Colombier if (q) {
12*8ccd4a63SDavid du Colombier free(q);
13*8ccd4a63SDavid du Colombier *qp = nil;
14*8ccd4a63SDavid du Colombier }
15*8ccd4a63SDavid du Colombier }
16*8ccd4a63SDavid du Colombier
17*8ccd4a63SDavid du Colombier void
nbnsmessageresourcefree(NbnsMessageResource ** rp)18*8ccd4a63SDavid du Colombier nbnsmessageresourcefree(NbnsMessageResource **rp)
19*8ccd4a63SDavid du Colombier {
20*8ccd4a63SDavid du Colombier NbnsMessageResource *r = *rp;
21*8ccd4a63SDavid du Colombier if (r) {
22*8ccd4a63SDavid du Colombier free(r->rdata);
23*8ccd4a63SDavid du Colombier free(r);
24*8ccd4a63SDavid du Colombier *rp = nil;
25*8ccd4a63SDavid du Colombier }
26*8ccd4a63SDavid du Colombier }
27*8ccd4a63SDavid du Colombier
28*8ccd4a63SDavid du Colombier static void
questionfree(NbnsMessageQuestion ** qp)29*8ccd4a63SDavid du Colombier questionfree(NbnsMessageQuestion **qp)
30*8ccd4a63SDavid du Colombier {
31*8ccd4a63SDavid du Colombier while (*qp) {
32*8ccd4a63SDavid du Colombier NbnsMessageQuestion *next = (*qp)->next;
33*8ccd4a63SDavid du Colombier nbnsmessagequestionfree(qp);
34*8ccd4a63SDavid du Colombier *qp = next;
35*8ccd4a63SDavid du Colombier }
36*8ccd4a63SDavid du Colombier }
37*8ccd4a63SDavid du Colombier
38*8ccd4a63SDavid du Colombier static void
resourcefree(NbnsMessageResource ** rp)39*8ccd4a63SDavid du Colombier resourcefree(NbnsMessageResource **rp)
40*8ccd4a63SDavid du Colombier {
41*8ccd4a63SDavid du Colombier while (*rp) {
42*8ccd4a63SDavid du Colombier NbnsMessageResource *next = (*rp)->next;
43*8ccd4a63SDavid du Colombier nbnsmessageresourcefree(rp);
44*8ccd4a63SDavid du Colombier *rp = next;
45*8ccd4a63SDavid du Colombier }
46*8ccd4a63SDavid du Colombier }
47*8ccd4a63SDavid du Colombier
48*8ccd4a63SDavid du Colombier void
nbnsmessagefree(NbnsMessage ** sp)49*8ccd4a63SDavid du Colombier nbnsmessagefree(NbnsMessage **sp)
50*8ccd4a63SDavid du Colombier {
51*8ccd4a63SDavid du Colombier NbnsMessage *s = *sp;
52*8ccd4a63SDavid du Colombier if (s) {
53*8ccd4a63SDavid du Colombier questionfree(&s->q);
54*8ccd4a63SDavid du Colombier resourcefree(&s->an);
55*8ccd4a63SDavid du Colombier resourcefree(&s->ns);
56*8ccd4a63SDavid du Colombier resourcefree(&s->ar);
57*8ccd4a63SDavid du Colombier free(s);
58*8ccd4a63SDavid du Colombier *sp = nil;
59*8ccd4a63SDavid du Colombier }
60*8ccd4a63SDavid du Colombier }
61*8ccd4a63SDavid du Colombier
62*8ccd4a63SDavid du Colombier void
nbnsmessageaddquestion(NbnsMessage * s,NbnsMessageQuestion * q)63*8ccd4a63SDavid du Colombier nbnsmessageaddquestion(NbnsMessage *s, NbnsMessageQuestion *q)
64*8ccd4a63SDavid du Colombier {
65*8ccd4a63SDavid du Colombier NbnsMessageQuestion **qp;
66*8ccd4a63SDavid du Colombier for (qp = &s->q; *qp; qp = &(*qp)->next)
67*8ccd4a63SDavid du Colombier ;
68*8ccd4a63SDavid du Colombier *qp = q;
69*8ccd4a63SDavid du Colombier }
70*8ccd4a63SDavid du Colombier
71*8ccd4a63SDavid du Colombier NbnsMessageQuestion *
nbnsmessagequestionnew(NbName name,ushort type,ushort class)72*8ccd4a63SDavid du Colombier nbnsmessagequestionnew(NbName name, ushort type, ushort class)
73*8ccd4a63SDavid du Colombier {
74*8ccd4a63SDavid du Colombier NbnsMessageQuestion *q;
75*8ccd4a63SDavid du Colombier q = mallocz(sizeof(*q), 1);
76*8ccd4a63SDavid du Colombier if (q == nil)
77*8ccd4a63SDavid du Colombier return nil;
78*8ccd4a63SDavid du Colombier nbnamecpy(q->name, name);
79*8ccd4a63SDavid du Colombier q->type = type;
80*8ccd4a63SDavid du Colombier q->class = class;
81*8ccd4a63SDavid du Colombier return q;
82*8ccd4a63SDavid du Colombier }
83*8ccd4a63SDavid du Colombier
84*8ccd4a63SDavid du Colombier NbnsMessageResource *
nbnsmessageresourcenew(NbName name,ushort type,ushort class,ulong ttl,int rdlength,uchar * rdata)85*8ccd4a63SDavid du Colombier nbnsmessageresourcenew(NbName name, ushort type, ushort class, ulong ttl, int rdlength, uchar *rdata)
86*8ccd4a63SDavid du Colombier {
87*8ccd4a63SDavid du Colombier NbnsMessageResource *r;
88*8ccd4a63SDavid du Colombier r= mallocz(sizeof(*r), 1);
89*8ccd4a63SDavid du Colombier if (r == nil)
90*8ccd4a63SDavid du Colombier return nil;
91*8ccd4a63SDavid du Colombier nbnamecpy(r->name, name);
92*8ccd4a63SDavid du Colombier r->type = type;
93*8ccd4a63SDavid du Colombier r->class = class;
94*8ccd4a63SDavid du Colombier r->ttl = ttl;
95*8ccd4a63SDavid du Colombier r->rdlength = rdlength;
96*8ccd4a63SDavid du Colombier if (rdlength) {
97*8ccd4a63SDavid du Colombier r->rdata = malloc(rdlength);
98*8ccd4a63SDavid du Colombier if (r->rdata == nil) {
99*8ccd4a63SDavid du Colombier free(r);
100*8ccd4a63SDavid du Colombier return nil;
101*8ccd4a63SDavid du Colombier }
102*8ccd4a63SDavid du Colombier memcpy(r->rdata, rdata, rdlength);
103*8ccd4a63SDavid du Colombier }
104*8ccd4a63SDavid du Colombier return r;
105*8ccd4a63SDavid du Colombier }
106*8ccd4a63SDavid du Colombier
107*8ccd4a63SDavid du Colombier void
nbnsmessageaddresource(NbnsMessageResource ** rp,NbnsMessageResource * r)108*8ccd4a63SDavid du Colombier nbnsmessageaddresource(NbnsMessageResource **rp, NbnsMessageResource *r)
109*8ccd4a63SDavid du Colombier {
110*8ccd4a63SDavid du Colombier for (; *rp; rp = &(*rp)->next)
111*8ccd4a63SDavid du Colombier ;
112*8ccd4a63SDavid du Colombier *rp = r;
113*8ccd4a63SDavid du Colombier }
114*8ccd4a63SDavid du Colombier
115*8ccd4a63SDavid du Colombier NbnsMessage *
nbnsmessagenew(void)116*8ccd4a63SDavid du Colombier nbnsmessagenew(void)
117*8ccd4a63SDavid du Colombier {
118*8ccd4a63SDavid du Colombier return mallocz(sizeof(NbnsMessage), 1);
119*8ccd4a63SDavid du Colombier }
120*8ccd4a63SDavid du Colombier
121*8ccd4a63SDavid du Colombier static int
resourcedecode(NbnsMessageResource ** headp,int count,uchar * ap,uchar * pp,uchar * ep)122*8ccd4a63SDavid du Colombier resourcedecode(NbnsMessageResource **headp, int count, uchar *ap, uchar *pp, uchar *ep)
123*8ccd4a63SDavid du Colombier {
124*8ccd4a63SDavid du Colombier uchar *p = pp;
125*8ccd4a63SDavid du Colombier int i;
126*8ccd4a63SDavid du Colombier for (i = 0; i < count; i++) {
127*8ccd4a63SDavid du Colombier int n;
128*8ccd4a63SDavid du Colombier NbnsMessageResource *r, **rp;
129*8ccd4a63SDavid du Colombier r = mallocz(sizeof(NbnsMessageResource), 1);
130*8ccd4a63SDavid du Colombier if (r == nil)
131*8ccd4a63SDavid du Colombier return -1;
132*8ccd4a63SDavid du Colombier for (rp = headp; *rp; rp = &(*rp)->next)
133*8ccd4a63SDavid du Colombier ;
134*8ccd4a63SDavid du Colombier *rp = r;
135*8ccd4a63SDavid du Colombier n = nbnamedecode(ap, p, ep, r->name);
136*8ccd4a63SDavid du Colombier if (n == 0)
137*8ccd4a63SDavid du Colombier return -1;
138*8ccd4a63SDavid du Colombier p += n;
139*8ccd4a63SDavid du Colombier if (p + 10 > ep)
140*8ccd4a63SDavid du Colombier return -1;
141*8ccd4a63SDavid du Colombier r->type = nhgets(p); p += 2;
142*8ccd4a63SDavid du Colombier r->class = nhgets(p); p += 2;
143*8ccd4a63SDavid du Colombier r->ttl = nhgetl(p); p += 4;
144*8ccd4a63SDavid du Colombier r->rdlength = nhgets(p); p += 2;
145*8ccd4a63SDavid du Colombier //print("rdlength %d\n", r->rdlength);
146*8ccd4a63SDavid du Colombier if (r->rdlength) {
147*8ccd4a63SDavid du Colombier if (p + r->rdlength > ep)
148*8ccd4a63SDavid du Colombier return -1;
149*8ccd4a63SDavid du Colombier r->rdata = malloc(r->rdlength);
150*8ccd4a63SDavid du Colombier if (r == nil)
151*8ccd4a63SDavid du Colombier return -1;
152*8ccd4a63SDavid du Colombier memcpy(r->rdata, p, r->rdlength);
153*8ccd4a63SDavid du Colombier p += r->rdlength;
154*8ccd4a63SDavid du Colombier }
155*8ccd4a63SDavid du Colombier }
156*8ccd4a63SDavid du Colombier return p - pp;
157*8ccd4a63SDavid du Colombier }
158*8ccd4a63SDavid du Colombier
159*8ccd4a63SDavid du Colombier NbnsMessage *
nbnsconvM2S(uchar * ap,int nap)160*8ccd4a63SDavid du Colombier nbnsconvM2S(uchar *ap, int nap)
161*8ccd4a63SDavid du Colombier {
162*8ccd4a63SDavid du Colombier uchar *p, *ep;
163*8ccd4a63SDavid du Colombier ushort qdcount, ancount, nscount, arcount, ctrl;
164*8ccd4a63SDavid du Colombier int i;
165*8ccd4a63SDavid du Colombier NbnsMessage *s;
166*8ccd4a63SDavid du Colombier int n;
167*8ccd4a63SDavid du Colombier
168*8ccd4a63SDavid du Colombier if (nap < 12)
169*8ccd4a63SDavid du Colombier return nil;
170*8ccd4a63SDavid du Colombier p = ap;
171*8ccd4a63SDavid du Colombier ep = ap + nap;
172*8ccd4a63SDavid du Colombier s = nbnsmessagenew();
173*8ccd4a63SDavid du Colombier if (s == nil)
174*8ccd4a63SDavid du Colombier return nil;
175*8ccd4a63SDavid du Colombier s->id = nhgets(p); p+= 2;
176*8ccd4a63SDavid du Colombier ctrl = nhgets(p); p += 2;
177*8ccd4a63SDavid du Colombier qdcount = nhgets(p); p += 2;
178*8ccd4a63SDavid du Colombier ancount = nhgets(p); p += 2;
179*8ccd4a63SDavid du Colombier nscount = nhgets(p); p += 2;
180*8ccd4a63SDavid du Colombier arcount = nhgets(p); p += 2;
181*8ccd4a63SDavid du Colombier s->response = (ctrl & NbnsResponse) != 0;
182*8ccd4a63SDavid du Colombier s->opcode = (ctrl >> NbnsOpShift) & NbnsOpMask;
183*8ccd4a63SDavid du Colombier s->broadcast = (ctrl & NbnsFlagBroadcast) != 0;
184*8ccd4a63SDavid du Colombier s->recursionavailable = (ctrl & NbnsFlagRecursionAvailable) != 0;
185*8ccd4a63SDavid du Colombier s->recursiondesired = (ctrl & NbnsFlagRecursionDesired) != 0;
186*8ccd4a63SDavid du Colombier s->truncation = (ctrl & NbnsFlagTruncation) != 0;
187*8ccd4a63SDavid du Colombier s->authoritativeanswer = (ctrl & NbnsFlagAuthoritativeAnswer) != 0;
188*8ccd4a63SDavid du Colombier s->rcode = s->response ? (ctrl & NbnsRcodeMask) : 0;
189*8ccd4a63SDavid du Colombier for (i = 0; i < qdcount; i++) {
190*8ccd4a63SDavid du Colombier int n;
191*8ccd4a63SDavid du Colombier NbName nbname;
192*8ccd4a63SDavid du Colombier NbnsMessageQuestion *q;
193*8ccd4a63SDavid du Colombier ushort type, class;
194*8ccd4a63SDavid du Colombier n = nbnamedecode(ap, p, ep, nbname);
195*8ccd4a63SDavid du Colombier if (n == 0)
196*8ccd4a63SDavid du Colombier goto fail;
197*8ccd4a63SDavid du Colombier p += n;
198*8ccd4a63SDavid du Colombier if (p + 4 > ep)
199*8ccd4a63SDavid du Colombier goto fail;
200*8ccd4a63SDavid du Colombier type = nhgets(p); p += 2;
201*8ccd4a63SDavid du Colombier class = nhgets(p); p += 2;
202*8ccd4a63SDavid du Colombier q = nbnsmessagequestionnew(nbname, type, class);
203*8ccd4a63SDavid du Colombier if (q == nil)
204*8ccd4a63SDavid du Colombier goto fail;
205*8ccd4a63SDavid du Colombier nbnsmessageaddquestion(s, q);
206*8ccd4a63SDavid du Colombier }
207*8ccd4a63SDavid du Colombier n = resourcedecode(&s->an, ancount, ap, p, ep);
208*8ccd4a63SDavid du Colombier if (n < 0)
209*8ccd4a63SDavid du Colombier goto fail;
210*8ccd4a63SDavid du Colombier p += n;
211*8ccd4a63SDavid du Colombier n = resourcedecode(&s->ns, nscount, ap, p, ep);
212*8ccd4a63SDavid du Colombier if (n < 0)
213*8ccd4a63SDavid du Colombier goto fail;
214*8ccd4a63SDavid du Colombier p += n;
215*8ccd4a63SDavid du Colombier n = resourcedecode(&s->ar, arcount, ap, p, ep);
216*8ccd4a63SDavid du Colombier if (n < 0)
217*8ccd4a63SDavid du Colombier goto fail;
218*8ccd4a63SDavid du Colombier //print("arcount %d\n", arcount);
219*8ccd4a63SDavid du Colombier return s;
220*8ccd4a63SDavid du Colombier fail:
221*8ccd4a63SDavid du Colombier nbnsmessagefree(&s);
222*8ccd4a63SDavid du Colombier return nil;
223*8ccd4a63SDavid du Colombier }
224*8ccd4a63SDavid du Colombier
225*8ccd4a63SDavid du Colombier static int
resourceencode(NbnsMessageResource * r,uchar * ap,uchar * ep)226*8ccd4a63SDavid du Colombier resourceencode(NbnsMessageResource *r, uchar *ap, uchar *ep)
227*8ccd4a63SDavid du Colombier {
228*8ccd4a63SDavid du Colombier uchar *p = ap;
229*8ccd4a63SDavid du Colombier for (; r; r = r->next) {
230*8ccd4a63SDavid du Colombier int n = nbnameencode(p, ep, r->name);
231*8ccd4a63SDavid du Colombier if (n == 0)
232*8ccd4a63SDavid du Colombier return -1;
233*8ccd4a63SDavid du Colombier p += n;
234*8ccd4a63SDavid du Colombier if (p + 10 > ep)
235*8ccd4a63SDavid du Colombier return -1;
236*8ccd4a63SDavid du Colombier hnputs(p, r->type); p += 2;
237*8ccd4a63SDavid du Colombier hnputs(p, r->class); p += 2;
238*8ccd4a63SDavid du Colombier hnputl(p, r->ttl); p += 4;
239*8ccd4a63SDavid du Colombier hnputs(p, r->rdlength); p += 2;
240*8ccd4a63SDavid du Colombier if (p + r->rdlength > ep)
241*8ccd4a63SDavid du Colombier return -1;
242*8ccd4a63SDavid du Colombier memcpy(p, r->rdata, r->rdlength);
243*8ccd4a63SDavid du Colombier p += r->rdlength;
244*8ccd4a63SDavid du Colombier }
245*8ccd4a63SDavid du Colombier return p - ap;
246*8ccd4a63SDavid du Colombier }
247*8ccd4a63SDavid du Colombier
248*8ccd4a63SDavid du Colombier int
nbnsconvS2M(NbnsMessage * s,uchar * ap,int nap)249*8ccd4a63SDavid du Colombier nbnsconvS2M(NbnsMessage *s, uchar *ap, int nap)
250*8ccd4a63SDavid du Colombier {
251*8ccd4a63SDavid du Colombier uchar *p = ap;
252*8ccd4a63SDavid du Colombier uchar *ep = ap + nap;
253*8ccd4a63SDavid du Colombier ushort ctrl;
254*8ccd4a63SDavid du Colombier NbnsMessageQuestion *q;
255*8ccd4a63SDavid du Colombier NbnsMessageResource *r;
256*8ccd4a63SDavid du Colombier int k;
257*8ccd4a63SDavid du Colombier int n;
258*8ccd4a63SDavid du Colombier
259*8ccd4a63SDavid du Colombier if (p + 12 > ep)
260*8ccd4a63SDavid du Colombier return 0;
261*8ccd4a63SDavid du Colombier hnputs(p, s->id); p+= 2;
262*8ccd4a63SDavid du Colombier ctrl = (s->opcode & NbnsOpMask) << NbnsOpShift;
263*8ccd4a63SDavid du Colombier if (s->response) {
264*8ccd4a63SDavid du Colombier ctrl |= s->rcode & NbnsRcodeMask;
265*8ccd4a63SDavid du Colombier ctrl |= NbnsResponse;
266*8ccd4a63SDavid du Colombier }
267*8ccd4a63SDavid du Colombier if (s->broadcast)
268*8ccd4a63SDavid du Colombier ctrl |= NbnsFlagBroadcast;
269*8ccd4a63SDavid du Colombier if (s->recursionavailable)
270*8ccd4a63SDavid du Colombier ctrl |= NbnsFlagRecursionAvailable;
271*8ccd4a63SDavid du Colombier if (s->recursiondesired)
272*8ccd4a63SDavid du Colombier ctrl |= NbnsFlagRecursionDesired;
273*8ccd4a63SDavid du Colombier if (s->truncation)
274*8ccd4a63SDavid du Colombier ctrl |= NbnsFlagTruncation;
275*8ccd4a63SDavid du Colombier if (s->authoritativeanswer)
276*8ccd4a63SDavid du Colombier ctrl |= NbnsFlagAuthoritativeAnswer;
277*8ccd4a63SDavid du Colombier hnputs(p, ctrl); p += 2;
278*8ccd4a63SDavid du Colombier for (q = s->q, k = 0; q; k++, q = q->next)
279*8ccd4a63SDavid du Colombier ;
280*8ccd4a63SDavid du Colombier hnputs(p, k); p += 2;
281*8ccd4a63SDavid du Colombier for (r = s->an, k = 0; r; k++, r = r->next)
282*8ccd4a63SDavid du Colombier ;
283*8ccd4a63SDavid du Colombier hnputs(p, k); p += 2;
284*8ccd4a63SDavid du Colombier for (r = s->ns, k = 0; r; k++, r = r->next)
285*8ccd4a63SDavid du Colombier ;
286*8ccd4a63SDavid du Colombier hnputs(p, k); p += 2;
287*8ccd4a63SDavid du Colombier for (r = s->ar, k = 0; r; k++, r = r->next)
288*8ccd4a63SDavid du Colombier ;
289*8ccd4a63SDavid du Colombier hnputs(p, k); p += 2;
290*8ccd4a63SDavid du Colombier for (q = s->q; q; q = q->next) {
291*8ccd4a63SDavid du Colombier int n = nbnameencode(p, ep, q->name);
292*8ccd4a63SDavid du Colombier if (n == 0)
293*8ccd4a63SDavid du Colombier return 0;
294*8ccd4a63SDavid du Colombier p += n;
295*8ccd4a63SDavid du Colombier if (p + 4 > ep)
296*8ccd4a63SDavid du Colombier return 0;
297*8ccd4a63SDavid du Colombier hnputs(p, q->type); p += 2;
298*8ccd4a63SDavid du Colombier hnputs(p, q->class); p += 2;
299*8ccd4a63SDavid du Colombier }
300*8ccd4a63SDavid du Colombier n = resourceencode(s->an, p, ep);
301*8ccd4a63SDavid du Colombier if (n < 0)
302*8ccd4a63SDavid du Colombier return 0;
303*8ccd4a63SDavid du Colombier p += n;
304*8ccd4a63SDavid du Colombier n = resourceencode(s->ns, p, ep);
305*8ccd4a63SDavid du Colombier if (n < 0)
306*8ccd4a63SDavid du Colombier return 0;
307*8ccd4a63SDavid du Colombier p += n;
308*8ccd4a63SDavid du Colombier n = resourceencode(s->ar, p, ep);
309*8ccd4a63SDavid du Colombier if (n < 0)
310*8ccd4a63SDavid du Colombier return 0;
311*8ccd4a63SDavid du Colombier p += n;
312*8ccd4a63SDavid du Colombier return p - ap;
313*8ccd4a63SDavid du Colombier }
314*8ccd4a63SDavid du Colombier
315