1a4a2722fSToomas Soome /* 2a4a2722fSToomas Soome * Copyright (c) 1992 Regents of the University of California. 3a4a2722fSToomas Soome * All rights reserved. 4a4a2722fSToomas Soome * 5a4a2722fSToomas Soome * This software was developed by the Computer Systems Engineering group 6a4a2722fSToomas Soome * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7a4a2722fSToomas Soome * contributed to Berkeley. 8a4a2722fSToomas Soome * 9a4a2722fSToomas Soome * Redistribution and use in source and binary forms, with or without 10a4a2722fSToomas Soome * modification, are permitted provided that the following conditions 11a4a2722fSToomas Soome * are met: 12a4a2722fSToomas Soome * 1. Redistributions of source code must retain the above copyright 13a4a2722fSToomas Soome * notice, this list of conditions and the following disclaimer. 14a4a2722fSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 15a4a2722fSToomas Soome * notice, this list of conditions and the following disclaimer in the 16a4a2722fSToomas Soome * documentation and/or other materials provided with the distribution. 17a4a2722fSToomas Soome * 3. Neither the name of the University nor the names of its contributors 18a4a2722fSToomas Soome * may be used to endorse or promote products derived from this software 19a4a2722fSToomas Soome * without specific prior written permission. 20a4a2722fSToomas Soome * 21a4a2722fSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22a4a2722fSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23a4a2722fSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24a4a2722fSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25a4a2722fSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26a4a2722fSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27a4a2722fSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28a4a2722fSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29a4a2722fSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30a4a2722fSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31a4a2722fSToomas Soome * SUCH DAMAGE. 32a4a2722fSToomas Soome */ 33a4a2722fSToomas Soome 34a4a2722fSToomas Soome /* 35a4a2722fSToomas Soome * The send and receive functions were originally implemented in udp.c and 36a4a2722fSToomas Soome * moved here. Also it is likely some more cleanup can be done, especially 37a4a2722fSToomas Soome * once we will implement the support for tcp. 38a4a2722fSToomas Soome */ 39a4a2722fSToomas Soome 40a4a2722fSToomas Soome #include <sys/cdefs.h> 41a4a2722fSToomas Soome 42a4a2722fSToomas Soome #include <sys/param.h> 43a4a2722fSToomas Soome #include <sys/socket.h> 44a4a2722fSToomas Soome #include <sys/queue.h> 45a4a2722fSToomas Soome 46a4a2722fSToomas Soome #include <string.h> 47a4a2722fSToomas Soome 48a4a2722fSToomas Soome #include <net/if.h> 49a4a2722fSToomas Soome #include <netinet/in.h> 50a4a2722fSToomas Soome #include <netinet/if_ether.h> 51a4a2722fSToomas Soome #include <netinet/in_systm.h> 52a4a2722fSToomas Soome 53a4a2722fSToomas Soome #include <netinet/in_pcb.h> 54a4a2722fSToomas Soome #include <netinet/ip.h> 55a4a2722fSToomas Soome #include <netinet/ip_var.h> 56a4a2722fSToomas Soome #include <netinet/udp.h> 57a4a2722fSToomas Soome #include <netinet/udp_var.h> 58a4a2722fSToomas Soome 59a4a2722fSToomas Soome #include "stand.h" 60a4a2722fSToomas Soome #include "net.h" 61a4a2722fSToomas Soome 62a4a2722fSToomas Soome typedef STAILQ_HEAD(ipqueue, ip_queue) ip_queue_t; 63a4a2722fSToomas Soome struct ip_queue { 64a4a2722fSToomas Soome void *ipq_pkt; 65a4a2722fSToomas Soome struct ip *ipq_hdr; 66a4a2722fSToomas Soome STAILQ_ENTRY(ip_queue) ipq_next; 67a4a2722fSToomas Soome }; 68a4a2722fSToomas Soome 69a4a2722fSToomas Soome /* 70a4a2722fSToomas Soome * Fragment re-assembly queue. 71a4a2722fSToomas Soome */ 72a4a2722fSToomas Soome struct ip_reasm { 73a4a2722fSToomas Soome struct in_addr ip_src; 74a4a2722fSToomas Soome struct in_addr ip_dst; 75a4a2722fSToomas Soome uint16_t ip_id; 76a4a2722fSToomas Soome uint8_t ip_proto; 77a4a2722fSToomas Soome uint8_t ip_ttl; 78a4a2722fSToomas Soome size_t ip_total_size; 79a4a2722fSToomas Soome ip_queue_t ip_queue; 80a4a2722fSToomas Soome void *ip_pkt; 81a4a2722fSToomas Soome struct ip *ip_hdr; 82a4a2722fSToomas Soome STAILQ_ENTRY(ip_reasm) ip_next; 83a4a2722fSToomas Soome }; 84a4a2722fSToomas Soome 85a4a2722fSToomas Soome STAILQ_HEAD(ire_list, ip_reasm) ire_list = STAILQ_HEAD_INITIALIZER(ire_list); 86a4a2722fSToomas Soome 87a4a2722fSToomas Soome /* Caller must leave room for ethernet and ip headers in front!! */ 88a4a2722fSToomas Soome ssize_t 89a4a2722fSToomas Soome sendip(struct iodesc *d, void *pkt, size_t len, uint8_t proto) 90a4a2722fSToomas Soome { 91a4a2722fSToomas Soome ssize_t cc; 92a4a2722fSToomas Soome struct ip *ip; 93a4a2722fSToomas Soome u_char *ea; 94a4a2722fSToomas Soome 95a4a2722fSToomas Soome #ifdef NET_DEBUG 96a4a2722fSToomas Soome if (debug) { 97a4a2722fSToomas Soome printf("sendip: proto: %x d=%p called.\n", proto, (void *)d); 98a4a2722fSToomas Soome if (d) { 99a4a2722fSToomas Soome printf("saddr: %s:%d", 100a4a2722fSToomas Soome inet_ntoa(d->myip), ntohs(d->myport)); 101a4a2722fSToomas Soome printf(" daddr: %s:%d\n", 102a4a2722fSToomas Soome inet_ntoa(d->destip), ntohs(d->destport)); 103a4a2722fSToomas Soome } 104a4a2722fSToomas Soome } 105a4a2722fSToomas Soome #endif 106a4a2722fSToomas Soome 107a4a2722fSToomas Soome ip = (struct ip *)pkt - 1; 108a4a2722fSToomas Soome len += sizeof(*ip); 109a4a2722fSToomas Soome 110a4a2722fSToomas Soome bzero(ip, sizeof(*ip)); 111a4a2722fSToomas Soome 112a4a2722fSToomas Soome ip->ip_v = IPVERSION; /* half-char */ 113a4a2722fSToomas Soome ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ 114a4a2722fSToomas Soome ip->ip_len = htons(len); 115a4a2722fSToomas Soome ip->ip_p = proto; /* char */ 116a4a2722fSToomas Soome ip->ip_ttl = IPDEFTTL; /* char */ 117a4a2722fSToomas Soome ip->ip_src = d->myip; 118a4a2722fSToomas Soome ip->ip_dst = d->destip; 119a4a2722fSToomas Soome ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ 120a4a2722fSToomas Soome 121a4a2722fSToomas Soome if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || 122a4a2722fSToomas Soome netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) 123a4a2722fSToomas Soome ea = arpwhohas(d, ip->ip_dst); 124a4a2722fSToomas Soome else 125a4a2722fSToomas Soome ea = arpwhohas(d, gateip); 126a4a2722fSToomas Soome 127a4a2722fSToomas Soome cc = sendether(d, ip, len, ea, ETHERTYPE_IP); 128a4a2722fSToomas Soome if (cc == -1) 129a4a2722fSToomas Soome return (-1); 130a4a2722fSToomas Soome if (cc != len) 131a4a2722fSToomas Soome panic("sendip: bad write (%zd != %zd)", cc, len); 132a4a2722fSToomas Soome return (cc - sizeof(*ip)); 133a4a2722fSToomas Soome } 134a4a2722fSToomas Soome 135a4a2722fSToomas Soome static void 136a4a2722fSToomas Soome ip_reasm_free(struct ip_reasm *ipr) 137a4a2722fSToomas Soome { 138a4a2722fSToomas Soome struct ip_queue *ipq; 139a4a2722fSToomas Soome 140a4a2722fSToomas Soome while ((ipq = STAILQ_FIRST(&ipr->ip_queue)) != NULL) { 141a4a2722fSToomas Soome STAILQ_REMOVE_HEAD(&ipr->ip_queue, ipq_next); 142a4a2722fSToomas Soome free(ipq->ipq_pkt); 143a4a2722fSToomas Soome free(ipq); 144a4a2722fSToomas Soome } 145a4a2722fSToomas Soome free(ipr->ip_pkt); 146a4a2722fSToomas Soome free(ipr); 147a4a2722fSToomas Soome } 148a4a2722fSToomas Soome 149a4a2722fSToomas Soome static int 150a4a2722fSToomas Soome ip_reasm_add(struct ip_reasm *ipr, void *pkt, struct ip *ip) 151a4a2722fSToomas Soome { 152a4a2722fSToomas Soome struct ip_queue *ipq, *prev, *p; 153a4a2722fSToomas Soome 154a4a2722fSToomas Soome if ((ipq = calloc(1, sizeof (*ipq))) == NULL) 155a4a2722fSToomas Soome return (1); 156a4a2722fSToomas Soome 157a4a2722fSToomas Soome ipq->ipq_pkt = pkt; 158a4a2722fSToomas Soome ipq->ipq_hdr = ip; 159a4a2722fSToomas Soome 160a4a2722fSToomas Soome prev = NULL; 161a4a2722fSToomas Soome STAILQ_FOREACH(p, &ipr->ip_queue, ipq_next) { 162a4a2722fSToomas Soome if ((ntohs(p->ipq_hdr->ip_off) & IP_OFFMASK) < 163a4a2722fSToomas Soome (ntohs(ip->ip_off) & IP_OFFMASK)) { 164a4a2722fSToomas Soome prev = p; 165a4a2722fSToomas Soome continue; 166a4a2722fSToomas Soome } 167a4a2722fSToomas Soome if (prev == NULL) 168a4a2722fSToomas Soome break; 169a4a2722fSToomas Soome 170a4a2722fSToomas Soome STAILQ_INSERT_AFTER(&ipr->ip_queue, prev, ipq, ipq_next); 171a4a2722fSToomas Soome return (0); 172a4a2722fSToomas Soome } 173a4a2722fSToomas Soome STAILQ_INSERT_HEAD(&ipr->ip_queue, ipq, ipq_next); 174a4a2722fSToomas Soome return (0); 175a4a2722fSToomas Soome } 176a4a2722fSToomas Soome 177a4a2722fSToomas Soome /* 178a4a2722fSToomas Soome * Receive a IP packet and validate it is for us. 179a4a2722fSToomas Soome */ 180a4a2722fSToomas Soome static ssize_t 181a4a2722fSToomas Soome readipv4(struct iodesc *d, void **pkt, void **payload, time_t tleft, 182a4a2722fSToomas Soome uint8_t proto) 183a4a2722fSToomas Soome { 184a4a2722fSToomas Soome ssize_t n; 185a4a2722fSToomas Soome size_t hlen; 186a4a2722fSToomas Soome struct ether_header *eh; 187a4a2722fSToomas Soome struct ip *ip; 188a4a2722fSToomas Soome struct udphdr *uh; 189a4a2722fSToomas Soome uint16_t etype; /* host order */ 190a4a2722fSToomas Soome char *ptr; 191a4a2722fSToomas Soome struct ip_reasm *ipr; 192a4a2722fSToomas Soome struct ip_queue *ipq, *last; 193a4a2722fSToomas Soome 194a4a2722fSToomas Soome #ifdef NET_DEBUG 195a4a2722fSToomas Soome if (debug) 196a4a2722fSToomas Soome printf("readip: called\n"); 197a4a2722fSToomas Soome #endif 198a4a2722fSToomas Soome 199a4a2722fSToomas Soome ip = NULL; 200a4a2722fSToomas Soome ptr = NULL; 201a4a2722fSToomas Soome n = readether(d, (void **)&ptr, (void **)&ip, tleft, &etype); 202a4a2722fSToomas Soome if (n == -1 || n < sizeof(*ip) + sizeof(*uh)) { 203a4a2722fSToomas Soome free(ptr); 204a4a2722fSToomas Soome return (-1); 205a4a2722fSToomas Soome } 206a4a2722fSToomas Soome 207a4a2722fSToomas Soome /* Ethernet address checks now in readether() */ 208a4a2722fSToomas Soome 209a4a2722fSToomas Soome /* Need to respond to ARP requests. */ 210a4a2722fSToomas Soome if (etype == ETHERTYPE_ARP) { 211a4a2722fSToomas Soome struct arphdr *ah = (void *)ip; 212a4a2722fSToomas Soome if (ah->ar_op == htons(ARPOP_REQUEST)) { 213a4a2722fSToomas Soome /* Send ARP reply */ 214a4a2722fSToomas Soome arp_reply(d, ah); 215a4a2722fSToomas Soome } 216a4a2722fSToomas Soome free(ptr); 217a4a2722fSToomas Soome errno = EAGAIN; /* Call me again. */ 218a4a2722fSToomas Soome return (-1); 219a4a2722fSToomas Soome } 220a4a2722fSToomas Soome 221a4a2722fSToomas Soome if (etype != ETHERTYPE_IP) { 222a4a2722fSToomas Soome #ifdef NET_DEBUG 223a4a2722fSToomas Soome if (debug) 224a4a2722fSToomas Soome printf("readip: not IP. ether_type=%x\n", etype); 225a4a2722fSToomas Soome #endif 226a4a2722fSToomas Soome free(ptr); 227a4a2722fSToomas Soome return (-1); 228a4a2722fSToomas Soome } 229a4a2722fSToomas Soome 230a4a2722fSToomas Soome /* Check ip header */ 231a4a2722fSToomas Soome if (ip->ip_v != IPVERSION || /* half char */ 232a4a2722fSToomas Soome ip->ip_p != proto) { 233a4a2722fSToomas Soome #ifdef NET_DEBUG 234a4a2722fSToomas Soome if (debug) { 235a4a2722fSToomas Soome printf("readip: IP version or proto. ip_v=%d ip_p=%d\n", 236a4a2722fSToomas Soome ip->ip_v, ip->ip_p); 237a4a2722fSToomas Soome } 238a4a2722fSToomas Soome #endif 239a4a2722fSToomas Soome free(ptr); 240a4a2722fSToomas Soome return (-1); 241a4a2722fSToomas Soome } 242a4a2722fSToomas Soome 243a4a2722fSToomas Soome hlen = ip->ip_hl << 2; 244a4a2722fSToomas Soome if (hlen < sizeof(*ip) || 245a4a2722fSToomas Soome in_cksum(ip, hlen) != 0) { 246a4a2722fSToomas Soome #ifdef NET_DEBUG 247a4a2722fSToomas Soome if (debug) 248a4a2722fSToomas Soome printf("readip: short hdr or bad cksum.\n"); 249a4a2722fSToomas Soome #endif 250a4a2722fSToomas Soome free(ptr); 251a4a2722fSToomas Soome return (-1); 252a4a2722fSToomas Soome } 253a4a2722fSToomas Soome if (n < ntohs(ip->ip_len)) { 254a4a2722fSToomas Soome #ifdef NET_DEBUG 255a4a2722fSToomas Soome if (debug) 256a4a2722fSToomas Soome printf("readip: bad length %d < %d.\n", 257a4a2722fSToomas Soome (int)n, ntohs(ip->ip_len)); 258a4a2722fSToomas Soome #endif 259a4a2722fSToomas Soome free(ptr); 260a4a2722fSToomas Soome return (-1); 261a4a2722fSToomas Soome } 262a4a2722fSToomas Soome if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) { 263a4a2722fSToomas Soome #ifdef NET_DEBUG 264a4a2722fSToomas Soome if (debug) { 265a4a2722fSToomas Soome printf("readip: bad saddr %s != ", inet_ntoa(d->myip)); 266a4a2722fSToomas Soome printf("%s\n", inet_ntoa(ip->ip_dst)); 267a4a2722fSToomas Soome } 268a4a2722fSToomas Soome #endif 269a4a2722fSToomas Soome free(ptr); 270a4a2722fSToomas Soome return (-1); 271a4a2722fSToomas Soome } 272a4a2722fSToomas Soome 273a4a2722fSToomas Soome /* Unfragmented packet. */ 274a4a2722fSToomas Soome if ((ntohs(ip->ip_off) & IP_MF) == 0 && 275a4a2722fSToomas Soome (ntohs(ip->ip_off) & IP_OFFMASK) == 0) { 276a4a2722fSToomas Soome uh = (struct udphdr *)((uintptr_t)ip + sizeof (*ip)); 277a4a2722fSToomas Soome /* If there were ip options, make them go away */ 278a4a2722fSToomas Soome if (hlen != sizeof(*ip)) { 279a4a2722fSToomas Soome bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); 280a4a2722fSToomas Soome ip->ip_len = htons(sizeof(*ip)); 281a4a2722fSToomas Soome n -= hlen - sizeof(*ip); 282a4a2722fSToomas Soome } 283a4a2722fSToomas Soome 284a4a2722fSToomas Soome n = (n > (ntohs(ip->ip_len) - sizeof(*ip))) ? 285a4a2722fSToomas Soome ntohs(ip->ip_len) - sizeof(*ip) : n; 286a4a2722fSToomas Soome *pkt = ptr; 287a4a2722fSToomas Soome *payload = (void *)((uintptr_t)ip + sizeof(*ip)); 288a4a2722fSToomas Soome return (n); 289a4a2722fSToomas Soome } 290a4a2722fSToomas Soome 291a4a2722fSToomas Soome STAILQ_FOREACH(ipr, &ire_list, ip_next) { 292a4a2722fSToomas Soome if (ipr->ip_src.s_addr == ip->ip_src.s_addr && 293a4a2722fSToomas Soome ipr->ip_dst.s_addr == ip->ip_dst.s_addr && 294a4a2722fSToomas Soome ipr->ip_id == ip->ip_id && 295a4a2722fSToomas Soome ipr->ip_proto == ip->ip_p) 296a4a2722fSToomas Soome break; 297a4a2722fSToomas Soome } 298a4a2722fSToomas Soome 299a4a2722fSToomas Soome /* Allocate new reassembly entry */ 300a4a2722fSToomas Soome if (ipr == NULL) { 301a4a2722fSToomas Soome if ((ipr = calloc(1, sizeof (*ipr))) == NULL) { 302a4a2722fSToomas Soome free(ptr); 303a4a2722fSToomas Soome return (-1); 304a4a2722fSToomas Soome } 305a4a2722fSToomas Soome 306a4a2722fSToomas Soome ipr->ip_src = ip->ip_src; 307a4a2722fSToomas Soome ipr->ip_dst = ip->ip_dst; 308a4a2722fSToomas Soome ipr->ip_id = ip->ip_id; 309a4a2722fSToomas Soome ipr->ip_proto = ip->ip_p; 310a4a2722fSToomas Soome ipr->ip_ttl = MAXTTL; 311a4a2722fSToomas Soome STAILQ_INIT(&ipr->ip_queue); 312a4a2722fSToomas Soome STAILQ_INSERT_TAIL(&ire_list, ipr, ip_next); 313a4a2722fSToomas Soome } 314a4a2722fSToomas Soome 315a4a2722fSToomas Soome if (ip_reasm_add(ipr, ptr, ip) != 0) { 316a4a2722fSToomas Soome STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); 317a4a2722fSToomas Soome free(ipr); 318a4a2722fSToomas Soome free(ptr); 319a4a2722fSToomas Soome return (-1); 320a4a2722fSToomas Soome } 321a4a2722fSToomas Soome 322a4a2722fSToomas Soome if ((ntohs(ip->ip_off) & IP_MF) == 0) { 323a4a2722fSToomas Soome ipr->ip_total_size = (8 * (ntohs(ip->ip_off) & IP_OFFMASK)); 324a4a2722fSToomas Soome ipr->ip_total_size += n + sizeof (*ip); 325a4a2722fSToomas Soome ipr->ip_total_size += sizeof (struct ether_header); 326a4a2722fSToomas Soome 327a4a2722fSToomas Soome ipr->ip_pkt = malloc(ipr->ip_total_size + 2); 328a4a2722fSToomas Soome if (ipr->ip_pkt == NULL) { 329a4a2722fSToomas Soome STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); 330a4a2722fSToomas Soome ip_reasm_free(ipr); 331a4a2722fSToomas Soome return (-1); 332a4a2722fSToomas Soome } 333a4a2722fSToomas Soome } 334a4a2722fSToomas Soome 335a4a2722fSToomas Soome /* 336a4a2722fSToomas Soome * If we do not have re-assembly buffer ipr->ip_pkt, we are still 337a4a2722fSToomas Soome * missing fragments, so just restart the read. 338a4a2722fSToomas Soome */ 339a4a2722fSToomas Soome if (ipr->ip_pkt == NULL) { 340a4a2722fSToomas Soome errno = EAGAIN; 341a4a2722fSToomas Soome return (-1); 342a4a2722fSToomas Soome } 343a4a2722fSToomas Soome 344a4a2722fSToomas Soome /* 345a4a2722fSToomas Soome * Walk the packet list in reassembly queue, if we got all the 346a4a2722fSToomas Soome * fragments, build the packet. 347a4a2722fSToomas Soome */ 348a4a2722fSToomas Soome n = 0; 349a4a2722fSToomas Soome last = NULL; 350a4a2722fSToomas Soome STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { 351a4a2722fSToomas Soome if ((ntohs(ipq->ipq_hdr->ip_off) & IP_OFFMASK) != n / 8) { 352a4a2722fSToomas Soome STAILQ_REMOVE(&ire_list, ipr, ip_reasm, ip_next); 353a4a2722fSToomas Soome ip_reasm_free(ipr); 354a4a2722fSToomas Soome return (-1); 355a4a2722fSToomas Soome } 356a4a2722fSToomas Soome 357a4a2722fSToomas Soome n += ntohs(ipq->ipq_hdr->ip_len) - (ipq->ipq_hdr->ip_hl << 2); 358a4a2722fSToomas Soome last = ipq; 359a4a2722fSToomas Soome } 360a4a2722fSToomas Soome if ((ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0) { 361a4a2722fSToomas Soome errno = EAGAIN; 362a4a2722fSToomas Soome return (-1); 363a4a2722fSToomas Soome } 364a4a2722fSToomas Soome 365a4a2722fSToomas Soome ipq = STAILQ_FIRST(&ipr->ip_queue); 366a4a2722fSToomas Soome /* Fabricate ethernet header */ 367a4a2722fSToomas Soome eh = (struct ether_header *)((uintptr_t)ipr->ip_pkt + 2); 368a4a2722fSToomas Soome bcopy((void *)((uintptr_t)ipq->ipq_pkt + 2), eh, sizeof (*eh)); 369a4a2722fSToomas Soome 370a4a2722fSToomas Soome /* Fabricate IP header */ 371a4a2722fSToomas Soome ipr->ip_hdr = (struct ip *)((uintptr_t)eh + sizeof (*eh)); 372a4a2722fSToomas Soome bcopy(ipq->ipq_hdr, ipr->ip_hdr, sizeof (*ipr->ip_hdr)); 373a4a2722fSToomas Soome ipr->ip_hdr->ip_hl = sizeof (*ipr->ip_hdr) >> 2; 374a4a2722fSToomas Soome ipr->ip_hdr->ip_len = htons(n); 375a4a2722fSToomas Soome ipr->ip_hdr->ip_sum = 0; 376a4a2722fSToomas Soome ipr->ip_hdr->ip_sum = in_cksum(ipr->ip_hdr, sizeof (*ipr->ip_hdr)); 377a4a2722fSToomas Soome 378a4a2722fSToomas Soome n = 0; 379a4a2722fSToomas Soome ptr = (char *)((uintptr_t)ipr->ip_hdr + sizeof (*ipr->ip_hdr)); 380a4a2722fSToomas Soome STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { 381a4a2722fSToomas Soome char *data; 382a4a2722fSToomas Soome size_t len; 383a4a2722fSToomas Soome 384a4a2722fSToomas Soome hlen = ipq->ipq_hdr->ip_hl << 2; 385a4a2722fSToomas Soome len = ntohs(ipq->ipq_hdr->ip_len) - hlen; 386a4a2722fSToomas Soome data = (char *)((uintptr_t)ipq->ipq_hdr + hlen); 387a4a2722fSToomas Soome 388a4a2722fSToomas Soome bcopy(data, ptr + n, len); 389a4a2722fSToomas Soome n += len; 390a4a2722fSToomas Soome } 391a4a2722fSToomas Soome 392a4a2722fSToomas Soome *pkt = ipr->ip_pkt; 393a4a2722fSToomas Soome ipr->ip_pkt = NULL; /* Avoid free from ip_reasm_free() */ 394a4a2722fSToomas Soome *payload = ptr; 395a4a2722fSToomas Soome 396a4a2722fSToomas Soome /* Clean up the reassembly list */ 397a4a2722fSToomas Soome while ((ipr = STAILQ_FIRST(&ire_list)) != NULL) { 398a4a2722fSToomas Soome STAILQ_REMOVE_HEAD(&ire_list, ip_next); 399a4a2722fSToomas Soome ip_reasm_free(ipr); 400a4a2722fSToomas Soome } 401a4a2722fSToomas Soome return (n); 402a4a2722fSToomas Soome } 403a4a2722fSToomas Soome 404a4a2722fSToomas Soome /* 405a4a2722fSToomas Soome * Receive a IP packet. 406a4a2722fSToomas Soome */ 407a4a2722fSToomas Soome ssize_t 408a4a2722fSToomas Soome readip(struct iodesc *d, void **pkt, void **payload, time_t tleft, 409a4a2722fSToomas Soome uint8_t proto) 410a4a2722fSToomas Soome { 411a4a2722fSToomas Soome time_t t; 412a4a2722fSToomas Soome ssize_t ret = -1; 413a4a2722fSToomas Soome 414a4a2722fSToomas Soome t = getsecs(); 415a4a2722fSToomas Soome while ((getsecs() - t) < tleft) { 416a4a2722fSToomas Soome errno = 0; 417a4a2722fSToomas Soome ret = readipv4(d, pkt, payload, tleft, proto); 418*a01cd540SToomas Soome if (ret >= 0) 419a4a2722fSToomas Soome return (ret); 420*a01cd540SToomas Soome /* Bubble up the error if it wasn't successful */ 421*a01cd540SToomas Soome if (errno != EAGAIN) 422*a01cd540SToomas Soome return (-1); 423*a01cd540SToomas Soome } 424*a01cd540SToomas Soome /* We've exhausted tleft; timeout */ 425*a01cd540SToomas Soome errno = ETIMEDOUT; 426*a01cd540SToomas Soome return (-1); 427a4a2722fSToomas Soome } 428