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