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