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