Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/error.h"
7
 
8
#include	"ip.h"
9
#include	"ipv6.h"
10
 
11
 
12
#define DPRINT if(0)print
13
 
14
enum
15
{
16
	UDP_UDPHDR_SZ	= 8,
17
 
18
	UDP4_PHDR_OFF = 8,
19
	UDP4_PHDR_SZ = 12,
20
	UDP4_IPHDR_SZ = 20,
21
	UDP6_IPHDR_SZ = 40,
22
	UDP6_PHDR_SZ = 40,
23
	UDP6_PHDR_OFF = 0,
24
 
25
	IP_UDPPROTO	= 17,
26
	UDP_USEAD7	= 52,
27
 
28
	Udprxms		= 200,
29
	Udptickms	= 100,
30
	Udpmaxxmit	= 10,
31
};
32
 
33
typedef struct Udp4hdr Udp4hdr;
34
struct Udp4hdr
35
{
36
	/* ip header */
37
	uchar	vihl;		/* Version and header length */
38
	uchar	tos;		/* Type of service */
39
	uchar	length[2];	/* packet length */
40
	uchar	id[2];		/* Identification */
41
	uchar	frag[2];	/* Fragment information */
42
	uchar	Unused;
43
	uchar	udpproto;	/* Protocol */
44
	uchar	udpplen[2];	/* Header plus data length */
45
	uchar	udpsrc[IPv4addrlen];	/* Ip source */
46
	uchar	udpdst[IPv4addrlen];	/* Ip destination */
47
 
48
	/* udp header */
49
	uchar	udpsport[2];	/* Source port */
50
	uchar	udpdport[2];	/* Destination port */
51
	uchar	udplen[2];	/* data length */
52
	uchar	udpcksum[2];	/* Checksum */
53
};
54
 
55
typedef struct Udp6hdr Udp6hdr;
56
struct Udp6hdr {
57
	uchar viclfl[4];
58
	uchar len[2];
59
	uchar nextheader;
60
	uchar hoplimit;
61
	uchar udpsrc[IPaddrlen];
62
	uchar udpdst[IPaddrlen];
63
 
64
	/* udp header */
65
	uchar	udpsport[2];	/* Source port */
66
	uchar	udpdport[2];	/* Destination port */
67
	uchar	udplen[2];	/* data length */
68
	uchar	udpcksum[2];	/* Checksum */
69
};
70
 
71
/* MIB II counters */
72
typedef struct Udpstats Udpstats;
73
struct Udpstats
74
{
75
	uvlong	udpInDatagrams;
76
	ulong	udpNoPorts;
77
	ulong	udpInErrors;
78
	uvlong	udpOutDatagrams;
79
};
80
 
81
typedef struct Udppriv Udppriv;
82
struct Udppriv
83
{
84
	Ipht		ht;
85
 
86
	/* MIB counters */
87
	Udpstats	ustats;
88
 
89
	/* non-MIB stats */
90
	ulong		csumerr;		/* checksum errors */
91
	ulong		lenerr;			/* short packet */
92
};
93
 
94
void (*etherprofiler)(char *name, int qlen);
95
void udpkick(void *x, Block *bp);
96
 
97
/*
98
 *  protocol specific part of Conv
99
 */
100
typedef struct Udpcb Udpcb;
101
struct Udpcb
102
{
103
	QLock;
104
	uchar	headers;
105
};
106
 
107
static char*
108
udpconnect(Conv *c, char **argv, int argc)
109
{
110
	char *e;
111
	Udppriv *upriv;
112
 
113
	upriv = c->p->priv;
114
	e = Fsstdconnect(c, argv, argc);
115
	Fsconnected(c, e);
116
	if(e != nil)
117
		return e;
118
 
119
	iphtadd(&upriv->ht, c);
120
	return nil;
121
}
122
 
123
 
124
static int
125
udpstate(Conv *c, char *state, int n)
126
{
127
	return snprint(state, n, "%s qin %d qout %d\n",
128
		c->inuse ? "Open" : "Closed",
129
		c->rq ? qlen(c->rq) : 0,
130
		c->wq ? qlen(c->wq) : 0
131
	);
132
}
133
 
