Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/ip_input.c
2 views
/* SPDX-License-Identifier: BSD-3-Clause */1/*2* Copyright (c) 1982, 1986, 1988, 19933* The Regents of the University of California. All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13* 3. Neither the name of the University nor the names of its contributors14* may be used to endorse or promote products derived from this software15* without specific prior written permission.16*17* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*29* @(#)ip_input.c 8.2 (Berkeley) 1/4/9430* ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp31*/3233/*34* Changes and additions relating to SLiRP are35* Copyright (c) 1995 Danny Gasparovski.36*/3738#include "slirp.h"39#include "ip_icmp.h"4041static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);42static void ip_freef(Slirp *slirp, struct ipq *fp);43static void ip_enq(register struct ipas *p, register struct ipas *prev);44static void ip_deq(register struct ipas *p);4546/*47* IP initialization: fill in IP protocol switch table.48* All protocols not implemented in kernel go to raw IP protocol handler.49*/50void ip_init(Slirp *slirp)51{52slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;53udp_init(slirp);54tcp_init(slirp);55icmp_init(slirp);56}5758void ip_cleanup(Slirp *slirp)59{60udp_cleanup(slirp);61tcp_cleanup(slirp);62icmp_cleanup(slirp);63}6465/*66* Ip input routine. Checksum and byte swap header. If fragmented67* try to reassemble. Process options. Pass to next level.68*/69void ip_input(struct mbuf *m)70{71Slirp *slirp = m->slirp;72M_DUP_DEBUG(slirp, m, 0, TCPIPHDR_DELTA);7374register struct ip *ip;75int hlen;7677if (!slirp->in_enabled) {78goto bad;79}8081DEBUG_CALL("ip_input");82DEBUG_ARG("m = %p", m);83DEBUG_ARG("m_len = %d", m->m_len);8485if (m->m_len < sizeof(struct ip)) {86goto bad;87}8889ip = mtod(m, struct ip *);9091if (ip->ip_v != IPVERSION) {92goto bad;93}9495hlen = ip->ip_hl << 2;96if (hlen < sizeof(struct ip) || hlen > m->m_len) { /* min header length */97goto bad; /* or packet too short */98}99100/* keep ip header intact for ICMP reply101* ip->ip_sum = cksum(m, hlen);102* if (ip->ip_sum) {103*/104if (cksum(m, hlen)) {105goto bad;106}107108/*109* Convert fields to host representation.110*/111NTOHS(ip->ip_len);112if (ip->ip_len < hlen) {113goto bad;114}115NTOHS(ip->ip_id);116NTOHS(ip->ip_off);117118/*119* Check that the amount of data in the buffers120* is as at least much as the IP header would have us expect.121* Trim mbufs if longer than we expect.122* Drop packet if shorter than we expect.123*/124if (m->m_len < ip->ip_len) {125goto bad;126}127128/* Should drop packet if mbuf too long? hmmm... */129if (m->m_len > ip->ip_len)130m_adj(m, ip->ip_len - m->m_len);131132/* check ip_ttl for a correct ICMP reply */133if (ip->ip_ttl == 0) {134icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");135goto bad;136}137138/*139* If offset or IP_MF are set, must reassemble.140* Otherwise, nothing need be done.141* (We could look in the reassembly queue to see142* if the packet was previously fragmented,143* but it's not worth the time; just let them time out.)144*145* XXX This should fail, don't fragment yet146*/147if (ip->ip_off & ~IP_DF) {148register struct ipq *q;149struct qlink *l;150/*151* Look for queue of fragments152* of this datagram.153*/154for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;155l = l->next) {156q = container_of(l, struct ipq, ip_link);157if (ip->ip_id == q->ipq_id &&158ip->ip_src.s_addr == q->ipq_src.s_addr &&159ip->ip_dst.s_addr == q->ipq_dst.s_addr &&160ip->ip_p == q->ipq_p)161goto found;162}163q = NULL;164found:165166/*167* Adjust ip_len to not reflect header,168* set ip_mff if more fragments are expected,169* convert offset of this to bytes.170*/171ip->ip_len -= hlen;172if (ip->ip_off & IP_MF)173ip->ip_tos |= 1;174else175ip->ip_tos &= ~1;176177ip->ip_off <<= 3;178179/*180* If datagram marked as having more fragments181* or if this is not the first fragment,182* attempt reassembly; if it succeeds, proceed.183*/184if (ip->ip_tos & 1 || ip->ip_off) {185ip = ip_reass(slirp, ip, q);186if (ip == NULL)187return;188m = dtom(slirp, ip);189} else if (q)190ip_freef(slirp, q);191192} else193ip->ip_len -= hlen;194195/*196* Switch out to protocol's input routine.197*/198switch (ip->ip_p) {199case IPPROTO_TCP:200tcp_input(m, hlen, (struct socket *)NULL, AF_INET);201break;202case IPPROTO_UDP:203udp_input(m, hlen);204break;205case IPPROTO_ICMP:206icmp_input(m, hlen);207break;208default:209m_free(m);210}211return;212bad:213m_free(m);214}215216#define iptoas(P) container_of((P), struct ipas, ipf_ip)217#define astoip(P) (&(P)->ipf_ip)218/*219* Take incoming datagram fragment and try to220* reassemble it into whole datagram. If a chain for221* reassembly of this datagram already exists, then it222* is given as q; otherwise have to make a chain.223*/224static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *q)225{226register struct mbuf *m = dtom(slirp, ip);227struct ipas *first = container_of(q, struct ipas, ipq);228register struct ipas *cursor;229int hlen = ip->ip_hl << 2;230int i, next;231232DEBUG_CALL("ip_reass");233DEBUG_ARG("ip = %p", ip);234DEBUG_ARG("q = %p", q);235DEBUG_ARG("m = %p", m);236237/*238* Presence of header sizes in mbufs239* would confuse code below.240* Fragment m_data is concatenated.241*/242m->m_data += hlen;243m->m_len -= hlen;244245/*246* If first fragment to arrive, create a reassembly queue.247*/248if (q == NULL) {249struct mbuf *t = m_get(slirp);250251if (t == NULL) {252goto dropfrag;253}254first = mtod(t, struct ipas *);255q = &first->ipq;256slirp_insque(&q->ip_link, &slirp->ipq.ip_link);257q->ipq_ttl = IPFRAGTTL;258q->ipq_p = ip->ip_p;259q->ipq_id = ip->ip_id;260first->link.next = first->link.prev = first;261q->ipq_src = ip->ip_src;262q->ipq_dst = ip->ip_dst;263cursor = first;264goto insert;265}266267/*268* Find a segment which begins after this one does.269*/270for (cursor = first->link.next; cursor != first; cursor = cursor->link.next)271if (cursor->ipf_off > ip->ip_off)272break;273274/*275* If there is a preceding segment, it may provide some of276* our data already. If so, drop the data from the incoming277* segment. If it provides all of our data, drop us.278*/279if (cursor->link.prev != first) {280struct ipas *pq = cursor->link.prev;281i = pq->ipf_off + pq->ipf_len - ip->ip_off;282if (i > 0) {283if (i >= ip->ip_len)284goto dropfrag;285m_adj(dtom(slirp, ip), i);286ip->ip_off += i;287ip->ip_len -= i;288}289}290291/*292* While we overlap succeeding segments trim them or,293* if they are completely covered, dequeue them.294*/295while (cursor != first && ip->ip_off + ip->ip_len > cursor->ipf_off) {296struct ipas *prev;297i = (ip->ip_off + ip->ip_len) - cursor->ipf_off;298if (i < cursor->ipf_len) {299cursor->ipf_len -= i;300cursor->ipf_off += i;301m_adj(dtom(slirp, cursor), i);302break;303}304prev = cursor;305cursor = cursor->link.next;306ip_deq(prev);307m_free(dtom(slirp, prev));308}309310insert:311/*312* Stick new segment in its place;313* check for complete reassembly.314*/315ip_enq(iptoas(ip), cursor->link.prev);316next = 0;317for (cursor = first->link.next; cursor != first; cursor = cursor->link.next) {318if (cursor->ipf_off != next)319return NULL;320next += cursor->ipf_len;321}322if (((struct ipas *)(cursor->link.prev))->ipf_tos & 1)323return NULL;324325/*326* Reassembly is complete; concatenate fragments.327*/328cursor = first->link.next;329m = dtom(slirp, cursor);330int delta = (char *)cursor - (m->m_flags & M_EXT ? m->m_ext : m->m_dat);331332cursor = cursor->link.next;333while (cursor != first) {334struct mbuf *t = dtom(slirp, cursor);335cursor = cursor->link.next;336m_cat(m, t);337}338339/*340* Create header for new ip packet by341* modifying header of first packet;342* dequeue and discard fragment reassembly header.343* Make header visible.344*/345cursor = first->link.next;346347/*348* If the fragments concatenated to an mbuf that's bigger than the total349* size of the fragment and the mbuf was not already using an m_ext buffer,350* then an m_ext buffer was allocated. But q->ipq_next points to the old351* buffer (in the mbuf), so we must point ip into the new buffer.352*/353if (m->m_flags & M_EXT) {354cursor = (struct ipas *)(m->m_ext + delta);355}356357ip = astoip(cursor);358ip->ip_len = next;359ip->ip_tos &= ~1;360ip->ip_src = q->ipq_src;361ip->ip_dst = q->ipq_dst;362slirp_remque(&q->ip_link);363m_free(dtom(slirp, q));364m->m_len += (ip->ip_hl << 2);365m->m_data -= (ip->ip_hl << 2);366367return ip;368369dropfrag:370m_free(m);371return NULL;372}373374/*375* Free a fragment reassembly header and all376* associated datagrams.377*/378static void ip_freef(Slirp *slirp, struct ipq *q)379{380struct ipas *first = container_of(q, struct ipas, ipq);381register struct ipas *cursor, *next;382383for (cursor = first->link.next; cursor != first; cursor = next) {384next = cursor->link.next;385ip_deq(cursor);386m_free(dtom(slirp, cursor));387}388slirp_remque(&q->ip_link);389m_free(dtom(slirp, q));390}391392/*393* Put an ip fragment on a reassembly chain.394* Like slirp_insque, but pointers in middle of structure.395*/396static void ip_enq(register struct ipas *p, register struct ipas *prev)397{398DEBUG_CALL("ip_enq");399DEBUG_ARG("prev = %p", prev);400p->link.prev = prev;401p->link.next = prev->link.next;402((struct ipas *)(prev->link.next))->link.prev = p;403prev->link.next = p;404}405406/*407* To ip_enq as slirp_remque is to slirp_insque.408*/409static void ip_deq(register struct ipas *p)410{411((struct ipas *)(p->link.prev))->link.next = p->link.next;412((struct ipas *)(p->link.next))->link.prev = p->link.prev;413}414415void ip_slowtimo(Slirp *slirp)416{417struct qlink *l;418419DEBUG_CALL("ip_slowtimo");420421l = slirp->ipq.ip_link.next;422423if (l == NULL)424return;425426while (l != &slirp->ipq.ip_link) {427struct ipq *q = container_of(l, struct ipq, ip_link);428l = l->next;429if (--q->ipq_ttl == 0) {430ip_freef(slirp, q);431}432}433}434435void ip_stripoptions(register struct mbuf *m)436{437register int i;438struct ip *ip = mtod(m, struct ip *);439register char *opts;440int olen;441442olen = (ip->ip_hl << 2) - sizeof(struct ip);443opts = (char *)(ip + 1);444i = m->m_len - (sizeof(struct ip) + olen);445memmove(opts, opts + olen, (unsigned)i);446m->m_len -= olen;447448ip->ip_hl = sizeof(struct ip) >> 2;449}450451452