| plan 9 kernel history: overview | file list | diff list |
1998/0306/ip/udp.c (diff list | history)
| ip/udp.c on 1997/0327 | ||
| 1997/0327 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ip.h" #define DPRINT if(0)print enum { UDP_PHDRSIZE = 12, UDP_HDRSIZE = 20, UDP_IPHDR = 8, IP_UDPPROTO = 17, | |
| 1998/0306 | UDP_USEAD = 36, | |
| 1997/0327 | Udprxms = 200, Udptickms = 100, Udpmaxxmit = 10, }; typedef struct Udphdr Udphdr; struct Udphdr { /* ip header */ | |
| 1998/0306 | uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar Unused; uchar udpproto; /* Protocol */ uchar udpplen[2]; /* Header plus data length */ uchar udpsrc[4]; /* Ip source */ uchar udpdst[4]; /* Ip destination */ | |
| 1997/0327 | /* udp header */ | |
| 1998/0306 | uchar udpsport[2]; /* Source port */ uchar udpdport[2]; /* Destination port */ uchar udplen[2]; /* data length */ uchar udpcksum[2]; /* Checksum */ | |
| 1997/0327 | }; /* * protocol specific part of Conv */ typedef struct Udpcb Udpcb; struct Udpcb { QLock; | |
| 1998/0306 | uchar headers; | |
| 1997/0327 | }; Proto udp; int udpsum; uint generation; extern Fs fs; int udpdebug; static char* udpconnect(Conv *c, char **argv, int argc) { char *e; e = Fsstdconnect(c, argv, argc); Fsconnected(&fs, c, e); return e; } | |
| 1998/0306 | static int udpstate(Conv *c, char *state, int n) | |
| 1997/0327 | { USED(c); | |
| 1998/0306 | return snprint(state, n, "%s", "Datagram"); | |
| 1997/0327 | } | |
| 1997/0403 | static char* | |
| 1997/0411 | udpannounce(Conv *c, char** argv, int argc) | |
| 1997/0327 | { | |
| 1997/0411 | char *e; e = Fsstdannounce(c, argv, argc); if(e != nil) return e; | |
| 1997/0327 | Fsconnected(&fs, c, nil); | |
| 1997/0403 | return nil; | |
| 1997/0327 | } static void udpcreate(Conv *c) { | |
| 1997/0806 | c->rq = qopen(64*1024, 1, 0, 0); c->wq = qopen(64*1024, 0, 0, 0); | |
| 1997/0327 | } static void udpclose(Conv *c) { Udpcb *ucb; qclose(c->rq); qclose(c->wq); qclose(c->eq); | |
| 1998/0306 | ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); | |
| 1997/0327 | c->lport = 0; c->rport = 0; ucb = (Udpcb*)c->ptcl; ucb->headers = 0; unlock(c); } void | |
| 1998/0306 | udpkick(Conv *c, int) | |
| 1997/0327 | { Udphdr *uh; | |
| 1997/0530 | ushort rport; | |
| 1998/0306 | uchar laddr[IPaddrlen], raddr[IPaddrlen]; | |
| 1997/0806 | Block *bp; | |
| 1997/0327 | Udpcb *ucb; int dlen, ptcllen; | |
| 1998/0306 | netlog(Logudp, "udp: kick\n"); | |
| 1997/0327 | bp = qget(c->wq); if(bp == nil) return; ucb = (Udpcb*)c->ptcl; if(ucb->headers) { /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD); | |
| 1998/0306 | if(bp == nil) | |
| 1997/0327 | return; | |
| 1998/0306 | ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; if(ipforme(laddr) != Runi) findlocalip(laddr, raddr); /* pick interface closest to dest */ | |
| 1997/0530 | rport = nhgets(bp->rp); | |
| 1997/0327 | bp->rp += 2; | |
| 1997/0530 | /* ignore local port number */ bp->rp += 2; | |
| 1997/0327 | } else { | |
| 1997/0530 | rport = 0; | |
| 1997/0327 | } dlen = blocklen(bp); /* Make space to fit udp & ip header */ bp = padblock(bp, UDP_IPHDR+UDP_HDRSIZE); if(bp == nil) return; uh = (Udphdr *)(bp->rp); ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); uh->Unused = 0; uh->udpproto = IP_UDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->udpplen, ptcllen); if(ucb->headers) { | |
| 1998/0306 | v6tov4(uh->udpdst, raddr); | |
| 1997/0530 | hnputs(uh->udpdport, rport); | |
| 1998/0306 | v6tov4(uh->udpsrc, laddr); | |
| 1997/0327 | } else { | |
| 1998/0306 | v6tov4(uh->udpdst, c->raddr); | |
| 1997/0327 | hnputs(uh->udpdport, c->rport); | |
| 1998/0306 | if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(c->laddr, c->raddr); /* pick interface closest to dest */ v6tov4(uh->udpsrc, c->laddr); | |
| 1997/0327 | } hnputs(uh->udpsport, c->lport); hnputs(uh->udplen, ptcllen); uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_HDRSIZE)); ipoput(bp, 0, c->ttl); } void | |
| 1998/0306 | udpiput(uchar *ia, Block *bp) | |
| 1997/0327 | { | |
| 1997/0904 | int len, olen, ottl; | |
| 1997/0327 | Udphdr *uh; Conv *c, **p; Udpcb *ucb; | |
| 1998/0306 | uchar raddr[IPaddrlen], laddr[IPaddrlen]; | |
| 1997/0530 | ushort rport, lport; | |
| 1997/0327 | uh = (Udphdr*)(bp->rp); | |
| 1997/0904 | /* Put back pseudo header for checksum (remember old values for icmpnoconv()) */ ottl = uh->Unused; | |
| 1997/0327 | uh->Unused = 0; len = nhgets(uh->udplen); | |
| 1997/0904 | olen = nhgets(uh->udpplen); | |
| 1997/0327 | hnputs(uh->udpplen, len); | |
| 1998/0306 | v4tov6(raddr, uh->udpsrc); v4tov6(laddr, uh->udpdst); | |
| 1997/0725 | lport = nhgets(uh->udpdport); rport = nhgets(uh->udpsport); | |
| 1997/0327 | if(udpsum && nhgets(uh->udpcksum)) { if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { udp.csumerr++; | |
| 1998/0306 | netlog(Logudp, "udp: checksum error %I\n", raddr); | |
| 1997/0327 | freeblist(bp); return; } } /* Look for a conversation structure for this port */ c = nil; for(p = udp.conv; *p; p++) { c = *p; if(c->inuse == 0) continue; | |
| 1997/0530 | if(c->lport == lport && (c->rport == 0 || c->rport == rport)) | |
| 1997/0327 | break; } if(*p == nil) { | |
| 1998/0306 | netlog(Logudp, "udp: no conv %I.%d -> %I.%d\n", raddr, rport, laddr, lport); | |
| 1997/0904 | /* don't complain about broadcasts... */ | |
| 1998/0306 | if(ipforme(raddr) == 0){ | |
| 1997/0904 | uh->Unused = ottl; hnputs(uh->udpplen, olen); icmpnoconv(bp); } | |
| 1997/0327 | freeblist(bp); return; } /* * Trim the packet down to data size */ len -= (UDP_HDRSIZE-UDP_PHDRSIZE); bp = trimblock(bp, UDP_IPHDR+UDP_HDRSIZE, len); if(bp == nil){ | |
| 1998/0306 | netlog(Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); | |
| 1997/0327 | udp.lenerr++; return; } | |
| 1997/0806 | ||
| 1998/0306 | netlog(Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport, laddr, lport, len); | |
| 1997/0327 | ucb = (Udpcb*)c->ptcl; if(ucb->headers) { /* pass the src address */ bp = padblock(bp, UDP_USEAD); | |
| 1998/0306 | ipmove(bp->rp, raddr); if(ipforme(laddr) == Runi) ipmove(bp->rp+IPaddrlen, laddr); | |
| 1997/0901 | else | |
| 1998/0306 | ipmove(bp->rp+IPaddrlen, ia); hnputs(bp->rp+2*IPaddrlen, rport); hnputs(bp->rp+2*IPaddrlen+2, lport); | |
| 1997/0327 | } else { /* connection oriented udp */ if(c->raddr == 0){ /* save the src address in the conversation */ | |
| 1998/0306 | ipmove(c->raddr, raddr); | |
| 1997/0530 | c->rport = rport; | |
| 1997/0327 | /* reply with the same ip address (if not broadcast) */ | |
| 1998/0306 | if(ipforme(laddr) == Runi) ipmove(c->laddr, laddr); | |
| 1997/0708 | else | |
| 1998/0306 | ipmove(c->laddr, ia); | |
| 1997/0327 | } } if(bp->next) bp = concatblock(bp); | |
| 1997/0725 | if(qfull(c->rq)){ | |
| 1998/0306 | netlog(Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport, laddr, lport); | |
| 1997/0327 | freeblist(bp); | |
| 1997/0725 | }else | |
| 1997/0327 | qpass(c->rq, bp); } char* udpctl(Conv *c, char **f, int n) { Udpcb *ucb; ucb = (Udpcb*)c->ptcl; if(n == 1 && strcmp(f[0], "headers") == 0){ ucb->headers = 1; return nil; } if(n == 1 && strcmp(f[0], "debug") == 0){ udpdebug = 1; return nil; } return "unknown control request"; } void | |
| 1997/0829 | udpadvise(Block *bp, char *msg) { Udphdr *h; | |
| 1998/0306 | uchar source[IPaddrlen], dest[IPaddrlen]; | |
| 1997/0829 | ushort psource, pdest; Conv *s, **p; h = (Udphdr*)(bp->rp); | |
| 1998/0306 | v4tov6(dest, h->udpdst); v4tov6(source, h->udpsrc); | |
| 1997/0829 | psource = nhgets(h->udpsport); pdest = nhgets(h->udpdport); /* Look for a connection */ for(p = udp.conv; *p; p++) { s = *p; | |
| 1998/0306 | if(s->rport == pdest) if(s->lport == psource) if(ipcmp(s->raddr, dest) == 0) if(ipcmp(s->laddr, source) == 0){ | |
| 1997/0829 | qhangup(s->rq, msg); qhangup(s->wq, msg); break; } } freeblist(bp); } | |
| 1998/0306 | int udpstats(char *buf, int len) { return snprint(buf, len, "udp: csum %d hlen %d len %d order %d rexmit %d\n", udp.csumerr, udp.hlenerr, udp.lenerr, udp.order, udp.rexmit); } | |
| 1997/0829 | void | |
| 1997/0327 | udpinit(Fs *fs) { udp.name = "udp"; udp.kick = udpkick; udp.connect = udpconnect; udp.announce = udpannounce; udp.ctl = udpctl; udp.state = udpstate; udp.create = udpcreate; udp.close = udpclose; udp.rcv = udpiput; | |
| 1997/0829 | udp.advise = udpadvise; | |
| 1998/0306 | udp.stats = udpstats; | |
| 1997/0327 | udp.ipproto = IP_UDPPROTO; udp.nc = 16; udp.ptclsize = sizeof(Udpcb); Fsproto(fs, &udp); } | |