134
static char*
135
udpannounce(Conv *c, char** argv, int argc)
136
{
137
	char *e;
138
	Udppriv *upriv;
139
 
140
	upriv = c->p->priv;
141
	e = Fsstdannounce(c, argv, argc);
142
	if(e != nil)
143
		return e;
144
	Fsconnected(c, nil);
145
	iphtadd(&upriv->ht, c);
146
 
147
	return nil;
148
}
149
 
150
static void
151
udpcreate(Conv *c)
152
{
153
	c->rq = qopen(128*1024, Qmsg, 0, 0);
154
	c->wq = qbypass(udpkick, c);
155
}
156
 
157
static void
158
udpclose(Conv *c)
159
{
160
	Udpcb *ucb;
161
	Udppriv *upriv;
162
 
163
	upriv = c->p->priv;
164
	iphtrem(&upriv->ht, c);
165
 
166
	c->state = 0;
167
	qclose(c->rq);
168
	qclose(c->wq);
169
	qclose(c->eq);
170
	ipmove(c->laddr, IPnoaddr);
171
	ipmove(c->raddr, IPnoaddr);
172
	c->lport = 0;
173
	c->rport = 0;
174
 
175
	ucb = (Udpcb*)c->ptcl;
176
	ucb->headers = 0;
177
}
178
 
179
void
180
udpkick(void *x, Block *bp)
181
{
182
	Conv *c = x;
183
	Udp4hdr *uh4;
184
	Udp6hdr *uh6;
185
	ushort rport;
186
	uchar laddr[IPaddrlen], raddr[IPaddrlen];
187
	Udpcb *ucb;
188
	int dlen, ptcllen;
189
	Udppriv *upriv;
190
	Fs *f;
191
	int version;
192
	Conv *rc;
193
 
194
	upriv = c->p->priv;
195
	f = c->p->f;
196
 
197
//	netlog(c->p->f, Logudp, "udp: kick\n");	/* frequent and uninteresting */
198
	if(bp == nil)
199
		return;
200
 
201
	ucb = (Udpcb*)c->ptcl;
202
	switch(ucb->headers) {
203
	case 7:
204
		/* get user specified addresses */
205
		bp = pullupblock(bp, UDP_USEAD7);
206
		if(bp == nil)
207
			return;
208
		ipmove(raddr, bp->rp);
209
		bp->rp += IPaddrlen;
210
		ipmove(laddr, bp->rp);
211
		bp->rp += IPaddrlen;
212
		/* pick interface closest to dest */
213
		if(ipforme(f, laddr) != Runi)
214
			findlocalip(f, laddr, raddr);
215
		bp->rp += IPaddrlen;		/* Ignore ifc address */
216
		rport = nhgets(bp->rp);
217
		bp->rp += 2+2;			/* Ignore local port */
218
		break;
219
	default:
220
		rport = 0;
221
		break;
222
	}
223
 
224
	if(ucb->headers) {
225
		if(memcmp(laddr, v4prefix, IPv4off) == 0
226
		|| ipcmp(laddr, IPnoaddr) == 0)
227
			version = 4;
228
		else
229
			version = 6;
230
	} else {
231
		if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
232
			memcmp(c->laddr, v4prefix, IPv4off) == 0)
233
			|| ipcmp(c->raddr, IPnoaddr) == 0)
234
			version = 4;
235
		else
236
			version = 6;
237
	}
238
 
239
	dlen = blocklen(bp);
240
 
241
	/* fill in pseudo header and compute checksum */
