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 QLock;
24 Listen *head;
25 } listens;
26
27 static void
udplistener(void *)28 udplistener(void *)
29 {
30 //print("udplistener - starting\n");
31 for (;;) {
32 uchar msg[Udphdrsize + 576];
33 int len = read(udp.fd, msg, sizeof(msg));
34 if (len < 0)
35 break;
36 if (len >= nbudphdrsize) {
37 NbDgram s;
38 // Udphdr *uh;
39 uchar *p;
40 int n;
41
42 // uh = (Udphdr*)msg;
43 p = msg + nbudphdrsize;
44 len -= nbudphdrsize;
45 n = nbdgramconvM2S(&s, p, p + len);
46 if (n) {
47 switch (s.type) {
48 case NbDgramError:
49 print("nbdgramlisten: error: ip %I port %d code 0x%.2ux\n", s.srcip, s.srcport, s.error.code);
50 break;
51 case NbDgramDirectUnique:
52 case NbDgramDirectGroup:
53 case NbDgramBroadcast: {
54 int delivered = 0;
55 Listen **lp, *l;
56 if ((s.flags & NbDgramMore) || s.datagram.offset != 0)
57 break;
58 if (!nbnameisany(s.datagram.dstname)
59 && !nbnametablefind(s.datagram.dstname, 0)) {
60 /* - only do this if a broadcast node, and can tell when packets are broadcast...
61 s.flags &= 3;
62 ipmove(s.srcip, nbglobals.myipaddr);
63 s.srcport = NbDgramPort;
64 s.type = NbDgramError;
65 s.error.code = NbDgramErrorDestinationNameNotPresent;
66 nbdgramsendto(uh->raddr, nhgets(uh->rport), &s);
67 */
68 break;
69 }
70 qlock(&listens);
71 for (lp = &listens.head; (l = *lp) != nil;) {
72 if (nbnameisany(l->to) || nbnameequal(l->to, s.datagram.dstname)) {
73 switch ((*l->deliver)(l->magic, &s)) {
74 case 0:
75 delivered = 1;
76 /* fall through */
77 case -1:
78 *lp = l->next;
79 free(l);
80 continue;
81 default:
82 delivered = 1;
83 break;
84 }
85 }
86 lp = &l->next;
87 }
88 qunlock(&listens);
89 USED(delivered);
90 }
91 default:
92 ;
93 }
94 }
95 }
96 }
97 print("udplistener - exiting\n");
98 qlock(&udp);
99 udp.thread = -1;
100 qunlock(&udp);
101 }
102
103 static char *
startlistener(void)104 startlistener(void)
105 {
106 qlock(&udp);
107 if (udp.thread < 0) {
108 char *e;
109 e = nbudpannounce(NbDgramPort, &udp.fd);
110 if (e) {
111 qunlock(&udp);
112 return e;
113 }
114 udp.thread = proccreate(udplistener, nil, 16384);
115 }
116 qunlock(&udp);
117 return nil;
118 }
119
120 char *
nbdgramlisten(NbName to,int (* deliver)(void * magic,NbDgram * s),void * magic)121 nbdgramlisten(NbName to, int (*deliver)(void *magic, NbDgram *s), void *magic)
122 {
123 Listen *l;
124 char *e;
125 nbnametablefind(to, 1);
126 e = startlistener();
127 if (e)
128 return e;
129 l = nbemalloc(sizeof(Listen));
130 nbnamecpy(l->to, to);
131 l->deliver = deliver;
132 l->magic = magic;
133 qlock(&listens);
134 l->next = listens.head;
135 listens.head = l;
136 qunlock(&listens);
137 return 0;
138 }
139
140 int
nbdgramsendto(uchar * ipaddr,ushort port,NbDgram * s)141 nbdgramsendto(uchar *ipaddr, ushort port, NbDgram *s)
142 {
143 Udphdr *u;
144 uchar msg[NbDgramMaxPacket + Udphdrsize];
145 int l;
146 int rv;
147 char *e;
148
149 e = startlistener();
150 if (e != nil)
151 return 0;
152
153 l = nbdgramconvS2M(msg + nbudphdrsize, msg + sizeof(msg), s);
154 if (l == 0) {
155 print("conv failed\n");
156 return 0;
157 }
158 u = (Udphdr *)msg;
159 ipmove(u->laddr, nbglobals.myipaddr);
160 hnputs(u->lport, NbDgramPort);
161 ipmove(u->raddr, ipaddr);
162 hnputs(u->rport, port);
163 //nbdumpdata(msg, l + nbudphdrsize);
164 //print("transmitting\n");
165 rv = write(udp.fd, msg, l + nbudphdrsize);
166 //print("rv %d l %d hdrsize %d error %r\n", rv, l, nbudphdrsize);
167 return rv == l + nbudphdrsize;
168 }
169
170 static struct {
171 Lock;
172 ushort id;
173 } id;
174
175 static ushort
nextdgramid(void)176 nextdgramid(void)
177 {
178 ushort v;
179 lock(&id);
180 v = id.id++;
181 unlock(&id);
182 return v;
183 }
184
185 int
nbdgramsend(NbDgramSendParameters * p,uchar * data,long datalen)186 nbdgramsend(NbDgramSendParameters *p, uchar *data, long datalen)
187 {
188 NbDgram s;
189 uchar dstip[IPaddrlen];
190 s.type = p->type;
191 switch (p->type) {
192 case NbDgramBroadcast:
193 case NbDgramDirectGroup:
194 ipmove(dstip, nbglobals.bcastaddr);
195 break;
196 case NbDgramDirectUnique:
197 if (!nbnameresolve(p->to, dstip)) {
198 werrstr("nbdgramsend: name resolution failed");
199 return 0;
200 }
201 break;
202 default:
203 werrstr("nbdgramsend: illegal datagram type");
204 return 0;
205 }
206 s.flags = NbDgramFirst;
207 s.id = nextdgramid();
208 ipmove(s.srcip, nbglobals.myipaddr);
209 s.srcport = NbDgramPort;
210 s.datagram.offset = 0;
211 s.datagram.data = data;
212 s.datagram.length = datalen;
213 nbnamecpy(s.datagram.dstname, p->to);
214 nbnamecpy(s.datagram.srcname, nbglobals.myname);
215 return nbdgramsendto(dstip, NbDgramPort, &s);
216 }
217