1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <thread.h>
5 #include "netbios.h"
6
7 static struct {
8 int thread;
9 QLock;
10 int fd;
11 } udp = { -1 };
12
13 typedef struct Listen Listen;
14
15 struct Listen {
16 NbName to;
17 int (*deliver)(void *magic, NbDgram *s);
18 void *magic;
19 Listen *next;
20 };
21
22 static struct {
23 Lock;
24 ushort id;
25 } id;
26
27 struct {
28 QLock;
29 NbnsTransaction *head;
30 } transactionlist;
31
32 static void
udplistener(void *)33 udplistener(void *)
34 {
35 for (;;) {
36 uchar msg[Udphdrsize + 576];
37 int len = read(udp.fd, msg, sizeof(msg));
38 if (len < 0)
39 break;
40 if (len >= nbudphdrsize) {
41 NbnsMessage *s;
42 // Udphdr *uh;
43 uchar *p;
44
45 // uh = (Udphdr*)msg;
46 p = msg + nbudphdrsize;
47 len -= nbudphdrsize;
48 s = nbnsconvM2S(p, len);
49 if (s) {
50 //print("%I:%d -> %I:%d\n", uh->raddr, nhgets(uh->rport), uh->laddr, nhgets(uh->lport));
51 //nbnsdumpmessage(s);
52 if (s->response) {
53 NbnsTransaction *t;
54 qlock(&transactionlist);
55 for (t = transactionlist.head; t; t = t->next)
56 if (t->id == s->id)
57 break;
58 if (t)
59 sendp(t->c, s);
60 else
61 nbnsmessagefree(&s);
62 qunlock(&transactionlist);
63 }
64 else
65 nbnsmessagefree(&s);
66 }
67 }
68 }
69 }
70
71 static char *
startlistener(void)72 startlistener(void)
73 {
74 qlock(&udp);
75 if (udp.thread < 0) {
76 char *e;
77 e = nbudpannounce(NbnsPort, &udp.fd);
78 if (e) {
79 qunlock(&udp);
80 return e;
81 }
82 udp.thread = proccreate(udplistener, nil, 16384);
83 }
84 qunlock(&udp);
85 return nil;
86 }
87
88 ushort
nbnsnextid(void)89 nbnsnextid(void)
90 {
91 ushort rv;
92 lock(&id);
93 rv = id.id++;
94 unlock(&id);
95 return rv;
96 }
97
98 NbnsTransaction *
nbnstransactionnew(NbnsMessage * s,uchar * ipaddr)99 nbnstransactionnew(NbnsMessage *s, uchar *ipaddr)
100 {
101 NbnsTransaction *t;
102 uchar msg[Udphdrsize + 576];
103 Udphdr *u;
104 int len;
105
106 startlistener();
107 len = nbnsconvS2M(s, msg + nbudphdrsize, sizeof(msg) - nbudphdrsize);
108 if (len == 0)
109 return 0;
110 t = mallocz(sizeof(*t), 1);
111 if (t == nil)
112 return nil;
113 t->id = s->id;
114 t->c = chancreate(sizeof(NbnsMessage *), 3);
115 if (t->c == nil) {
116 free(t);
117 return nil;
118 }
119 qlock(&transactionlist);
120 t->next = transactionlist.head;
121 transactionlist.head = t;
122 qunlock(&transactionlist);
123 u = (Udphdr *)msg;
124 ipmove(u->laddr, nbglobals.myipaddr);
125 hnputs(u->lport, NbnsPort);
126 if (s->broadcast || ipaddr == nil)
127 ipmove(u->raddr, nbglobals.bcastaddr);
128 else
129 ipmove(u->raddr, ipaddr);
130 hnputs(u->rport, NbnsPort);
131 write(udp.fd, msg, len + nbudphdrsize);
132 return t;
133 }
134
135 void
nbnstransactionfree(NbnsTransaction ** tp)136 nbnstransactionfree(NbnsTransaction **tp)
137 {
138 NbnsTransaction **tp2;
139 NbnsMessage *s;
140 NbnsTransaction *t;
141
142 t = *tp;
143 if (t) {
144 qlock(&transactionlist);
145 while ((s = nbrecvp(t->c)) != nil)
146 nbnsmessagefree(&s);
147 for (tp2 = &transactionlist.head; *tp2 && *tp2 != t; tp2 = &(*tp2)->next)
148 ;
149 if (*tp2) {
150 *tp2 = t->next;
151 free(t);
152 }
153 qunlock(&transactionlist);
154 *tp = nil;
155 }
156 }
157