void relsendack(Conv *c, Reliable *r, int hangup) { Udphdr *uh; Block *bp; Rudphdr *rh; int ptcllen; Fs *f; bp = allocb(UDP_IPHDR + UDP_RHDRSIZE); if(bp == nil) return; bp->wp += UDP_IPHDR + UDP_RHDRSIZE; f = c->p->f; uh = (Udphdr *)(bp->rp); uh->vihl = IP_VER4; rh = (Rudphdr*)uh; ptcllen = (UDP_RHDRSIZE-UDP_PHDRSIZE); uh->Unused = 0; uh->udpproto = IP_UDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->udpplen, ptcllen); v6tov4(uh->udpdst, r->addr); hnputs(uh->udpdport, r->port); hnputs(uh->udpsport, c->lport); if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh->udpsrc, c->laddr); hnputs(uh->udplen, ptcllen); if(hangup) hnputl(rh->relsgen, Hangupgen); else hnputl(rh->relsgen, r->sndgen); hnputl(rh->relseq, 0); hnputl(rh->relagen, r->rcvgen); hnputl(rh->relack, r->rcvseq); if(r->acksent < r->rcvseq) r->acksent = r->rcvseq; uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, UDP_RHDRSIZE)); DPRINT("sendack: %lud/%lud, %lud/%lud\n", 0L, r->sndgen, r->rcvseq, r->rcvgen); doipoput(c, f, bp, 0, c->ttl, c->tos); }
void igmpsendreport(Medium *m, uchar *addr) { IGMPpkt *p; Block *bp; bp = allocb(sizeof(IGMPpkt)); if(bp == nil) return; p = (IGMPpkt*)bp->wp; p->vihl = IP_VER4; bp->wp += IGMPPKTSZ; memset(bp->rp, 0, IGMPPKTSZ); hnputl(p->src, Mediumgetaddr(m)); hnputl(p->dst, Ipallsys); p->vertype = (1<<4) | IGMPreport; p->proto = IP_IGMPPROTO; memmove(p->group, addr, IPaddrlen); hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)); netlog(Logigmp, "igmpreport %I\n", p->group); stats.outreports++; ipoput4(bp, 0, 1, DFLTTOS, nil); /* TTL of 1 */ }
void udpiput(struct Proto *udp, struct Ipifc *ifc, struct block *bp) { int len; Udp4hdr *uh4; Udp6hdr *uh6; struct conv *c; Udpcb *ucb; uint8_t raddr[IPaddrlen], laddr[IPaddrlen]; uint16_t rport, lport; Udppriv *upriv; struct Fs *f; int version; int ottl, oviclfl, olen; uint8_t *p; upriv = udp->priv; f = udp->f; upriv->ustats.udpInDatagrams++; uh4 = (Udp4hdr *) (bp->rp); version = ((uh4->vihl & 0xF0) == IP_VER6) ? V6 : V4; /* * 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 (!(bp->flag & Budpck) && (uh4->udpcksum[0] || uh4->udpcksum[1]) && ptclcsum(bp, UDP4_PHDR_OFF, len + UDP4_PHDR_SZ)) { upriv->ustats.udpInErrors++; netlog(f, Logudp, "udp: checksum error %I\n", raddr); printd("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); printd("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->qlock); c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); if (c == NULL) { /* no converstation found */ upriv->ustats.udpNoPorts++; qunlock(&udp->qlock); 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 == NULL) { qunlock(&udp->qlock); freeblist(bp); return; } iphtadd(&upriv->ht, c); ucb = (Udpcb *) c->ptcl; } } qlock(&c->qlock); qunlock(&udp->qlock); /* * 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 = NULL; panic("udpiput4: version %d", version); } if (bp == NULL) { qunlock(&c->qlock); 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->qlock); netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport, laddr, lport); freeblist(bp); return; } qpass(c->rq, bp); qunlock(&c->qlock); }
void udpkick(void *x, struct block *bp) { struct conv *c = x; Udp4hdr *uh4; Udp6hdr *uh6; uint16_t rport; uint8_t laddr[IPaddrlen], raddr[IPaddrlen]; Udpcb *ucb; int dlen, ptcllen; Udppriv *upriv; struct Fs *f; int version; struct conv *rc; upriv = c->p->priv; assert(upriv); f = c->p->f; netlog(c->p->f, Logudp, "udp: kick\n"); if (bp == NULL) return; ucb = (Udpcb *) c->ptcl; switch (ucb->headers) { case 7: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD7); if (bp == NULL) 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 == NULL) 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 = V4; else version = V6; } else { if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) version = V4; else version = V6; } 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 == NULL) 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 = NULL; } 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, UDP4_PHDR_SZ)); bp->checksum_start = UDP4_IPHDR_SZ; bp->checksum_offset = uh4->udpcksum - uh4->udpsport; bp->flag |= Budpck; 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 == NULL) 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 = NULL; } 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 igmpiput(Medium *m, Ipifc *, Block *bp) { int n; IGMPpkt *ghp; Ipaddr group; IGMPrep *rp, **lrp; Multicast *mp, **lmp; ghp = (IGMPpkt*)(bp->rp); netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group); n = blocklen(bp); if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){ netlog(Logigmp, "igmpiput: bad len\n"); goto error; } if((ghp->vertype>>4) != 1){ netlog(Logigmp, "igmpiput: bad igmp type\n"); goto error; } if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){ netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src); goto error; } group = nhgetl(ghp->group); lock(&igmpalloc); switch(ghp->vertype & 0xf){ case IGMPquery: /* * start reporting groups that we're a member of. */ stats.inqueries++; for(rp = igmpalloc.reports; rp; rp = rp->next) if(rp->m == m) break; if(rp != nil) break; /* already reporting */ mp = Mediumcopymulti(m); if(mp == nil) break; rp = malloc(sizeof(*rp)); if(rp == nil) break; rp->m = m; rp->multi = mp; rp->ticks = 0; for(; mp; mp = mp->next) mp->timeout = nrand(MAXTIMEOUT); rp->next = igmpalloc.reports; igmpalloc.reports = rp; wakeup(&igmpalloc.r); break; case IGMPreport: /* * find report list for this medium */ stats.inreports++; lrp = &igmpalloc.reports; for(rp = *lrp; rp; rp = *lrp){ if(rp->m == m) break; lrp = &rp->next; } if(rp == nil) break; /* * if someone else has reported a group, * we don't have to. */ lmp = &rp->multi; for(mp = *lmp; mp; mp = *lmp){ if(mp->addr == group){ *lmp = mp->next; free(mp); break; } lmp = &mp->next; } break; } unlock(&igmpalloc); error: freeb(bp); }
void rudpiput(Proto *rudp, Ipifc *ifc, Block *bp) { int len, olen, ottl; Udphdr *uh; Conv *c; Rudpcb *ucb; uint8_t raddr[IPaddrlen], laddr[IPaddrlen]; uint16_t rport, lport; Rudppriv *upriv; Fs *f; uint8_t *p; upriv = rudp->priv; f = rudp->f; upriv->ustats.rudpInDatagrams++; uh = (Udphdr*)(bp->rp); /* Put back pseudo header for checksum * (remember old values for icmpnoconv()) */ ottl = uh->Unused; uh->Unused = 0; len = nhgets(uh->udplen); olen = nhgets(uh->udpplen); hnputs(uh->udpplen, len); v4tov6(raddr, uh->udpsrc); v4tov6(laddr, uh->udpdst); lport = nhgets(uh->udpdport); rport = nhgets(uh->udpsport); if(nhgets(uh->udpcksum)) { if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { upriv->ustats.rudpInErrors++; upriv->csumerr++; netlog(f, Logrudp, "rudp: checksum error %I\n", raddr); DPRINT("rudp: checksum error %I\n", raddr); freeblist(bp); return; } } qlock(&rudp->ql); c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); if(c == nil){ /* no conversation found */ upriv->ustats.rudpNoPorts++; qunlock(&rudp->ql); netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport); uh->Unused = ottl; hnputs(uh->udpplen, olen); icmpnoconv(f, bp); freeblist(bp); return; } ucb = (Rudpcb*)c->ptcl; qlock(&ucb->ql); qunlock(&rudp->ql); if(reliput(c, bp, raddr, rport) < 0){ qunlock(&ucb->ql); freeb(bp); return; } /* * Trim the packet down to data size */ len -= (UDP_RHDRSIZE-UDP_PHDRSIZE); bp = trimblock(bp, UDP_IPHDR+UDP_RHDRSIZE, len); if(bp == nil) { netlog(f, Logrudp, "rudp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); DPRINT("rudp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); upriv->lenerr++; return; } netlog(f, Logrudpmsg, "rudp: %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; default: /* connection oriented rudp */ if(ipcmp(c->raddr, IPnoaddr) == 0){ /* save the src address in the conversation */ ipmove(c->raddr, raddr); c->rport = rport; /* reply with the same ip address (if not broadcast) */ if(ipforme(f, laddr) == Runi) ipmove(c->laddr, laddr); else v4tov6(c->laddr, ifc->lifc->local); } break; } if(bp->next) bp = concatblock(bp); if(qfull(c->rq)) { netlog(f, Logrudp, "rudp: qfull %I.%d -> %I.%d\n", raddr, rport, laddr, lport); freeblist(bp); } else qpass(c->rq, bp); qunlock(&ucb->ql); }
void rudpkick(void *x) { Proc *up = externup(); Conv *c = x; Udphdr *uh; uint16_t rport; uint8_t laddr[IPaddrlen], raddr[IPaddrlen]; Block *bp; Rudpcb *ucb; Rudphdr *rh; Reliable *r; int dlen, ptcllen; Rudppriv *upriv; Fs *f; upriv = c->p->priv; f = c->p->f; netlog(c->p->f, Logrudp, "rudp: kick\n"); bp = qget(c->wq); if(bp == nil) return; ucb = (Rudpcb*)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; default: ipmove(raddr, c->raddr); ipmove(laddr, c->laddr); rport = c->rport; break; } dlen = blocklen(bp); /* Make space to fit rudp & ip header */ bp = padblock(bp, UDP_IPHDR+UDP_RHDRSIZE); if(bp == nil) return; uh = (Udphdr *)(bp->rp); uh->vihl = IP_VER4; rh = (Rudphdr*)uh; ptcllen = dlen + (UDP_RHDRSIZE-UDP_PHDRSIZE); uh->Unused = 0; uh->udpproto = IP_UDPPROTO; uh->frag[0] = 0; uh->frag[1] = 0; hnputs(uh->udpplen, ptcllen); switch(ucb->headers){ case 7: v6tov4(uh->udpdst, raddr); hnputs(uh->udpdport, rport); v6tov4(uh->udpsrc, laddr); break; default: v6tov4(uh->udpdst, c->raddr); hnputs(uh->udpdport, c->rport); if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh->udpsrc, c->laddr); break; } hnputs(uh->udpsport, c->lport); hnputs(uh->udplen, ptcllen); uh->udpcksum[0] = 0; uh->udpcksum[1] = 0; qlock(&ucb->ql); r = relstate(ucb, raddr, rport, "kick"); r->sndseq = NEXTSEQ(r->sndseq); hnputl(rh->relseq, r->sndseq); hnputl(rh->relsgen, r->sndgen); hnputl(rh->relack, r->rcvseq); /* ACK last rcvd packet */ hnputl(rh->relagen, r->rcvgen); if(r->rcvseq != r->acksent) r->acksent = r->rcvseq; hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE)); relackq(r, bp); qunlock(&ucb->ql); upriv->ustats.rudpOutDatagrams++; DPRINT("sent: %lud/%lud, %lud/%lud\n", r->sndseq, r->sndgen, r->rcvseq, r->rcvgen); doipoput(c, f, bp, 0, c->ttl, c->tos); if(waserror()) { relput(r); qunlock(&r->lock); nexterror(); } /* flow control of sorts */ qlock(&r->lock); if(UNACKED(r) > Maxunacked){ r->blocked = 1; sleep(&r->vous, flow, r); r->blocked = 0; } qunlock(&r->lock); relput(r); poperror(); }