242
	switch(version){
243
	case V4:
244
		bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
245
		if(bp == nil)
246
			return;
247
 
248
		uh4 = (Udp4hdr *)(bp->rp);
249
		ptcllen = dlen + UDP_UDPHDR_SZ;
250
		uh4->Unused = 0;
251
		uh4->udpproto = IP_UDPPROTO;
252
		uh4->frag[0] = 0;
253
		uh4->frag[1] = 0;
254
		hnputs(uh4->udpplen, ptcllen);
255
		if(ucb->headers) {
256
			v6tov4(uh4->udpdst, raddr);
257
			hnputs(uh4->udpdport, rport);
258
			v6tov4(uh4->udpsrc, laddr);
259
			rc = nil;
260
		} else {
261
			v6tov4(uh4->udpdst, c->raddr);
262
			hnputs(uh4->udpdport, c->rport);
263
			if(ipcmp(c->laddr, IPnoaddr) == 0)
264
				findlocalip(f, c->laddr, c->raddr);
265
			v6tov4(uh4->udpsrc, c->laddr);
266
			rc = c;
267
		}
268
		hnputs(uh4->udpsport, c->lport);
269
		hnputs(uh4->udplen, ptcllen);
270
		uh4->udpcksum[0] = 0;
271
		uh4->udpcksum[1] = 0;
272
		hnputs(uh4->udpcksum,
273
		       ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
274
		uh4->vihl = IP_VER4;
275
		ipoput4(f, bp, 0, c->ttl, c->tos, rc);
276
		break;
277
 
278
	case V6:
279
		bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
280
		if(bp == nil)
281
			return;
282
 
283
		/*
284
		 * using the v6 ip header to create pseudo header
285
		 * first then reset it to the normal ip header
286
		 */
287
		uh6 = (Udp6hdr *)(bp->rp);
288
		memset(uh6, 0, 8);
289
		ptcllen = dlen + UDP_UDPHDR_SZ;
290
		hnputl(uh6->viclfl, ptcllen);
291
		uh6->hoplimit = IP_UDPPROTO;
292
		if(ucb->headers) {
293
			ipmove(uh6->udpdst, raddr);
294
			hnputs(uh6->udpdport, rport);
295
			ipmove(uh6->udpsrc, laddr);
296
			rc = nil;
297
		} else {
298
			ipmove(uh6->udpdst, c->raddr);
299
			hnputs(uh6->udpdport, c->rport);
300
			if(ipcmp(c->laddr, IPnoaddr) == 0)
301
				findlocalip(f, c->laddr, c->raddr);
302
			ipmove(uh6->udpsrc, c->laddr);
303
			rc = c;
304
		}
305
		hnputs(uh6->udpsport, c->lport);
306
		hnputs(uh6->udplen, ptcllen);
307
		uh6->udpcksum[0] = 0;
308
		uh6->udpcksum[1] = 0;
309
		hnputs(uh6->udpcksum,
310
		       ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
311
		memset(uh6, 0, 8);
312
		uh6->viclfl[0] = IP_VER6;
313
		hnputs(uh6->len, ptcllen);
314
		uh6->nextheader = IP_UDPPROTO;
315
		ipoput6(f, bp, 0, c->ttl, c->tos, rc);
316
		break;
317
 
318
	default:
319
		panic("udpkick: version %d", version);
320
	}
321
	upriv->ustats.udpOutDatagrams++;
322
}
323
 
324
void
325
udpiput(Proto *udp, Ipifc *ifc, Block *bp)
326
{
327
	int len;
328
	Udp4hdr *uh4;
329
	Udp6hdr *uh6;
330
	Conv *c;
331
	Udpcb *ucb;
332
	uchar raddr[IPaddrlen], laddr[IPaddrlen];
333
	ushort rport, lport;
334
	Udppriv *upriv;
335
	Fs *f;
336
	int version;
337
	int ottl, oviclfl, olen;
338
	uchar *p;
339
 
340
	upriv = udp->priv;
341
	f = udp->f;
342
	upriv->ustats.udpInDatagrams++;
343
 
344
	uh4 = (Udp4hdr*)(bp->rp);
345
	version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
346
 
347
	/* Put back pseudo header for checksum
348
	 * (remember old values for icmpnoconv()) */
349
	switch(version) {
350
	case V4:
351
		ottl = uh4->Unused;
352
		uh4->Unused = 0;
353
		len = nhgets(uh4->udplen);
354
		olen = nhgets(uh4->udpplen);
355
		hnputs(uh4->udpplen, len);
356
 
357
		v4tov6(raddr, uh4->udpsrc);
358
		v4tov6(laddr, uh4->udpdst);
359
		lport = nhgets(uh4->udpdport);
360
		rport = nhgets(uh4->udpsport);
361
 
362
		if(nhgets(uh4->udpcksum)) {
363
			if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
364
				upriv->ustats.udpInErrors++;
365
				netlog(f, Logudp, "udp: checksum error %I\n", raddr);
366
				DPRINT("udp: checksum error %I\n", raddr);
367
				freeblist(bp);
368
				return;
369
			}
370
		}
371
		uh4->Unused = ottl;
372
		hnputs(uh4->udpplen, olen);
373
		break;
374
	case V6:
375
		uh6 = (Udp6hdr*)(bp->rp);
376
		len = nhgets(uh6->udplen);
377
		oviclfl = nhgetl(uh6->viclfl);
378
		olen = nhgets(uh6->len);
379
		ottl = uh6->hoplimit;
380
		ipmove(raddr, uh6->udpsrc);
381
		ipmove(laddr, uh6->udpdst);
382
		lport = nhgets(uh6->udpdport);
383
		rport = nhgets(uh6->udpsport);
384
		memset(uh6, 0, 8);
385
		hnputl(uh6->viclfl, len);
386
		uh6->hoplimit = IP_UDPPROTO;
387
		if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
388
			upriv->ustats.udpInErrors++;
389
			netlog(f, Logudp, "udp: checksum error %I\n", raddr);
390
			DPRINT("udp: checksum error %I\n", raddr);
391
			freeblist(bp);
392
			return;
393
		}
394
		hnputl(uh6->viclfl, oviclfl);
395
		hnputs(uh6->len, olen);
396
		uh6->nextheader = IP_UDPPROTO;
397
		uh6->hoplimit = ottl;
398
		break;
399
	default:
400
		panic("udpiput: version %d", version);
401
		return;	/* to avoid a warning */
402
	}
