|
@@ -0,0 +1,643 @@
|
|
|
+#include "u.h"
|
|
|
+#include "../port/lib.h"
|
|
|
+#include "mem.h"
|
|
|
+#include "dat.h"
|
|
|
+#include "fns.h"
|
|
|
+#include "../port/error.h"
|
|
|
+
|
|
|
+#include "ip.h"
|
|
|
+#include "ipv6.h"
|
|
|
+
|
|
|
+
|
|
|
+#define DPRINT if(0)print
|
|
|
+
|
|
|
+enum
|
|
|
+{
|
|
|
+ UDP_UDPHDR_SZ = 8,
|
|
|
+
|
|
|
+ UDP4_PHDR_OFF = 8,
|
|
|
+ UDP4_PHDR_SZ = 12,
|
|
|
+ UDP4_IPHDR_SZ = 20,
|
|
|
+ UDP6_IPHDR_SZ = 40,
|
|
|
+ UDP6_PHDR_SZ = 40,
|
|
|
+ UDP6_PHDR_OFF = 0,
|
|
|
+
|
|
|
+ IP_UDPPROTO = 17,
|
|
|
+ UDP_USEAD7 = 52,
|
|
|
+ UDP_USEAD6 = 36,
|
|
|
+
|
|
|
+ Udprxms = 200,
|
|
|
+ Udptickms = 100,
|
|
|
+ Udpmaxxmit = 10,
|
|
|
+};
|
|
|
+
|
|
|
+typedef struct Udp4hdr Udp4hdr;
|
|
|
+struct Udp4hdr
|
|
|
+{
|
|
|
+ /* ip header */
|
|
|
+ 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[IPv4addrlen]; /* Ip source */
|
|
|
+ uchar udpdst[IPv4addrlen]; /* Ip destination */
|
|
|
+
|
|
|
+ /* udp header */
|
|
|
+ uchar udpsport[2]; /* Source port */
|
|
|
+ uchar udpdport[2]; /* Destination port */
|
|
|
+ uchar udplen[2]; /* data length */
|
|
|
+ uchar udpcksum[2]; /* Checksum */
|
|
|
+};
|
|
|
+
|
|
|
+typedef struct Udp6hdr Udp6hdr;
|
|
|
+struct Udp6hdr {
|
|
|
+ uchar viclfl[4];
|
|
|
+ uchar len[2];
|
|
|
+ uchar nextheader;
|
|
|
+ uchar hoplimit;
|
|
|
+ uchar udpsrc[IPaddrlen];
|
|
|
+ uchar udpdst[IPaddrlen];
|
|
|
+
|
|
|
+ /* udp header */
|
|
|
+ uchar udpsport[2]; /* Source port */
|
|
|
+ uchar udpdport[2]; /* Destination port */
|
|
|
+ uchar udplen[2]; /* data length */
|
|
|
+ uchar udpcksum[2]; /* Checksum */
|
|
|
+};
|
|
|
+
|
|
|
+/* MIB II counters */
|
|
|
+typedef struct Udpstats Udpstats;
|
|
|
+struct Udpstats
|
|
|
+{
|
|
|
+ ulong udpInDatagrams;
|
|
|
+ ulong udpNoPorts;
|
|
|
+ ulong udpInErrors;
|
|
|
+ ulong udpOutDatagrams;
|
|
|
+};
|
|
|
+
|
|
|
+typedef struct Udppriv Udppriv;
|
|
|
+struct Udppriv
|
|
|
+{
|
|
|
+ Ipht ht;
|
|
|
+
|
|
|
+ /* MIB counters */
|
|
|
+ Udpstats ustats;
|
|
|
+
|
|
|
+ /* non-MIB stats */
|
|
|
+ ulong csumerr; /* checksum errors */
|
|
|
+ ulong lenerr; /* short packet */
|
|
|
+};
|
|
|
+
|
|
|
+void (*etherprofiler)(char *name, int qlen);
|
|
|
+void udpkick(void *x, Block *bp);
|
|
|
+
|
|
|
+/*
|
|
|
+ * protocol specific part of Conv
|
|
|
+ */
|
|
|
+typedef struct Udpcb Udpcb;
|
|
|
+struct Udpcb
|
|
|
+{
|
|
|
+ QLock;
|
|
|
+ uchar headers;
|
|
|
+};
|
|
|
+
|
|
|
+static char*
|
|
|
+udpconnect(Conv *c, char **argv, int argc)
|
|
|
+{
|
|
|
+ char *e;
|
|
|
+ Udppriv *upriv;
|
|
|
+
|
|
|
+ upriv = c->p->priv;
|
|
|
+ e = Fsstdconnect(c, argv, argc);
|
|
|
+ Fsconnected(c, e);
|
|
|
+ if(e != nil)
|
|
|
+ return e;
|
|
|
+
|
|
|
+ iphtadd(&upriv->ht, c);
|
|
|
+ return nil;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int
|
|
|
+udpstate(Conv *c, char *state, int n)
|
|
|
+{
|
|
|
+ return snprint(state, n, "%s", c->inuse?"Open":"Closed");
|
|
|
+}
|
|
|
+
|
|
|
+static char*
|
|
|
+udpannounce(Conv *c, char** argv, int argc)
|
|
|
+{
|
|
|
+ char *e;
|
|
|
+ Udppriv *upriv;
|
|
|
+
|
|
|
+ upriv = c->p->priv;
|
|
|
+ e = Fsstdannounce(c, argv, argc);
|
|
|
+ if(e != nil)
|
|
|
+ return e;
|
|
|
+ Fsconnected(c, nil);
|
|
|
+ iphtadd(&upriv->ht, c);
|
|
|
+
|
|
|
+ return nil;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+udpcreate(Conv *c)
|
|
|
+{
|
|
|
+ c->rq = qopen(128*1024, Qmsg, 0, 0);
|
|
|
+ c->wq = qbypass(udpkick, c);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+udpclose(Conv *c)
|
|
|
+{
|
|
|
+ Udpcb *ucb;
|
|
|
+ Udppriv *upriv;
|
|
|
+
|
|
|
+ upriv = c->p->priv;
|
|
|
+ iphtrem(&upriv->ht, c);
|
|
|
+
|
|
|
+ c->state = 0;
|
|
|
+ qclose(c->rq);
|
|
|
+ qclose(c->wq);
|
|
|
+ qclose(c->eq);
|
|
|
+ ipmove(c->laddr, IPnoaddr);
|
|
|
+ ipmove(c->raddr, IPnoaddr);
|
|
|
+ c->lport = 0;
|
|
|
+ c->rport = 0;
|
|
|
+
|
|
|
+ ucb = (Udpcb*)c->ptcl;
|
|
|
+ ucb->headers = 0;
|
|
|
+
|
|
|
+ qunlock(c);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+udpkick(void *x, Block *bp)
|
|
|
+{
|
|
|
+ Conv *c = x;
|
|
|
+ Udp4hdr *uh4;
|
|
|
+ Udp6hdr *uh6;
|
|
|
+ ushort rport;
|
|
|
+ uchar laddr[IPaddrlen], raddr[IPaddrlen];
|
|
|
+ Udpcb *ucb;
|
|
|
+ int dlen, ptcllen;
|
|
|
+ Udppriv *upriv;
|
|
|
+ Fs *f;
|
|
|
+ int version;
|
|
|
+ Conv *rc;
|
|
|
+
|
|
|
+ upriv = c->p->priv;
|
|
|
+ f = c->p->f;
|
|
|
+
|
|
|
+ netlog(c->p->f, Logudp, "udp: kick\n");
|
|
|
+ if(bp == nil)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ucb = (Udpcb*)c->ptcl;
|
|
|
+ switch(ucb->headers) {
|
|
|
+ case 7:
|
|
|
+ /* get user specified addresses */
|
|
|
+ bp = pullupblock(bp, UDP_USEAD7);
|
|
|
+ if(bp == nil)
|
|
|
+ return;
|
|
|
+ ipmove(raddr, bp->rp);
|
|
|
+ bp->rp += IPaddrlen;
|
|
|
+ ipmove(laddr, bp->rp);
|
|
|
+ bp->rp += IPaddrlen;
|
|
|
+ /* pick interface closest to dest */
|
|
|
+ if(ipforme(f, laddr) != Runi)
|
|
|
+ findlocalip(f, laddr, raddr);
|
|
|
+ bp->rp += IPaddrlen; /* Ignore ifc address */
|
|
|
+ rport = nhgets(bp->rp);
|
|
|
+ bp->rp += 2+2; /* Ignore local port */
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ /* get user specified addresses */
|
|
|
+ bp = pullupblock(bp, UDP_USEAD6);
|
|
|
+ if(bp == nil)
|
|
|
+ return;
|
|
|
+ ipmove(raddr, bp->rp);
|
|
|
+ bp->rp += IPaddrlen;
|
|
|
+ ipmove(laddr, bp->rp);
|
|
|
+ bp->rp += IPaddrlen;
|
|
|
+ /* pick interface closest to dest */
|
|
|
+ if(ipforme(f, laddr) != Runi)
|
|
|
+ findlocalip(f, laddr, raddr);
|
|
|
+ rport = nhgets(bp->rp);
|
|
|
+ bp->rp += 2+2; /* Ignore local port */
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ rport = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(ucb->headers) {
|
|
|
+ if(memcmp(laddr, v4prefix, IPv4off) == 0 ||
|
|
|
+ ipcmp(laddr, IPnoaddr) == 0)
|
|
|
+ version = 4;
|
|
|
+ else
|
|
|
+ version = 6;
|
|
|
+ } else {
|
|
|
+ if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
|
|
|
+ memcmp(c->laddr, v4prefix, IPv4off) == 0)
|
|
|
+ || ipcmp(c->raddr, IPnoaddr) == 0)
|
|
|
+ version = 4;
|
|
|
+ else
|
|
|
+ version = 6;
|
|
|
+ }
|
|
|
+
|
|
|
+ dlen = blocklen(bp);
|
|
|
+
|
|
|
+ /* fill in pseudo header and compute checksum */
|
|
|
+ switch(version){
|
|
|
+ case V4:
|
|
|
+ bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
|
|
|
+ if(bp == nil)
|
|
|
+ return;
|
|
|
+
|
|
|
+ uh4 = (Udp4hdr *)(bp->rp);
|
|
|
+ ptcllen = dlen + UDP_UDPHDR_SZ;
|
|
|
+ uh4->Unused = 0;
|
|
|
+ uh4->udpproto = IP_UDPPROTO;
|
|
|
+ uh4->frag[0] = 0;
|
|
|
+ uh4->frag[1] = 0;
|
|
|
+ hnputs(uh4->udpplen, ptcllen);
|
|
|
+ if(ucb->headers) {
|
|
|
+ v6tov4(uh4->udpdst, raddr);
|
|
|
+ hnputs(uh4->udpdport, rport);
|
|
|
+ v6tov4(uh4->udpsrc, laddr);
|
|
|
+ rc = nil;
|
|
|
+ } else {
|
|
|
+ v6tov4(uh4->udpdst, c->raddr);
|
|
|
+ hnputs(uh4->udpdport, c->rport);
|
|
|
+ if(ipcmp(c->laddr, IPnoaddr) == 0)
|
|
|
+ findlocalip(f, c->laddr, c->raddr);
|
|
|
+ v6tov4(uh4->udpsrc, c->laddr);
|
|
|
+ rc = c;
|
|
|
+ }
|
|
|
+ hnputs(uh4->udpsport, c->lport);
|
|
|
+ hnputs(uh4->udplen, ptcllen);
|
|
|
+ uh4->udpcksum[0] = 0;
|
|
|
+ uh4->udpcksum[1] = 0;
|
|
|
+ hnputs(uh4->udpcksum,
|
|
|
+ ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
|
|
|
+ uh4->vihl = IP_VER4;
|
|
|
+ ipoput4(f, bp, 0, c->ttl, c->tos, rc);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case V6:
|
|
|
+ bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
|
|
|
+ if(bp == nil)
|
|
|
+ return;
|
|
|
+
|
|
|
+ // using the v6 ip header to create pseudo header
|
|
|
+ // first then reset it to the normal ip header
|
|
|
+ uh6 = (Udp6hdr *)(bp->rp);
|
|
|
+ memset(uh6, 0, 8);
|
|
|
+ ptcllen = dlen + UDP_UDPHDR_SZ;
|
|
|
+ hnputl(uh6->viclfl, ptcllen);
|
|
|
+ uh6->hoplimit = IP_UDPPROTO;
|
|
|
+ if(ucb->headers) {
|
|
|
+ ipmove(uh6->udpdst, raddr);
|
|
|
+ hnputs(uh6->udpdport, rport);
|
|
|
+ ipmove(uh6->udpsrc, laddr);
|
|
|
+ rc = nil;
|
|
|
+ } else {
|
|
|
+ ipmove(uh6->udpdst, c->raddr);
|
|
|
+ hnputs(uh6->udpdport, c->rport);
|
|
|
+ if(ipcmp(c->laddr, IPnoaddr) == 0)
|
|
|
+ findlocalip(f, c->laddr, c->raddr);
|
|
|
+ ipmove(uh6->udpsrc, c->laddr);
|
|
|
+ rc = c;
|
|
|
+ }
|
|
|
+ hnputs(uh6->udpsport, c->lport);
|
|
|
+ hnputs(uh6->udplen, ptcllen);
|
|
|
+ uh6->udpcksum[0] = 0;
|
|
|
+ uh6->udpcksum[1] = 0;
|
|
|
+ hnputs(uh6->udpcksum,
|
|
|
+ ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
|
|
|
+ memset(uh6, 0, 8);
|
|
|
+ uh6->viclfl[0] = IP_VER6;
|
|
|
+ hnputs(uh6->len, ptcllen);
|
|
|
+ uh6->nextheader = IP_UDPPROTO;
|
|
|
+ ipoput6(f, bp, 0, c->ttl, c->tos, rc);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ panic("udpkick: version %d", version);
|
|
|
+ }
|
|
|
+ upriv->ustats.udpOutDatagrams++;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
|
|
+{
|
|
|
+ int len;
|
|
|
+ Udp4hdr *uh4;
|
|
|
+ Udp6hdr *uh6;
|
|
|
+ Conv *c;
|
|
|
+ Udpcb *ucb;
|
|
|
+ uchar raddr[IPaddrlen], laddr[IPaddrlen];
|
|
|
+ ushort rport, lport;
|
|
|
+ Udppriv *upriv;
|
|
|
+ Fs *f;
|
|
|
+ int version;
|
|
|
+ int ottl, oviclfl, olen;
|
|
|
+ uchar *p;
|
|
|
+
|
|
|
+ upriv = udp->priv;
|
|
|
+ f = udp->f;
|
|
|
+ upriv->ustats.udpInDatagrams++;
|
|
|
+
|
|
|
+ uh4 = (Udp4hdr*)(bp->rp);
|
|
|
+ version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
|
|
|
+
|
|
|
+ /* Put back pseudo header for checksum
|
|
|
+ * (remember old values for icmpnoconv()) */
|
|
|
+ switch(version) {
|
|
|
+ case V4:
|
|
|
+ ottl = uh4->Unused;
|
|
|
+ uh4->Unused = 0;
|
|
|
+ len = nhgets(uh4->udplen);
|
|
|
+ olen = nhgets(uh4->udpplen);
|
|
|
+ hnputs(uh4->udpplen, len);
|
|
|
+
|
|
|
+ v4tov6(raddr, uh4->udpsrc);
|
|
|
+ v4tov6(laddr, uh4->udpdst);
|
|
|
+ lport = nhgets(uh4->udpdport);
|
|
|
+ rport = nhgets(uh4->udpsport);
|
|
|
+
|
|
|
+ if(nhgets(uh4->udpcksum)) {
|
|
|
+ if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
|
|
|
+ upriv->ustats.udpInErrors++;
|
|
|
+ netlog(f, Logudp, "udp: checksum error %I\n", raddr);
|
|
|
+ DPRINT("udp: checksum error %I\n", raddr);
|
|
|
+ freeblist(bp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ uh4->Unused = ottl;
|
|
|
+ hnputs(uh4->udpplen, olen);
|
|
|
+ break;
|
|
|
+ case V6:
|
|
|
+ uh6 = (Udp6hdr*)(bp->rp);
|
|
|
+ len = nhgets(uh6->udplen);
|
|
|
+ oviclfl = nhgetl(uh6->viclfl);
|
|
|
+ olen = nhgets(uh6->len);
|
|
|
+ ottl = uh6->hoplimit;
|
|
|
+ ipmove(raddr, uh6->udpsrc);
|
|
|
+ ipmove(laddr, uh6->udpdst);
|
|
|
+ lport = nhgets(uh6->udpdport);
|
|
|
+ rport = nhgets(uh6->udpsport);
|
|
|
+ memset(uh6, 0, 8);
|
|
|
+ hnputl(uh6->viclfl, len);
|
|
|
+ uh6->hoplimit = IP_UDPPROTO;
|
|
|
+ if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
|
|
|
+ upriv->ustats.udpInErrors++;
|
|
|
+ netlog(f, Logudp, "udp: checksum error %I\n", raddr);
|
|
|
+ DPRINT("udp: checksum error %I\n", raddr);
|
|
|
+ freeblist(bp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ hnputl(uh6->viclfl, oviclfl);
|
|
|
+ hnputs(uh6->len, olen);
|
|
|
+ uh6->nextheader = IP_UDPPROTO;
|
|
|
+ uh6->hoplimit = ottl;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ panic("udpiput: version %d", version);
|
|
|
+ return; /* to avoid a warning */
|
|
|
+ }
|
|
|
+
|
|
|
+ qlock(udp);
|
|
|
+
|
|
|
+ c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
|
|
|
+ if(c == nil){
|
|
|
+ /* no converstation found */
|
|
|
+ upriv->ustats.udpNoPorts++;
|
|
|
+ qunlock(udp);
|
|
|
+ netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
|
|
|
+ laddr, lport);
|
|
|
+
|
|
|
+ switch(version){
|
|
|
+ case V4:
|
|
|
+ icmpnoconv(f, bp);
|
|
|
+ break;
|
|
|
+ case V6:
|
|
|
+ icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ panic("udpiput2: version %d", version);
|
|
|
+ }
|
|
|
+
|
|
|
+ freeblist(bp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ucb = (Udpcb*)c->ptcl;
|
|
|
+
|
|
|
+ if(c->state == Announced){
|
|
|
+ if(ucb->headers == 0){
|
|
|
+ /* create a new conversation */
|
|
|
+ if(ipforme(f, laddr) != Runi) {
|
|
|
+ switch(version){
|
|
|
+ case V4:
|
|
|
+ v4tov6(laddr, ifc->lifc->local);
|
|
|
+ break;
|
|
|
+ case V6:
|
|
|
+ ipmove(laddr, ifc->lifc->local);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ panic("udpiput3: version %d", version);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ c = Fsnewcall(c, raddr, rport, laddr, lport, version);
|
|
|
+ if(c == nil){
|
|
|
+ qunlock(udp);
|
|
|
+ freeblist(bp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ iphtadd(&upriv->ht, c);
|
|
|
+ ucb = (Udpcb*)c->ptcl;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ qlock(c);
|
|
|
+ qunlock(udp);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Trim the packet down to data size
|
|
|
+ */
|
|
|
+ len -= UDP_UDPHDR_SZ;
|
|
|
+ switch(version){
|
|
|
+ case V4:
|
|
|
+ bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
|
|
|
+ break;
|
|
|
+ case V6:
|
|
|
+ bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ bp = nil;
|
|
|
+ panic("udpiput4: version %d", version);
|
|
|
+ }
|
|
|
+ if(bp == nil){
|
|
|
+ qunlock(c);
|
|
|
+ netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
|
|
|
+ laddr, lport);
|
|
|
+ upriv->lenerr++;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
|
|
|
+ laddr, lport, len);
|
|
|
+
|
|
|
+ switch(ucb->headers){
|
|
|
+ case 7:
|
|
|
+ /* pass the src address */
|
|
|
+ bp = padblock(bp, UDP_USEAD7);
|
|
|
+ p = bp->rp;
|
|
|
+ ipmove(p, raddr); p += IPaddrlen;
|
|
|
+ ipmove(p, laddr); p += IPaddrlen;
|
|
|
+ ipmove(p, ifc->lifc->local); p += IPaddrlen;
|
|
|
+ hnputs(p, rport); p += 2;
|
|
|
+ hnputs(p, lport);
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ /* pass the src address */
|
|
|
+ bp = padblock(bp, UDP_USEAD6);
|
|
|
+ p = bp->rp;
|
|
|
+ ipmove(p, raddr); p += IPaddrlen;
|
|
|
+ ipmove(p, ipforme(f, laddr)==Runi ? laddr : ifc->lifc->local); p += IPaddrlen;
|
|
|
+ hnputs(p, rport); p += 2;
|
|
|
+ hnputs(p, lport);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bp->next)
|
|
|
+ bp = concatblock(bp);
|
|
|
+
|
|
|
+ if(qfull(c->rq)){
|
|
|
+ qunlock(c);
|
|
|
+ netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
|
|
|
+ laddr, lport);
|
|
|
+ freeblist(bp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ qpass(c->rq, bp);
|
|
|
+ qunlock(c);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+char*
|
|
|
+udpctl(Conv *c, char **f, int n)
|
|
|
+{
|
|
|
+ Udpcb *ucb;
|
|
|
+
|
|
|
+ ucb = (Udpcb*)c->ptcl;
|
|
|
+ if(n == 1){
|
|
|
+ if(strcmp(f[0], "oldheaders") == 0){
|
|
|
+ ucb->headers = 6;
|
|
|
+ return nil;
|
|
|
+ } else if(strcmp(f[0], "headers") == 0){
|
|
|
+ ucb->headers = 7;
|
|
|
+ return nil;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "unknown control request";
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+udpadvise(Proto *udp, Block *bp, char *msg)
|
|
|
+{
|
|
|
+ Udp4hdr *h4;
|
|
|
+ Udp6hdr *h6;
|
|
|
+ uchar source[IPaddrlen], dest[IPaddrlen];
|
|
|
+ ushort psource, pdest;
|
|
|
+ Conv *s, **p;
|
|
|
+ int version;
|
|
|
+
|
|
|
+ h4 = (Udp4hdr*)(bp->rp);
|
|
|
+ version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
|
|
|
+
|
|
|
+ switch(version) {
|
|
|
+ case V4:
|
|
|
+ v4tov6(dest, h4->udpdst);
|
|
|
+ v4tov6(source, h4->udpsrc);
|
|
|
+ psource = nhgets(h4->udpsport);
|
|
|
+ pdest = nhgets(h4->udpdport);
|
|
|
+ break;
|
|
|
+ case V6:
|
|
|
+ h6 = (Udp6hdr*)(bp->rp);
|
|
|
+ ipmove(dest, h6->udpdst);
|
|
|
+ ipmove(source, h6->udpsrc);
|
|
|
+ psource = nhgets(h6->udpsport);
|
|
|
+ pdest = nhgets(h6->udpdport);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ panic("udpadvise: version %d", version);
|
|
|
+ return; /* to avoid a warning */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Look for a connection */
|
|
|
+ qlock(udp);
|
|
|
+ for(p = udp->conv; *p; p++) {
|
|
|
+ s = *p;
|
|
|
+ if(s->rport == pdest)
|
|
|
+ if(s->lport == psource)
|
|
|
+ if(ipcmp(s->raddr, dest) == 0)
|
|
|
+ if(ipcmp(s->laddr, source) == 0){
|
|
|
+ if(s->ignoreadvice)
|
|
|
+ break;
|
|
|
+ qlock(s);
|
|
|
+ qunlock(udp);
|
|
|
+ qhangup(s->rq, msg);
|
|
|
+ qhangup(s->wq, msg);
|
|
|
+ qunlock(s);
|
|
|
+ freeblist(bp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ qunlock(udp);
|
|
|
+ freeblist(bp);
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+udpstats(Proto *udp, char *buf, int len)
|
|
|
+{
|
|
|
+ Udppriv *upriv;
|
|
|
+
|
|
|
+ upriv = udp->priv;
|
|
|
+ return snprint(buf, len, "InDatagrams: %lud\nNoPorts: %lud\nInErrors: %lud\nOutDatagrams: %lud\n",
|
|
|
+ upriv->ustats.udpInDatagrams,
|
|
|
+ upriv->ustats.udpNoPorts,
|
|
|
+ upriv->ustats.udpInErrors,
|
|
|
+ upriv->ustats.udpOutDatagrams);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+udpinit(Fs *fs)
|
|
|
+{
|
|
|
+ Proto *udp;
|
|
|
+
|
|
|
+ udp = smalloc(sizeof(Proto));
|
|
|
+ udp->priv = smalloc(sizeof(Udppriv));
|
|
|
+ udp->name = "udp";
|
|
|
+ udp->connect = udpconnect;
|
|
|
+ udp->announce = udpannounce;
|
|
|
+ udp->ctl = udpctl;
|
|
|
+ udp->state = udpstate;
|
|
|
+ udp->create = udpcreate;
|
|
|
+ udp->close = udpclose;
|
|
|
+ udp->rcv = udpiput;
|
|
|
+ udp->advise = udpadvise;
|
|
|
+ udp->stats = udpstats;
|
|
|
+ udp->ipproto = IP_UDPPROTO;
|
|
|
+ udp->nc = Nchans;
|
|
|
+ udp->ptclsize = sizeof(Udpcb);
|
|
|
+
|
|
|
+ Fsproto(fs, udp);
|
|
|
+}
|