SLiRP 64-bit fixes. Originally written by Gleb Natapov for QEMU.

This commit is contained in:
SarahW 2017-08-08 21:19:36 +01:00
commit 5a957e5d00
11 changed files with 156 additions and 233 deletions

View file

@ -52,7 +52,7 @@ struct ipq ipq;
void
ip_init()
{
ipq.next = ipq.prev = (ipqp_32)&ipq;
ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link;
ip_id = tt.tv_sec & 0xffff;
udp_init();
tcp_init();
@ -154,19 +154,21 @@ ip_input(m)
* XXX This should fail, don't fragment yet
*/
if (ip->ip_off &~ IP_DF) {
register struct ipq *fp;
struct ipq *fp;
struct qlink *l;
/*
* Look for queue of fragments
* of this datagram.
*/
for (fp = (struct ipq *) ipq.next; fp != &ipq;
fp = (struct ipq *) fp->next)
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
ip->ip_p == fp->ipq_p)
for (l = (struct qlink*)(ipq.ip_link.next); l != &ipq.ip_link; l = (struct qlink*)(l->next)) {
fp = container_of(l, struct ipq, ip_link);
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
ip->ip_p == fp->ipq_p)
goto found;
fp = 0;
}
fp = NULL;
found:
/*
@ -176,9 +178,9 @@ ip_input(m)
*/
ip->ip_len -= hlen;
if (ip->ip_off & IP_MF)
((struct ipasfrag *)ip)->ipf_mff |= 1;
ip->ip_tos |= 1;
else
((struct ipasfrag *)ip)->ipf_mff &= ~1;
ip->ip_tos &= ~1;
ip->ip_off <<= 3;
@ -187,9 +189,9 @@ ip_input(m)
* or if this is not the first fragment,
* attempt reassembly; if it succeeds, proceed.
*/
if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
if ((ip->ip_tos & 1) || ip->ip_off) {
ipstat.ips_fragments++;
ip = ip_reass((struct ipasfrag *)ip, fp);
ip = ip_reass(ip, fp);
if (ip == 0)
return;
ipstat.ips_reassembled++;
@ -225,16 +227,16 @@ bad:
return;
}
#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
/*
* Take incoming datagram fragment and try to
* reassemble it into whole datagram. If a chain for
* reassembly of this datagram already exists, then it
* is given as fp; otherwise have to make a chain.
*/
struct ip *
ip_reass(ip, fp)
register struct ipasfrag *ip;
register struct ipq *fp;
struct ip *ip_reass(struct ip *ip, struct ipq *fp)
{
register struct SLIRPmbuf *m = dtom(ip);
register struct ipasfrag *q;
@ -261,13 +263,13 @@ ip_reass(ip, fp)
struct SLIRPmbuf *t;
if ((t = m_get()) == NULL) goto dropfrag;
fp = mtod(t, struct ipq *);
insque_32(fp, &ipq);
insque(&fp->ip_link, &ipq.ip_link);
fp->ipq_ttl = IPFRAGTTL;
fp->ipq_p = ip->ip_p;
fp->ipq_id = ip->ip_id;
fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp;
fp->ipq_src = ((struct ip *)ip)->ip_src;
fp->ipq_dst = ((struct ip *)ip)->ip_dst;
fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
fp->ipq_src = ip->ip_src;
fp->ipq_dst = ip->ip_dst;
q = (struct ipasfrag *)fp;
goto insert;
}
@ -275,19 +277,19 @@ ip_reass(ip, fp)
/*
* Find a segment which begins after this one does.
*/
for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp;
q = (struct ipasfrag *)q->ipf_next)
if (q->ip_off > ip->ip_off)
for (q = (struct ipasfrag*)fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; q = (struct ipasfrag*)(q->ipf_next)) {
if (q->ipf_off > ip->ip_off)
break;
}
/*
* If there is a preceding segment, it may provide some of
* our data already. If so, drop the data from the incoming
* segment. If it provides all of our data, drop us.
*/
if (q->ipf_prev != (ipasfragp_32)fp) {
i = ((struct ipasfrag *)(q->ipf_prev))->ip_off +
((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off;
if (q->ipf_prev != &fp->frag_link) {
struct ipasfrag *pq = (struct ipasfrag*)(q->ipf_prev);
i = pq->ipf_off + pq->ipf_len - ip->ip_off;
if (i > 0) {
if (i >= ip->ip_len)
goto dropfrag;
@ -301,17 +303,18 @@ ip_reass(ip, fp)
* While we overlap succeeding segments trim them or,
* if they are completely covered, dequeue them.
*/
while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
i = (ip->ip_off + ip->ip_len) - q->ip_off;
if (i < q->ip_len) {
q->ip_len -= i;
q->ip_off += i;
while (q != (struct ipasfrag*)&fp->frag_link &&
ip->ip_off + ip->ip_len > q->ipf_off) {
i = (ip->ip_off + ip->ip_len) - q->ipf_off;
if (i < q->ipf_len) {
q->ipf_len -= i;
q->ipf_off += i;
m_adj(dtom(q), i);
break;
}
q = (struct ipasfrag *) q->ipf_next;
m_freem(dtom((struct ipasfrag *) q->ipf_prev));
ip_deq((struct ipasfrag *) q->ipf_prev);
q = (struct ipasfrag*)(q->ipf_next);
m_freem(dtom(q->ipf_prev));
ip_deq((struct ipasfrag*)(q->ipf_prev));
}
insert:
@ -319,29 +322,27 @@ insert:
* Stick new segment in its place;
* check for complete reassembly.
*/
ip_enq(ip, (struct ipasfrag *) q->ipf_prev);
ip_enq(iptofrag(ip), (struct ipasfrag*)(q->ipf_prev));
next = 0;
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
q = (struct ipasfrag *) q->ipf_next) {
if (q->ip_off != next)
return (0);
next += q->ip_len;
for (q = (struct ipasfrag*)(fp->frag_link.next); q != (struct ipasfrag*)&fp->frag_link; q = (struct ipasfrag*)(q->ipf_next)) {
if (q->ipf_off != next)
return 0;
next += q->ipf_len;
}
if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1)
if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
return (0);
/*
* Reassembly is complete; concatenate fragments.
*/
q = (struct ipasfrag *) fp->ipq_next;
q = (struct ipasfrag*)(fp->frag_link.next);
m = dtom(q);
q = (struct ipasfrag *) q->ipf_next;
while (q != (struct ipasfrag *)fp) {
struct SLIRPmbuf *t;
t = dtom(q);
q = (struct ipasfrag *) q->ipf_next;
m_cat(m, t);
while (q != (struct ipasfrag*)&fp->frag_link) {
struct mbuf *t = dtom(q);
q = (struct ipasfrag *) q->ipf_next;
m_cat(m, t);
}
/*
@ -350,7 +351,7 @@ insert:
* dequeue and discard fragment reassembly header.
* Make header visible.
*/
ip = (struct ipasfrag *) fp->ipq_next;
q = (struct ipasfrag*)(fp->frag_link.next);
/*
* If the fragments concatenated to an SLIRPmbuf that's
@ -362,23 +363,23 @@ insert:
if (m->m_flags & M_EXT) {
int delta;
delta = (char *)ip - m->m_dat;
ip = (struct ipasfrag *)(m->m_ext + delta);
q = (struct ipasfrag *)(m->m_ext + delta);
}
/* DEBUG_ARG("ip = %lx", (long)ip);
* ip=(struct ipasfrag *)m->m_data; */
ip = fragtoip(q);
ip->ip_len = next;
ip->ipf_mff &= ~1;
((struct ip *)ip)->ip_src = fp->ipq_src;
((struct ip *)ip)->ip_dst = fp->ipq_dst;
remque_32(fp);
ip->ip_tos &= ~1;
ip->ip_src = fp->ipq_src;
ip->ip_dst = fp->ipq_dst;
remque(&fp->ip_link);
(void) m_free(dtom(fp));
m = dtom(ip);
m->m_len += (ip->ip_hl << 2);
m->m_data -= (ip->ip_hl << 2);
return ((struct ip *)ip);
return ip;
dropfrag:
ipstat.ips_fragdropped++;
@ -396,13 +397,12 @@ ip_freef(fp)
{
register struct ipasfrag *q, *p;
for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
q = p) {
p = (struct ipasfrag *) q->ipf_next;
for (q = (struct ipasfrag*)(fp->frag_link.next); q != (struct ipasfrag*)&fp->frag_link; q = p) {
p = (struct ipasfrag*)(q->ipf_next);
ip_deq(q);
m_freem(dtom(q));
}
remque_32(fp);
remque(&fp->ip_link);
(void) m_free(dtom(fp));
}
@ -416,10 +416,10 @@ ip_enq(p, prev)
{
DEBUG_CALL("ip_enq");
DEBUG_ARG("prev = %lx", (long)prev);
p->ipf_prev = (ipasfragp_32) prev;
p->ipf_prev = prev;
p->ipf_next = prev->ipf_next;
((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p;
prev->ipf_next = (ipasfragp_32) p;
((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
prev->ipf_next = p;
}
/*
@ -438,23 +438,23 @@ ip_deq(p)
* if a timer expires on a reassembly
* queue, discard it.
*/
void
ip_slowtimo()
void ip_slowtimo()
{
register struct ipq *fp;
struct qlink *l;
DEBUG_CALL("ip_slowtimo");
fp = (struct ipq *) ipq.next;
if (fp == 0)
return;
l = (struct qlink*)(ipq.ip_link.next);
while (fp != &ipq) {
--fp->ipq_ttl;
fp = (struct ipq *) fp->next;
if (((struct ipq *)(fp->prev))->ipq_ttl == 0) {
if (l == 0)
return;
while (l != &ipq.ip_link) {
struct ipq *fp = container_of(l, struct ipq, ip_link);
l = (struct qlink*)(l->next);
if (--fp->ipq_ttl == 0) {
ipstat.ips_fragtimeout++;
ip_freef((struct ipq *) fp->prev);
ip_freef(fp);
}
}
}