403
 
404
	qlock(udp);
405
 
406
	c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
407
	if(c == nil){
408
		/* no conversation found */
409
		upriv->ustats.udpNoPorts++;
410
		qunlock(udp);
411
		netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
412
		       laddr, lport);
413
 
414
		switch(version){
415
		case V4:
416
			icmpnoconv(f, bp);
417
			break;
418
		case V6:
419
			icmphostunr(f, ifc, bp, Icmp6_port_unreach, 0);
420
			break;
421
		default:
422
			panic("udpiput2: version %d", version);
423
		}
424
 
425
		freeblist(bp);
426
		return;
427
	}
428
	ucb = (Udpcb*)c->ptcl;
429
 
430
	if(c->state == Announced){
431
		if(ucb->headers == 0){
432
			/* create a new conversation */
433
			if(ipforme(f, laddr) != Runi) {
434
				switch(version){
435
				case V4:
436
					v4tov6(laddr, ifc->lifc->local);
437
					break;
438
				case V6:
439
					ipmove(laddr, ifc->lifc->local);
440
					break;
441
				default:
442
					panic("udpiput3: version %d", version);
443
				}
444
			}
445
			c = Fsnewcall(c, raddr, rport, laddr, lport, version);
446
			if(c == nil){
447
				qunlock(udp);
448
				freeblist(bp);
449
				return;
450
			}
451
			iphtadd(&upriv->ht, c);
452
			ucb = (Udpcb*)c->ptcl;
453
		}
454
	}
455
 
456
	qlock(c);
457
	qunlock(udp);
458
 
459
	/*
460
	 * Trim the packet down to data size
461
	 */
462
	len -= UDP_UDPHDR_SZ;
463
	switch(version){
464
	case V4:
465
		bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
466
		break;
467
	case V6:
468
		bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
469
		break;
470
	default:
471
		bp = nil;
472
		panic("udpiput4: version %d", version);
473
	}
474
	if(bp == nil){
475
		qunlock(c);
476
		netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
477
		       laddr, lport);
478
		upriv->lenerr++;
479
		return;
480
	}
481
 
482
	netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
483
	       laddr, lport, len);
484
 
485
	switch(ucb->headers){
486
	case 7:
487
		/* pass the src address */
488
		bp = padblock(bp, UDP_USEAD7);
489
		p = bp->rp;
490
		ipmove(p, raddr); p += IPaddrlen;
491
		ipmove(p, laddr); p += IPaddrlen;
492
		ipmove(p, ifc->lifc->local); p += IPaddrlen;
493
		hnputs(p, rport); p += 2;
494
		hnputs(p, lport);
495
		break;
496
	}
