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