Index: head/stand/libsa/ip.c =================================================================== --- head/stand/libsa/ip.c (revision 339969) +++ head/stand/libsa/ip.c (revision 339970) @@ -1,428 +1,427 @@ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * The send and receive functions were originally implemented in udp.c and * moved here. Also it is likely some more cleanup can be done, especially * once we will implement the support for tcp. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include -#include #include #include #include #include #include "stand.h" #include "net.h" typedef STAILQ_HEAD(ipqueue, ip_queue) ip_queue_t; struct ip_queue { void *ipq_pkt; struct ip *ipq_hdr; STAILQ_ENTRY(ip_queue) ipq_next; }; /* * Fragment re-assembly queue. */ struct ip_reasm { struct in_addr ip_src; struct in_addr ip_dst; uint16_t ip_id; uint8_t ip_proto; uint8_t ip_ttl; size_t ip_total_size; ip_queue_t ip_queue; void *ip_pkt; struct ip *ip_hdr; STAILQ_ENTRY(ip_reasm) ip_next; }; STAILQ_HEAD(ire_list, ip_reasm) ire_list = STAILQ_HEAD_INITIALIZER(ire_list); /* Caller must leave room for ethernet and ip headers in front!! */ ssize_t sendip(struct iodesc *d, void *pkt, size_t len, uint8_t proto) { ssize_t cc; struct ip *ip; u_char *ea; #ifdef NET_DEBUG if (debug) { printf("sendip: proto: %x d=%p called.\n", proto, (void *)d); if (d) { printf("saddr: %s:%d", inet_ntoa(d->myip), ntohs(d->myport)); printf(" daddr: %s:%d\n", inet_ntoa(d->destip), ntohs(d->destport)); } } #endif ip = (struct ip *)pkt - 1; len += sizeof(*ip); bzero(ip, sizeof(*ip)); ip->ip_v = IPVERSION; /* half-char */ ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ ip->ip_len = htons(len); ip->ip_p = proto; /* char */ ip->ip_ttl = IPDEFTTL; /* char */ ip->ip_src = d->myip; ip->ip_dst = d->destip; ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) ea = arpwhohas(d, ip->ip_dst); else ea = arpwhohas(d, gateip); cc = sendether(d, ip, len, ea, ETHERTYPE_IP); if (cc == -1) return (-1); if (cc != len) panic("sendip: bad write (%zd != %zd)", cc, len); return (cc - sizeof(*ip)); } static void ip_reasm_free(struct ip_reasm *ipr) { struct ip_queue *ipq; while ((ipq = STAILQ_FIRST(&ipr->ip_queue)) != NULL) { STAILQ_REMOVE_HEAD(&ipr->ip_queue, ipq_next); free(ipq->ipq_pkt); free(ipq); } free(ipr->ip_pkt); free(ipr); } static int ip_reasm_add(struct ip_reasm *ipr, void *pkt, struct ip *ip) { struct ip_queue *ipq, *prev, *p; if ((ipq = calloc(1, sizeof (*ipq))) == NULL) return (1); ipq->ipq_pkt = pkt; ipq->ipq_hdr = ip; prev = NULL; STAILQ_FOREACH(p, &ipr->ip_queue, ipq_next) { if ((ntohs(p->ipq_hdr->ip_off) & IP_OFFMASK) < (ntohs(ip->ip_off) & IP_OFFMASK)) { prev = p; continue; } if (prev == NULL) break; STAILQ_INSERT_AFTER(&ipr->ip_queue, prev, ipq, ipq_next); return (0); } STAILQ_INSERT_HEAD(&ipr->ip_queue, ipq, ipq_next); return (0); } /* * Receive a IP packet and validate it is for us. */ static ssize_t readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, uint8_t proto) { ssize_t n; size_t hlen; struct ether_header *eh; struct ip *ip; struct udphdr *uh; uint16_t etype; /* host order */ char *ptr; struct ip_reasm *ipr; struct ip_queue *ipq, *last; #ifdef NET_DEBUG if (debug) printf("readip: called\n"); #endif ip = NULL; ptr = NULL; n = readether(d, (void **)&ptr, (void **)&ip, tleft, &etype); if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) { free(ptr); return (-1); } /* Ethernet address checks now in readether() */ /* Need to respond to ARP requests. */ if (etype == ETHERTYPE_ARP) { struct arphdr *ah = (void *)ip; if (ah->ar_op == htons(ARPOP_REQUEST)) { /* Send ARP reply */ arp_reply(d, ah); } free(ptr); errno = EAGAIN; /* Call me again. */ return (-1); } if (etype != ETHERTYPE_IP) { #ifdef NET_DEBUG if (debug) printf("readip: not IP. ether_type=%x\n", etype); #endif free(ptr); return (-1); } /* Check ip header */ if (ip->ip_v != IPVERSION || /* half char */ ip->ip_p != proto) { #ifdef NET_DEBUG if (debug) { printf("readip: IP version or proto. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); } #endif free(ptr); return (-1); } hlen = ip->ip_hl << 2; if (hlen < sizeof(*ip) || in_cksum(ip, hlen) != 0) { #ifdef NET_DEBUG if (debug) printf("readip: short hdr or bad cksum.\n"); #endif free(ptr); return (-1); } if (n < ntohs(ip->ip_len)) { #ifdef NET_DEBUG if (debug) printf("readip: bad length %d < %d.\n", (int)n, ntohs(ip->ip_len)); #endif free(ptr); return (-1); } if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { #ifdef NET_DEBUG if (debug) { printf("readip: bad saddr %s != ", inet_ntoa(d->myip)); printf("%s\n", inet_ntoa(ip->ip_dst)); } #endif free(ptr); return (-1); } /* Unfragmented packet. */ if ((ntohs(ip->ip_off) & IP_MF) == 0 && (ntohs(ip->ip_off) & IP_OFFMASK) == 0) { uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip)); /* If there were ip options, make them go away */ if (hlen != sizeof(*ip)) { bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); ip->ip_len = htons(sizeof(*ip)); n -= hlen - sizeof(*ip); } n = (n > (ntohs(ip->ip_len) - sizeof(*ip))) ? ntohs(ip->ip_len) - sizeof(*ip) : n; *pkt = ptr; *payload = (void *)((uintptr_t)ip + sizeof(*ip)); return (n); } STAILQ_FOREACH(ipr, &ire_list, ip_next) { if (ipr->ip_src.s_addr == ip->ip_src.s_addr && ipr->ip_dst.s_addr == ip->ip_dst.s_addr && ipr->ip_id == ip->ip_id && ipr->ip_proto == ip->ip_p) break; } /* Allocate new reassembly entry */ if (ipr == NULL) { if ((ipr = calloc(1, sizeof (*ipr))) == NULL) { free(ptr); return (-1); } ipr->ip_src = ip->ip_src; ipr->ip_dst = ip->ip_dst; ipr->ip_id = ip->ip_id; ipr->ip_proto = ip->ip_p; ipr->ip_ttl = MAXTTL; STAILQ_INIT(&ipr->ip_queue); STAILQ_INSERT_TAIL(&ire_list, ipr, ip_next); } if (ip_reasm_add(ipr, ptr, ip) != 0) { STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); free(ipr); free(ptr); return (-1); } if ((ntohs(ip->ip_off) & IP_MF) == 0) { ipr->ip_total_size = (8 * (ntohs(ip->ip_off) & IP_OFFMASK)); ipr->ip_total_size += n + sizeof (*ip); ipr->ip_total_size += sizeof (struct ether_header); ipr->ip_pkt = malloc(ipr->ip_total_size + 2); if (ipr->ip_pkt == NULL) { STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); ip_reasm_free(ipr); return (-1); } } /* * If we do not have re-assembly buffer ipr->ip_pkt, we are still * missing fragments, so just restart the read. */ if (ipr->ip_pkt == NULL) { errno = EAGAIN; return (-1); } /* * Walk the packet list in reassembly queue, if we got all the * fragments, build the packet. */ n = 0; last = NULL; STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { if ((ntohs(ipq->ipq_hdr->ip_off) & IP_OFFMASK) != n / 8) { STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); ip_reasm_free(ipr); return (-1); } n += ntohs(ipq->ipq_hdr->ip_len) - (ipq->ipq_hdr->ip_hl << 2); last = ipq; } if ((ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0) { errno = EAGAIN; return (-1); } ipq = STAILQ_FIRST(&ipr->ip_queue); /* Fabricate ethernet header */ eh = (struct ether_header *)((uintptr_t)ipr->ip_pkt + 2); bcopy((void *)((uintptr_t)ipq->ipq_pkt + 2), eh, sizeof (*eh)); /* Fabricate IP header */ ipr->ip_hdr = (struct ip *)((uintptr_t)eh + sizeof (*eh)); bcopy(ipq->ipq_hdr, ipr->ip_hdr, sizeof (*ipr->ip_hdr)); ipr->ip_hdr->ip_hl = sizeof (*ipr->ip_hdr) >> 2; ipr->ip_hdr->ip_len = htons(n); ipr->ip_hdr->ip_sum = 0; ipr->ip_hdr->ip_sum = in_cksum(ipr->ip_hdr, sizeof (*ipr->ip_hdr)); n = 0; ptr = (char *)((uintptr_t)ipr->ip_hdr + sizeof (*ipr->ip_hdr)); STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { char *data; size_t len; hlen = ipq->ipq_hdr->ip_hl << 2; len = ntohs(ipq->ipq_hdr->ip_len) - hlen; data = (char *)((uintptr_t)ipq->ipq_hdr + hlen); bcopy(data, ptr + n, len); n += len; } *pkt = ipr->ip_pkt; ipr->ip_pkt = NULL; /* Avoid free from ip_reasm_free() */ *payload = ptr; /* Clean up the reassembly list */ while ((ipr = STAILQ_FIRST(&ire_list)) != NULL) { STAILQ_REMOVE_HEAD(&ire_list, ip_next); ip_reasm_free(ipr); } return (n); } /* * Receive a IP packet. */ ssize_t readip(struct iodesc *d, void **pkt, void **payload, time_t tleft, uint8_t proto) { time_t t; ssize_t ret = -1; t = getsecs(); while ((getsecs() - t) < tleft) { errno = 0; ret = readipv4(d, pkt, payload, tleft, proto); if (ret >= 0) return (ret); /* Bubble up the error if it wasn't successful */ if (errno != EAGAIN) return (-1); } /* We've exhausted tleft; timeout */ errno = ETIMEDOUT; return (-1); } Index: head/stand/libsa/net.c =================================================================== --- head/stand/libsa/net.c (revision 339969) +++ head/stand/libsa/net.c (revision 339970) @@ -1,303 +1,302 @@ /* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include -#include #include #include #include #include #include "stand.h" #include "net.h" /* * Maximum wait time for sending and receiving before we give up and timeout. * If set to 0, operations will eventually timeout completely, but send/recv * timeouts must progress exponentially from MINTMO to MAXTMO before final * timeout is hit. */ #ifndef MAXWAIT #define MAXWAIT 0 /* seconds */ #endif #if MAXWAIT < 0 #error MAXWAIT must not be a negative number #endif /* * Send a packet and wait for a reply, with exponential backoff. * * The send routine must return the actual number of bytes written, * or -1 on error. * * The receive routine can indicate success by returning the number of * bytes read; it can return 0 to indicate EOF; it can return -1 with a * non-zero errno to indicate failure; finally, it can return -1 with a * zero errno to indicate it isn't done yet. */ ssize_t sendrecv(struct iodesc *d, ssize_t (*sproc)(struct iodesc *, void *, size_t), void *sbuf, size_t ssize, ssize_t (*rproc)(struct iodesc *, void **, void **, time_t, void *), void **pkt, void **payload, void *recv_extra) { ssize_t cc; time_t t, tmo, tlast; time_t tref; long tleft; #ifdef NET_DEBUG if (debug) printf("sendrecv: called\n"); #endif tmo = MINTMO; tlast = 0; tleft = 0; tref = getsecs(); t = getsecs(); for (;;) { if (MAXWAIT > 0 && (getsecs() - tref) >= MAXWAIT) { errno = ETIMEDOUT; return -1; } if (tleft <= 0) { if (tmo >= MAXTMO) { errno = ETIMEDOUT; return -1; } cc = (*sproc)(d, sbuf, ssize); if (cc != -1 && cc < ssize) panic("sendrecv: short write! (%zd < %zd)", cc, ssize); tleft = tmo; tmo += MINTMO; if (tmo > MAXTMO) tmo = MAXTMO; if (cc == -1) { /* Error on transmit; wait before retrying */ while ((getsecs() - t) < tmo) ; tleft = 0; continue; } tlast = t; } /* Try to get a packet and process it. */ cc = (*rproc)(d, pkt, payload, tleft, recv_extra); /* Return on data, EOF or real error. */ if (cc != -1 || (errno != 0 && errno != ETIMEDOUT)) return (cc); /* Timed out or didn't get the packet we're waiting for */ t = getsecs(); tleft -= t - tlast; tlast = t; } } /* * Like inet_addr() in the C library, but we only accept base-10. * Return values are in network order. */ n_long inet_addr(char *cp) { u_long val; int n; char c; u_int parts[4]; u_int *pp = parts; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, other=decimal. */ val = 0; while ((c = *cp) != '\0') { if (c >= '0' && c <= '9') { val = (val * 10) + (c - '0'); cp++; continue; } break; } if (*cp == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16-bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3 || val > 0xff) goto bad; *pp++ = val, cp++; } else break; } /* * Check for trailing characters. */ if (*cp != '\0') goto bad; /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; switch (n) { case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (val > 0xffffff) goto bad; val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if (val > 0xffff) goto bad; val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xff) goto bad; val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } return (htonl(val)); bad: return (htonl(INADDR_NONE)); } char * inet_ntoa(struct in_addr ia) { return (intoa(ia.s_addr)); } /* Similar to inet_ntoa() */ char * intoa(n_long addr) { char *cp; u_int byte; int n; static char buf[17]; /* strlen(".255.255.255.255") + 1 */ addr = ntohl(addr); cp = &buf[sizeof buf]; *--cp = '\0'; n = 4; do { byte = addr & 0xff; *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) { *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) *--cp = byte + '0'; } *--cp = '.'; addr >>= 8; } while (--n > 0); return (cp+1); } static char * number(char *s, n_long *n) { for (*n = 0; isdigit(*s); s++) *n = (*n * 10) + *s - '0'; return s; } n_long ip_convertaddr(char *p) { #define IP_ANYADDR 0 n_long addr = 0, n; if (p == NULL || *p == '\0') return IP_ANYADDR; p = number(p, &n); addr |= (n << 24) & 0xff000000; if (*p == '\0' || *p++ != '.') return IP_ANYADDR; p = number(p, &n); addr |= (n << 16) & 0xff0000; if (*p == '\0' || *p++ != '.') return IP_ANYADDR; p = number(p, &n); addr |= (n << 8) & 0xff00; if (*p == '\0' || *p++ != '.') return IP_ANYADDR; p = number(p, &n); addr |= n & 0xff; if (*p != '\0') return IP_ANYADDR; return htonl(addr); } Index: head/stand/libsa/udp.c =================================================================== --- head/stand/libsa/udp.c (revision 339969) +++ head/stand/libsa/udp.c (revision 339970) @@ -1,180 +1,179 @@ /* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include -#include #include #include #include #include #include "stand.h" #include "net.h" /* Caller must leave room for ethernet, ip and udp headers in front!! */ ssize_t sendudp(struct iodesc *d, void *pkt, size_t len) { ssize_t cc; struct udpiphdr *ui; struct udphdr *uh; #ifdef NET_DEBUG if (debug) { printf("sendudp: d=%lx called.\n", (long)d); if (d) { printf("saddr: %s:%d", inet_ntoa(d->myip), ntohs(d->myport)); printf(" daddr: %s:%d\n", inet_ntoa(d->destip), ntohs(d->destport)); } } #endif ui = (struct udpiphdr *)pkt - 1; bzero(ui, sizeof(*ui)); uh = (struct udphdr *)pkt - 1; len += sizeof(*uh); uh->uh_sport = d->myport; uh->uh_dport = d->destport; uh->uh_ulen = htons(len); ui->ui_pr = IPPROTO_UDP; ui->ui_len = uh->uh_ulen; ui->ui_src = d->myip; ui->ui_dst = d->destip; #ifndef UDP_NO_CKSUM uh->uh_sum = in_cksum(ui, len + sizeof (struct ip)); #endif cc = sendip(d, uh, len, IPPROTO_UDP); if (cc == -1) return (-1); if (cc != len) panic("sendudp: bad write (%zd != %zd)", cc, len); return (cc - sizeof(*uh)); } /* * Receive a UDP packet and validate it is for us. */ ssize_t readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft) { ssize_t n; struct udphdr *uh; void *ptr; #ifdef NET_DEBUG if (debug) printf("readudp: called\n"); #endif uh = NULL; ptr = NULL; n = readip(d, &ptr, (void **)&uh, tleft, IPPROTO_UDP); if (n == -1 || n < sizeof(*uh) || n != ntohs(uh->uh_ulen)) { free(ptr); return (-1); } if (uh->uh_dport != d->myport) { #ifdef NET_DEBUG if (debug) printf("readudp: bad dport %d != %d\n", d->myport, ntohs(uh->uh_dport)); #endif free(ptr); return (-1); } #ifndef UDP_NO_CKSUM if (uh->uh_sum) { struct udpiphdr *ui; struct ip *ip; struct ip tip; n = ntohs(uh->uh_ulen) + sizeof(*ip); /* Check checksum (must save and restore ip header) */ ip = (struct ip *)uh - 1; tip = *ip; ui = (struct udpiphdr *)ip; bzero(&ui->ui_x1, sizeof(ui->ui_x1)); ui->ui_len = uh->uh_ulen; if (in_cksum(ui, n) != 0) { #ifdef NET_DEBUG if (debug) printf("readudp: bad cksum\n"); #endif free(ptr); return (-1); } *ip = tip; } #endif if (ntohs(uh->uh_ulen) < sizeof(*uh)) { #ifdef NET_DEBUG if (debug) printf("readudp: bad udp len %d < %d\n", ntohs(uh->uh_ulen), (int)sizeof(*uh)); #endif free(ptr); return (-1); } n = (n > (ntohs(uh->uh_ulen) - sizeof(*uh))) ? ntohs(uh->uh_ulen) - sizeof(*uh) : n; *pkt = ptr; *payload = (void *)((uintptr_t)uh + sizeof(*uh)); return (n); }