497
 
498
	if(bp->next)
499
		bp = concatblock(bp);
500
 
501
	if(qfull(c->rq)){
502
		qunlock(c);
503
		netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
504
		       laddr, lport);
505
		freeblist(bp);
506
		return;
507
	}
508
 
509
	qpass(c->rq, bp);
510
	qunlock(c);
511
 
512
}
513
 
514
char*
515
udpctl(Conv *c, char **f, int n)
516
{
517
	Udpcb *ucb;
518
 
519
	ucb = (Udpcb*)c->ptcl;
520
	if(n == 1){
521
		if(strcmp(f[0], "headers") == 0){
522
			ucb->headers = 7;	/* new headers format */
523
			return nil;
524
		}
525
	}
526
	return "unknown control request";
527
}
528
 
529
void
530
udpadvise(Proto *udp, Block *bp, char *msg)
531
{
532
	Udp4hdr *h4;
533
	Udp6hdr *h6;
534
	uchar source[IPaddrlen], dest[IPaddrlen];
535
	ushort psource, pdest;
536
	Conv *s, **p;
537
	int version;
538
 
539
	h4 = (Udp4hdr*)(bp->rp);
540
	version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
541
 
542
	switch(version) {
543
	case V4:
544
		v4tov6(dest, h4->udpdst);
545
		v4tov6(source, h4->udpsrc);
546
		psource = nhgets(h4->udpsport);
547
		pdest = nhgets(h4->udpdport);
548
		break;
549
	case V6:
550
		h6 = (Udp6hdr*)(bp->rp);
551
		ipmove(dest, h6->udpdst);
552
		ipmove(source, h6->udpsrc);
553
		psource = nhgets(h6->udpsport);
554
		pdest = nhgets(h6->udpdport);
555
		break;
556
	default:
557
		panic("udpadvise: version %d", version);
558
		return;  /* to avoid a warning */
559
	}
560
 
561
	/* Look for a connection */
562
	qlock(udp);
563
	for(p = udp->conv; *p; p++) {
564
		s = *p;
565
		if(s->rport == pdest)
566
		if(s->lport == psource)
567
		if(ipcmp(s->raddr, dest) == 0)
568
		if(ipcmp(s->laddr, source) == 0){
569
			if(s->ignoreadvice)
570
				break;
571
			qlock(s);
572
			qunlock(udp);
573
			qhangup(s->rq, msg);
574
			qhangup(s->wq, msg);
575
			qunlock(s);
576
			freeblist(bp);
577
			return;
578
		}
579
	}
580
	qunlock(udp);
581
	freeblist(bp);
582
}
583
 
584
int
585
udpstats(Proto *udp, char *buf, int len)
586
{
587
	Udppriv *upriv;
588
 
589
	upriv = udp->priv;
590
	return snprint(buf, len, "InDatagrams: %llud\nNoPorts: %lud\n"
591
		"InErrors: %lud\nOutDatagrams: %llud\n",
592
		upriv->ustats.udpInDatagrams,
593
		upriv->ustats.udpNoPorts,
594
		upriv->ustats.udpInErrors,
595
		upriv->ustats.udpOutDatagrams);
596
}
597
 
598
void
599
udpinit(Fs *fs)
600
{
601
	Proto *udp;
602
 
603
	udp = smalloc(sizeof(Proto));
604
	udp->priv = smalloc(sizeof(Udppriv));
605
	udp->name = "udp";
606
	udp->connect = udpconnect;
607
	udp->announce = udpannounce;
608
	udp->ctl = udpctl;
609
	udp->state = udpstate;
610
	udp->create = udpcreate;
611
	udp->close = udpclose;
612
	udp->rcv = udpiput;
613
	udp->advise = udpadvise;
614
	udp->stats = udpstats;
615
	udp->ipproto = IP_UDPPROTO;
616
	udp->nc = Nchans;
617
	udp->ptclsize = sizeof(Udpcb);
618
 
619
	Fsproto(fs, udp);
620
}