Dear Maintainer, I tried to find some more information about this issue. Attached is a file containing some hints how I did run the UML process and some debugging output.
As far as I see it is yet another issue with some "caddr32_t" sizes, this time they are used to map the input data. Therefore 8 Bytes get written instead of 4, when assigning the next and prev pointer inside function tcp_input, line 306. [2] Therefore the checksum for each IP packet does not match anymore and gets dropped. ("11 discarded for bad checksums") As it seems this type is sometimes mapped to input data and then used for holding real pointers, it looks their size cannot be just increased as done in patch 012_ipq64.patch. Related bugs seem to be: #948268 or #922323. When realising this type being the issue I found this patch [1], which might have been created in the Qemu area. Unfortunately this patch did not apply cleanly, but attached patch c11b4078042_fix_64_bit_issue_in_slirp.patch is created from the package with all patches applied and additionally 949003_explicit_extern_declaration.patch to fix a build failure. One thing to note is building the package with -DDEBUG allows to use the '-d 7' switch to get some verbose output in file 'slirp_debug'. A package built with both patches and "-DDEBUG" was able to do some http downloads. Kind regards, Bernhard [1] https://gitlab.freedesktop.org/slirp/libslirp/-/commit/c11b407804272b71e5bdd7a2a9181c64c7a594ed [2] (gdb) bt #0 tcp_input (m=0x558551242be0, iphlen=<optimized out>, inso=inso@entry=0x0) at ./tcp_input.c:313 #1 0x000055854f58399c in ip_input (m=<optimized out>) at ip_input.c:214 #2 0x000055854f58c01f in sl_dispatch (ttyp=ttyp@entry=0x55855123e2c0) at ./sl.c:127 #3 0x000055854f58c1ee in sl_input (ttyp=0x55855123e2c0, if_bptr=0x7ffddbe4f67e "\300\264\004\002\b\n`\354\303a", if_n=63) at ./sl.c:35 #4 0x000055854f581ed2 in if_input (ttyp=0x55855123e2c0) at ./if.c:191 #5 0x000055854f58567f in main_loop () at ./main.c:1158 #6 0x000055854f5757d7 in main (argc=3, argv=0x7ffddbe504f8) at ./main.c:95
Description: 949003 Author: Bernhard Übelacker <bernha...@mailbox.org> Bug-Debian: https://bugs.debian.org/949003 Forwarded: no Last-Update: 2020-09-02 Index: slirp-1.0.17/src/options.c =================================================================== --- slirp-1.0.17.orig/src/options.c +++ slirp-1.0.17/src/options.c @@ -74,8 +74,8 @@ int nozeros; /* If se * Read the config file */ -int (*lprint_print) _P((void *, const char *format, va_list)); -char *lprint_ptr, *lprint_ptr2, **lprint_arg; +extern int (*lprint_print) _P((void *, const char *format, va_list)); +extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; struct sbuf *lprint_sb; int cfg_unit;
Description: Fix 64 bit issue in slirp Origin: https://gitlab.freedesktop.org/slirp/libslirp/-/commit/c11b407804272b71e5bdd7a2a9181c64c7a594ed Bug-Debian: https://bugs.debian.org/949003 Last-Update: 2020-09-02 Index: slirp-1.0.17/src/ip.h =================================================================== --- slirp-1.0.17.orig/src/ip.h +++ slirp-1.0.17/src/ip.h @@ -187,35 +187,31 @@ struct ip_timestamp { #define IP_MSS 576 /* default maximum segment size */ -#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ -#include <sys/types32.h> -#else #if SIZEOF_CHAR_P == 4 -typedef caddr_t caddr32_t; -#else -typedef void* caddr32_t; -#endif -#endif - -#if SIZEOF_CHAR_P == 4 -typedef struct ipq *ipqp_32; -typedef struct ipasfrag *ipasfragp_32; +struct mbuf_ptr { + struct mbuf *mptr; + uint32_t dummy; +}; #else -typedef void* ipqp_32; -typedef void* ipasfragp_32; +struct mbuf_ptr { + struct mbuf *mptr; +}; #endif +struct qlink { + void *next, *prev; +}; /* * Overlay for ip header used by other protocols (tcp, udp). */ struct ipovly { - caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ + struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ u_int8_t ih_x1; /* (unused) */ u_int8_t ih_pr; /* protocol */ int16_t ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ -}; +} __attribute__((packed)); /* * Ip reassembly queue structure. Each fragment @@ -225,44 +221,30 @@ struct ipovly { * size 28 bytes */ struct ipq { - ipqp_32 next,prev; /* to other reass headers */ + struct qlink frag_link; /* to ip headers of fragments */ + struct qlink ip_link; /* to other reass headers */ u_int8_t ipq_ttl; /* time for reass q to live */ u_int8_t ipq_p; /* protocol of this fragment */ u_int16_t ipq_id; /* sequence id for reassembly */ - ipasfragp_32 ipq_next,ipq_prev; - /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; }; /* * Ip header, when holding a fragment. * - * Note: ipf_next must be at same offset as ipq_next above + * Note: ipf_link must be at same offset as frag_link above */ struct ipasfrag { -#ifdef WORDS_BIGENDIAN - u_int ip_v:4, - ip_hl:4; -#else - u_int ip_hl:4, - ip_v:4; -#endif - /* BUG : u_int changed to u_int8_t. - * sizeof(u_int)==4 on linux 2.0 - */ - u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit - * to avoid destroying tos (PPPDTRuu); - * copied from (ip_off&IP_MF) */ - int16_t ip_len; - u_int16_t ip_id; - int16_t ip_off; - u_int8_t ip_ttl; - u_int8_t ip_p; - u_int16_t ip_sum; - ipasfragp_32 ipf_next; /* next fragment */ - ipasfragp_32 ipf_prev; /* previous fragment */ + struct qlink ipf_link; + struct ip ipf_ip; }; +#define ipf_off ipf_ip.ip_off +#define ipf_tos ipf_ip.ip_tos +#define ipf_len ipf_ip.ip_len +#define ipf_next ipf_link.next +#define ipf_prev ipf_link.prev + /* * Structure stored in mbuf in inpcb.ip_options * and passed to ip_output when ip options are in use. Index: slirp-1.0.17/src/ip_input.c =================================================================== --- slirp-1.0.17.orig/src/ip_input.c +++ slirp-1.0.17/src/ip_input.c @@ -43,12 +43,23 @@ */ #include <slirp.h> +#include <stddef.h> #include "ip_icmp.h" +#ifndef container_of +#define container_of(ptr, type, member) \ + __extension__({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); \ + }) +#endif + int ip_defttl; struct ipstat ipstat; struct ipq ipq; +static struct ip *ip_reass(register struct ip *ip, register struct ipq *fp); + /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. @@ -56,7 +67,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(); @@ -159,18 +170,20 @@ ip_input(m) */ if (ip->ip_off &~ IP_DF) { register 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) + for (l = ipq.ip_link.next; l != &ipq.ip_link; l = 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: /* @@ -180,9 +193,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; @@ -191,9 +204,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++; @@ -229,16 +242,15 @@ 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; +static struct ip *ip_reass(register struct ip *ip, register struct ipq *fp) { register struct mbuf *m = dtom(ip); register struct ipasfrag *q; @@ -265,13 +277,13 @@ ip_reass(ip, fp) struct mbuf *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; } @@ -279,9 +291,9 @@ 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 = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; + q = q->ipf_next) + if (q->ipf_off > ip->ip_off) break; /* @@ -289,9 +301,9 @@ ip_reass(ip, fp) * 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 = q->ipf_prev; + i = pq->ipf_off + pq->ipf_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; @@ -305,17 +317,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 = q->ipf_next; + m_freem(dtom(q->ipf_prev)); + ip_deq(q->ipf_prev); } insert: @@ -323,27 +336,26 @@ insert: * Stick new segment in its place; * check for complete reassembly. */ - ip_enq(ip, (struct ipasfrag *) q->ipf_prev); + ip_enq(iptofrag(ip), 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) + for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; + q = q->ipf_next) { + if (q->ipf_off != next) return (0); - next += q->ip_len; + 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 = fp->frag_link.next; m = dtom(q); q = (struct ipasfrag *) q->ipf_next; - while (q != (struct ipasfrag *)fp) { - struct mbuf *t; - t = dtom(q); + while (q != (struct ipasfrag *)&fp->frag_link) { + struct mbuf *t = dtom(q); m_cat(m, t); q = (struct ipasfrag *) q->ipf_next; } @@ -354,7 +366,7 @@ insert: * dequeue and discard fragment reassembly header. * Make header visible. */ - ip = (struct ipasfrag *) fp->ipq_next; + q = fp->frag_link.next; /* * If the fragments concatenated to an mbuf that's @@ -366,23 +378,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++; @@ -400,13 +412,13 @@ ip_freef(fp) { register struct ipasfrag *q, *p; - for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; q = p) { - p = (struct ipasfrag *) q->ipf_next; + p = q->ipf_next; ip_deq(q); m_freem(dtom(q)); } - remque_32(fp); + remque(&fp->ip_link); (void) m_free(dtom(fp)); } @@ -420,10 +432,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; } /* @@ -445,20 +457,21 @@ ip_deq(p) void ip_slowtimo() { - register struct ipq *fp; + struct qlink *l; DEBUG_CALL("ip_slowtimo"); - fp = (struct ipq *) ipq.next; - if (fp == 0) + l = ipq.ip_link.next; + + if (l == 0) return; - while (fp != &ipq) { - --fp->ipq_ttl; - fp = (struct ipq *) fp->next; - if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { + while (l != &ipq.ip_link) { + struct ipq *fp = container_of(l, struct ipq, ip_link); + l = l->next; + if (--fp->ipq_ttl == 0) { ipstat.ips_fragtimeout++; - ip_freef((struct ipq *) fp->prev); + ip_freef(fp); } } } Index: slirp-1.0.17/src/main.c =================================================================== --- slirp-1.0.17.orig/src/main.c +++ slirp-1.0.17/src/main.c @@ -760,8 +760,8 @@ while(1) { * *_slowtimo needs calling if there are IP fragments * in the fragment queue, or there are TCP connections active */ - do_slowtimo = ((tcb.so_next != &tcb) || - ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); + do_slowtimo = + ((tcb.so_next != &tcb) || (&ipq.ip_link != ipq.ip_link.next)); for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; Index: slirp-1.0.17/src/misc.c =================================================================== --- slirp-1.0.17.orig/src/misc.c +++ slirp-1.0.17/src/misc.c @@ -98,39 +98,6 @@ getouraddr() our_addr = *(struct in_addr *)he->h_addr; } -#if SIZEOF_CHAR_P == 8 - -struct quehead_32 { - u_int32_t qh_link; - u_int32_t qh_rlink; -}; - -inline void -insque_32(a, b) - void *a; - void *b; -{ - register struct quehead_32 *element = (struct quehead_32 *) a; - register struct quehead_32 *head = (struct quehead_32 *) b; - element->qh_link = head->qh_link; - head->qh_link = (u_int32_t)element; - element->qh_rlink = (u_int32_t)head; - ((struct quehead_32 *)(element->qh_link))->qh_rlink - = (u_int32_t)element; -} - -inline void -remque_32(a) - void *a; -{ - register struct quehead_32 *element = (struct quehead_32 *) a; - ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; - ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -#endif /* SIZEOF_CHAR_P == 8 */ - struct quehead { struct quehead *qh_link; struct quehead *qh_rlink; Index: slirp-1.0.17/src/slirp.h =================================================================== --- slirp-1.0.17.orig/src/slirp.h +++ slirp-1.0.17/src/slirp.h @@ -244,14 +244,6 @@ void lprint _P((const char *, ...)); extern int do_echo; -#if SIZEOF_CHAR_P == 4 -# define insque_32 insque -# define remque_32 remque -#else - inline void insque_32 _P((void *, void *)); - inline void remque_32 _P((void *)); -#endif - #include <pwd.h> #include <netdb.h> Index: slirp-1.0.17/src/tcp_input.c =================================================================== --- slirp-1.0.17.orig/src/tcp_input.c +++ slirp-1.0.17/src/tcp_input.c @@ -72,47 +72,49 @@ tcp_seq tcp_iss; /* tcp i * when segments are out of order (so fast retransmit can work). */ #ifdef TCP_ACK_HACK -#define TCP_REASS(tp, ti, m, so, flags) {\ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (tcpiphdrp_32)(tp) && \ - (tp)->t_state == TCPS_ESTABLISHED) {\ - if (ti->ti_flags & TH_PUSH) \ - tp->t_flags |= TF_ACKNOW; \ - else \ - tp->t_flags |= TF_DELACK; \ - (tp)->rcv_nxt += (ti)->ti_len; \ - flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ - if (so->so_emu) { \ - if (tcp_emu((so),(m))) sbappend((so), (m)); \ - } else \ - sbappend((so), (m)); \ -/* sorwakeup(so); */ \ - } else {\ - (flags) = tcp_reass((tp), (ti), (m)); \ - tp->t_flags |= TF_ACKNOW; \ - } \ +#define TCP_REASS(tp, ti, m, so, flags) \ + { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && tcpfrag_list_empty(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + if (ti->ti_flags & TH_PUSH) \ + tp->t_flags |= TF_ACKNOW; \ + else \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++; \ + tcpstat.tcps_rcvbyte += (ti)->ti_len; \ + if (so->so_emu) { \ + if (tcp_emu((so), (m))) \ + sbappend((so), (m)); \ + } else \ + sbappend((so), (m)); \ + /* sorwakeup(so); */ \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ } #else -#define TCP_REASS(tp, ti, m, so, flags) { \ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (tcpiphdrp_32)(tp) && \ - (tp)->t_state == TCPS_ESTABLISHED) { \ - tp->t_flags |= TF_DELACK; \ - (tp)->rcv_nxt += (ti)->ti_len; \ - flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ - if (so->so_emu) { \ - if (tcp_emu((so),(m))) sbappend(so, (m)); \ - } else \ - sbappend((so), (m)); \ -/* sorwakeup(so); */ \ - } else { \ - (flags) = tcp_reass((tp), (ti), (m)); \ - tp->t_flags |= TF_ACKNOW; \ - } \ +#define TCP_REASS(tp, ti, m, so, flags) \ + { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && tcpfrag_list_empty(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++; \ + tcpstat.tcps_rcvbyte += (ti)->ti_len; \ + if (so->so_emu) { \ + if (tcp_emu((so), (m))) \ + sbappend(so, (m)); \ + } else \ + sbappend((so), (m)); \ + /* sorwakeup(so); */ \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ } #endif @@ -136,8 +138,8 @@ tcp_reass(tp, ti, m) /* * Find a segment which begins after this one does. */ - for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; - q = (struct tcpiphdr *)q->ti_next) + for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp); + q = tcpiphdr_next(q)) if (SEQ_GT(q->ti_seq, ti->ti_seq)) break; @@ -146,9 +148,9 @@ tcp_reass(tp, ti, m) * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ - if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) { register int i; - q = (struct tcpiphdr *)q->ti_prev; + q = tcpiphdr_prev(q); /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { @@ -168,36 +170,36 @@ tcp_reass(tp, ti, m) ti->ti_len -= i; ti->ti_seq += i; } - q = (struct tcpiphdr *)(q->ti_next); + q = tcpiphdr_next(q); } tcpstat.tcps_rcvoopack++; tcpstat.tcps_rcvoobyte += ti->ti_len; - REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + ti->ti_mbuf = m; /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ - while (q != (struct tcpiphdr *)tp) { + while (!tcpfrag_list_end(q, tp)) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; if (i <= 0) break; if (i < q->ti_len) { q->ti_seq += i; q->ti_len -= i; - m_adj((struct mbuf *) REASS_MBUF(q), i); + m_adj(q->ti_mbuf, i); break; } - q = (struct tcpiphdr *)q->ti_next; - m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); - remque_32((void *)(q->ti_prev)); + q = tcpiphdr_next(q); + m = tcpiphdr_prev(q)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(q))); m_freem(m); } /* * Stick new segment in its place. */ - insque_32(ti, (void *)(q->ti_prev)); + insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q))); present: /* @@ -206,17 +208,17 @@ present: */ if (!TCPS_HAVEESTABLISHED(tp->t_state)) return (0); - ti = (struct tcpiphdr *) tp->seg_next; - if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + ti = tcpfrag_list_first(tp); + if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt) return (0); if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) return (0); do { tp->rcv_nxt += ti->ti_len; flags = ti->ti_flags & TH_FIN; - remque_32(ti); - m = (struct mbuf *) REASS_MBUF(ti); /* XXX */ - ti = (struct tcpiphdr *)ti->ti_next; + remque(tcpiphdr2qlink(ti)); + m = ti->ti_mbuf; + ti = tcpiphdr_next(ti); /* if (so->so_state & SS_FCANTRCVMORE) */ if (so->so_state & SS_FCANTSENDMORE) m_freem(m); @@ -303,7 +305,8 @@ tcp_input(m, iphlen, inso) * Checksum extended TCP header and data. */ tlen = ((struct ip *)ti)->ip_len; - ti->ti_next = ti->ti_prev = 0; + tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = 0; + memset(&ti->ti_i.ih_mbuf, 0, sizeof(struct mbuf_ptr)); ti->ti_x1 = 0; ti->ti_len = htons((u_int16_t)tlen); len = sizeof(struct ip ) + tlen; @@ -551,8 +554,7 @@ findso: return; } - } else if (ti->ti_ack == tp->snd_una && - tp->seg_next == (tcpiphdrp_32)tp && + } else if (ti->ti_ack == tp->snd_una && tcpfrag_list_empty(tp) && ti->ti_len <= sbspace(&so->so_rcv)) { /* * this is a pure, in-sequence data packet Index: slirp-1.0.17/src/tcp_subr.c =================================================================== --- slirp-1.0.17.orig/src/tcp_subr.c +++ slirp-1.0.17/src/tcp_subr.c @@ -84,7 +84,7 @@ tcp_template(tp) struct socket *so = tp->t_socket; register struct tcpiphdr *n = &tp->t_template; - n->ti_next = n->ti_prev = 0; + n->ti_mbuf = NULL; n->ti_x1 = 0; n->ti_pr = IPPROTO_TCP; n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); @@ -167,7 +167,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) tlen += sizeof (struct tcpiphdr); m->m_len = tlen; - ti->ti_next = ti->ti_prev = 0; + ti->ti_mbuf = 0; ti->ti_x1 = 0; ti->ti_seq = htonl(seq); ti->ti_ack = htonl(ack); @@ -207,7 +207,7 @@ tcp_newtcpcb(so) return ((struct tcpcb *)0); memset((char *) tp, 0, sizeof(struct tcpcb)); - tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; + tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; tp->t_maxseg = tcp_mssdflt; tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; @@ -284,11 +284,11 @@ tcp_close(tp) DEBUG_ARG("tp = %lx", (long )tp); /* free the reassembly queue, if any */ - t = (struct tcpiphdr *) tp->seg_next; - while (t != (struct tcpiphdr *)tp) { - t = (struct tcpiphdr *)t->ti_next; - m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); - remque_32((struct tcpiphdr *) t->ti_prev); + t = tcpfrag_list_first(tp); + while (!tcpfrag_list_end(t, tp)) { + t = tcpiphdr_next(t); + m = tcpiphdr_prev(t)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(t))); m_freem(m); } /* It's static */ Index: slirp-1.0.17/src/tcp_var.h =================================================================== --- slirp-1.0.17.orig/src/tcp_var.h +++ slirp-1.0.17/src/tcp_var.h @@ -40,18 +40,12 @@ #include "tcpip.h" #include "tcp_timer.h" -#if SIZEOF_CHAR_P == 4 - typedef struct tcpiphdr *tcpiphdrp_32; -#else - typedef void* tcpiphdrp_32; -#endif - /* * Tcp control block, one per tcp; fields: */ struct tcpcb { - tcpiphdrp_32 seg_next; /* sequencing queue */ - tcpiphdrp_32 seg_prev; + struct tcpiphdr *seg_next; /* sequencing queue */ + struct tcpiphdr *seg_prev; short t_state; /* state of this connection */ short t_timer[TCPT_NTIMERS]; /* tcp timers */ short t_rxtshift; /* log(2) of rexmt exp. backoff */ @@ -170,21 +164,6 @@ struct tcpcb { #define TCP_REXMTVAL(tp) \ (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) -/* XXX - * We want to avoid doing m_pullup on incoming packets but that - * means avoiding dtom on the tcp reassembly code. That in turn means - * keeping an mbuf pointer in the reassembly queue (since we might - * have a cluster). As a quick hack, the source & destination - * port numbers (which are no longer needed once we've located the - * tcpcb) are overlayed with an mbuf pointer. - */ -#if SIZEOF_CHAR_P == 4 -typedef struct mbuf *mbufp_32; -#else -typedef void* mbufp_32; -#endif -#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) - /* * TCP statistics. * Many of these should be kept per connection, Index: slirp-1.0.17/src/tcpip.h =================================================================== --- slirp-1.0.17.orig/src/tcpip.h +++ slirp-1.0.17/src/tcpip.h @@ -44,8 +44,7 @@ struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ struct tcphdr ti_t; /* tcp header */ }; -#define ti_next ti_i.ih_next -#define ti_prev ti_i.ih_prev +#define ti_mbuf ti_i.ih_mbuf.mptr #define ti_x1 ti_i.ih_x1 #define ti_pr ti_i.ih_pr #define ti_len ti_i.ih_len @@ -62,6 +61,16 @@ struct tcpiphdr { #define ti_sum ti_t.th_sum #define ti_urp ti_t.th_urp +#define tcpiphdr2qlink(T) \ + ((struct qlink *)(((char *)(T)) - sizeof(struct qlink))) +#define qlink2tcpiphdr(Q) \ + ((struct tcpiphdr *)(((char *)(Q)) + sizeof(struct qlink))) +#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next) +#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev) +#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next) +#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink *)(T)) +#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr *)(T)) + /* * Just a clean way to get to the first byte * of the packet Index: slirp-1.0.17/src/udp.c =================================================================== --- slirp-1.0.17.orig/src/udp.c +++ slirp-1.0.17/src/udp.c @@ -131,8 +131,7 @@ udp_input(m, iphlen) * Checksum extended UDP header and data. */ if (udpcksum && uh->uh_sum) { - ((struct ipovly *)ip)->ih_next = 0; - ((struct ipovly *)ip)->ih_prev = 0; + memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr)); ((struct ipovly *)ip)->ih_x1 = 0; ((struct ipovly *)ip)->ih_len = uh->uh_ulen; /* keep uh_sum for ICMP reply @@ -259,7 +258,7 @@ udp_output(so, m, addr) * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); - ui->ui_next = ui->ui_prev = 0; + memset(&ui->ui_i.ih_mbuf, 0, sizeof(struct mbuf_ptr)); ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ Index: slirp-1.0.17/src/udp.h =================================================================== --- slirp-1.0.17.orig/src/udp.h +++ slirp-1.0.17/src/udp.h @@ -60,8 +60,7 @@ struct udpiphdr { struct ipovly ui_i; /* overlaid ip structure */ struct udphdr ui_u; /* udp header */ }; -#define ui_next ui_i.ih_next -#define ui_prev ui_i.ih_prev +#define ui_mbuf ui_i.ih_mbuf.mptr #define ui_x1 ui_i.ih_x1 #define ui_pr ui_i.ih_pr #define ui_len ui_i.ih_len
# Bullseye/testing amd64 qemu VM 2020-09-01 https://wiki.debian.org/UserModeLinux https://web.archive.org/web/20100212221731/http://www.wlug.org.nz/UserModeLinux https://christine.website/blog/howto-usermode-linux-2019-07-07 dpkg --add-architecture i386 apt update apt dist-upgrade apt install systemd-coredump dpkg-dev devscripts quilt colordiff cdbs fakeroot meson cmake pkg-config libglib2.0-dev socat mc lightdm xserver-xorg openbox xterm htop gdb debootstrap user-mode-linux wget http://ftp.de.debian.org/debian/pool/main/s/slirp/slirp_1.0.17-10_amd64.deb wget http://ftp.de.debian.org/debian/pool/main/s/slirp/slirp_1.0.17-10_i386.deb dpkg -i slirp_1.0.17-10_amd64.deb apt install -f reboot mkdir /home/benutzer/source/slirp/orig -p cd /home/benutzer/source/slirp/orig dget http://deb.debian.org/debian/pool/main/s/slirp/slirp_1.0.17-10.dsc cd cd /home/benutzer/source/slirp cp orig try1 -a cd try1/slirp-1.0.17/ slirp-1.0.17/debian/rules -CFLAGS += $(CPPFLAGS) -I. -DUSE_PPP -DUSE_MS_DNS -fno-strict-aliasing -Wno-unused -std=gnu89 +CFLAGS += $(CPPFLAGS) -I. -DUSE_PPP -DUSE_MS_DNS -fno-strict-aliasing -Wno-unused -std=gnu89 -DDEBUG dpkg-buildpackage debootstrap --arch=amd64 --include=net-tools,bind9-dnsutils,mc,socat,wget bullseye /root/chroot http://192.168.178.25:9999/debian-11-bullseye-deb.debian.org env -i TERM=xterm LANG=de_DE.UTF-8 /usr/sbin/chroot chroot /bin/su - passwd cat <<EOF > /etc/network/interfaces.d/eth0 auto eth0 #iface eth0 inet dhcp iface eth0 inet static address 10.0.2.14 netmask 255.255.255.240 gateway 10.0.2.2 # #resolv.conf: # #nameserver 192.168.178.2 EOF exit . cat <<EOF > /root/slirp #!/bin/bash exec /usr/bin/slirp -d 7 EOF chmod +x /root/slirp export DISPLAY=:0 export XAUTHORITY=/home/benutzer/.Xauthority /usr/bin/linux.uml \ root=/dev/root \ rootfstype=hostfs \ rootflags=/root/chroot \ rw \ mem=128M \ eth0=slirp,,/root/slirp # Inside user mode linux systemctl stop systemd-timesyncd.service # to stop udp wget http://192.168.178.1 -O /tmp/x tail -f /root/slirp_debug ... TCP stats: ... 11 packets received 0 acks (for 0 bytes) 0 duplicate acks 0 acks for unsent data 0 packets received in sequence (0 bytes) 0 completely duplicate packets (0 bytes) 0 packets with some duplicate data (0 bytes duped) 0 out-of-order packets (0 bytes) 0 packets of data after window (0 bytes) 0 window probes 0 window update packets 0 packets received after close 11 discarded for bad checksums 0 discarded for bad header offset fields ... UDP stats: 136 datagrams received 0 with packets shorter than header 136 with bad checksums ... . root@debian:/home/benutzer/source/slirp/try1/slirp-1.0.17/src# gdb -q --pid $(pidof slirp) b tcp_input cont i386 example debugging: (gdb) x/60xb w 0x57f708a4: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x57f708ac: 0x00 0x06 0x00 0x28 0x0a 0x00 0x02 0x0e 0x57f708b4: 0xc0 0xa8 0xb2 0x01 0xaf 0xc6 0x00 0x50 0x57f708bc: 0x41 0xd3 0xf5 0x58 0x00 0x00 0x00 0x00 0x57f708c4: 0xa0 0x02 0xfa 0xf0 0x44 0x2a 0x00 0x00 0x57f708cc: 0x02 0x04 0x05 0xb4 0x04 0x02 0x08 0x0a 0x57f708d4: 0x1e 0x7f 0x84 0x6e 0x00 0x00 0x00 0x00 0x57f708dc: 0x01 0x03 0x03 0x04 (gdb) display/x sum 1: /x sum = 0x0 (gdb) display/x len 2: /x len = 0x3c (gdb) display len 3: len = 60 (gdb) undisp 2 (gdb) next 82 if ((1 & (long) w) && (mlen > 0)) { 1: /x sum = 0x0 3: len = <optimized out> (gdb) display mlen 4: mlen = <optimized out> (gdb) next 94 while ((mlen -= 32) >= 0) { 1: /x sum = 0x0 3: len = <optimized out> 4: mlen = 28 (gdb) 95 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 96 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 1: /x sum = 0x0 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 97 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 1: /x sum = 0x3c0c 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 98 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 1: /x sum = 0x1fd2d 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 99 w += 16; 1: /x sum = 0x32963 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 102 while ((mlen -= 8) >= 0) { 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = 20 (gdb) 103 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 104 w += 4; 1: /x sum = 0x44741 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 103 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 104 w += 4; 1: /x sum = 0x50b54 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 103 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 104 w += 4; 1: /x sum = 0x5f8f6 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 107 if (mlen == 0 && byte_swapped == 0) 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 109 REDUCE; 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 110 while ((mlen -= 2) >= 0) { 1: /x sum = 0xf8fb 3: len = <optimized out> 4: mlen = 2 (gdb) 111 sum += *w++; 1: /x sum = 0xf8fb 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 110 while ((mlen -= 2) >= 0) { 1: /x sum = 0xfbfc 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 111 sum += *w++; 1: /x sum = 0xfbfc 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 110 while ((mlen -= 2) >= 0) { 1: /x sum = 0xffff 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 114 if (byte_swapped) { 1: /x sum = 0xffff 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 125 } else if (mlen == -1) 1: /x sum = 0xffff 3: len = <optimized out> 4: mlen = <optimized out> (gdb) 142 REDUCE; 1: /x sum = <optimized out> 3: len = <optimized out> 4: mlen = <optimized out> (gdb) tcp_input (m=0x57f70850, iphlen=<optimized out>, inso=0x0) at ./tcp_input.c:322 322 off = ti->ti_off << 2; # Filling in a amd64 debug session the buffer with the values found valid at i386: (gdb) x/60xb w 0x558551242c50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x558551242c58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x558551242c60: 0x00 0xa8 0x00 0x28 0xb6 0xaa 0x00 0x50 0x558551242c68: 0x0d 0x71 0x80 0xd2 0x00 0x00 0x00 0x00 0x558551242c70: 0xa0 0x02 0xfa 0xf0 0x42 0xd8 0x00 0x00 0x558551242c78: 0x02 0x04 0x05 0xb4 0x04 0x02 0x08 0x0a 0x558551242c80: 0x60 0xc5 0xe5 0x7e 0x00 0x00 0x00 0x00 0x558551242c88: 0x01 0x03 0x03 0x04 (gdb) set *(((char*)0x558551242c50)+ 0) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 1) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 2) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 3) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 4) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 5) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 6) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 7) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 8) = 0x00 (gdb) set *(((char*)0x558551242c50)+ 9) = 0x06 (gdb) set *(((char*)0x558551242c50)+10) = 0x00 (gdb) set *(((char*)0x558551242c50)+11) = 0x28 (gdb) set *(((char*)0x558551242c50)+12) = 0x0a (gdb) set *(((char*)0x558551242c50)+13) = 0x00 (gdb) set *(((char*)0x558551242c50)+14) = 0x02 (gdb) set *(((char*)0x558551242c50)+15) = 0x0e (gdb) set *(((char*)0x558551242c50)+16) = 0xc0 (gdb) set *(((char*)0x558551242c50)+17) = 0xa8 (gdb) set *(((char*)0x558551242c50)+18) = 0xb2 (gdb) set *(((char*)0x558551242c50)+19) = 0x01 (gdb) set *(((char*)0x558551242c50)+20) = 0xaf (gdb) set *(((char*)0x558551242c50)+21) = 0xc6 (gdb) set *(((char*)0x558551242c50)+22) = 0x00 (gdb) set *(((char*)0x558551242c50)+23) = 0x50 (gdb) set *(((char*)0x558551242c50)+24) = 0x41 (gdb) set *(((char*)0x558551242c50)+25) = 0xd3 (gdb) set *(((char*)0x558551242c50)+26) = 0xf5 (gdb) set *(((char*)0x558551242c50)+27) = 0x58 (gdb) set *(((char*)0x558551242c50)+28) = 0x00 (gdb) set *(((char*)0x558551242c50)+29) = 0x00 (gdb) set *(((char*)0x558551242c50)+30) = 0x00 (gdb) set *(((char*)0x558551242c50)+31) = 0x00 (gdb) set *(((char*)0x558551242c50)+32) = 0xa0 (gdb) set *(((char*)0x558551242c50)+33) = 0x02 (gdb) set *(((char*)0x558551242c50)+34) = 0xfa (gdb) set *(((char*)0x558551242c50)+35) = 0xf0 (gdb) set *(((char*)0x558551242c50)+36) = 0x44 (gdb) set *(((char*)0x558551242c50)+37) = 0x2a (gdb) set *(((char*)0x558551242c50)+38) = 0x00 (gdb) set *(((char*)0x558551242c50)+39) = 0x00 (gdb) set *(((char*)0x558551242c50)+40) = 0x02 (gdb) set *(((char*)0x558551242c50)+41) = 0x04 (gdb) set *(((char*)0x558551242c50)+42) = 0x05 (gdb) set *(((char*)0x558551242c50)+43) = 0xb4 (gdb) set *(((char*)0x558551242c50)+44) = 0x04 (gdb) set *(((char*)0x558551242c50)+45) = 0x02 (gdb) set *(((char*)0x558551242c50)+46) = 0x08 (gdb) set *(((char*)0x558551242c50)+47) = 0x0a (gdb) set *(((char*)0x558551242c50)+48) = 0x1e (gdb) set *(((char*)0x558551242c50)+49) = 0x7f (gdb) set *(((char*)0x558551242c50)+50) = 0x84 (gdb) set *(((char*)0x558551242c50)+51) = 0x6e (gdb) set *(((char*)0x558551242c50)+52) = 0x00 (gdb) set *(((char*)0x558551242c50)+53) = 0x00 (gdb) set *(((char*)0x558551242c50)+54) = 0x00 (gdb) set *(((char*)0x558551242c50)+55) = 0x00 (gdb) set *(((char*)0x558551242c50)+56) = 0x01 (gdb) set *(((char*)0x558551242c50)+57) = 0x03 (gdb) set *(((char*)0x558551242c50)+58) = 0x03 (gdb) set *(((char*)0x558551242c50)+59) = 0x04 (gdb) x/60xb w 0x558551242c50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x558551242c58: 0x00 0x06 0x00 0x28 0x0a 0x00 0x02 0x0e 0x558551242c60: 0xc0 0xa8 0xb2 0x01 0xaf 0xc6 0x00 0x50 0x558551242c68: 0x41 0xd3 0xf5 0x58 0x00 0x00 0x00 0x00 0x558551242c70: 0xa0 0x02 0xfa 0xf0 0x44 0x2a 0x00 0x00 0x558551242c78: 0x02 0x04 0x05 0xb4 0x04 0x02 0x08 0x0a 0x558551242c80: 0x1e 0x7f 0x84 0x6e 0x00 0x00 0x00 0x00 0x558551242c88: 0x01 0x03 0x03 0x04 (gdb) display/x sum 1: /x sum = 0x0 (gdb) display/x len 2: /x len = 0x3c (gdb) display len 3: len = 60 (gdb) undisp 2 (gdb) next 78 len -= mlen; 1: /x sum = 0x0 3: len = 60 (gdb) display mlen 4: mlen = 60 (gdb) next 82 if ((1 & (long) w) && (mlen > 0)) { 1: /x sum = 0x0 3: len = 0 4: mlen = 60 (gdb) 94 while ((mlen -= 32) >= 0) { 1: /x sum = 0x0 3: len = 0 4: mlen = 28 (gdb) 95 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = 0x0 3: len = 0 4: mlen = 28 (gdb) 96 sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 1: /x sum = 0x0 3: len = 0 4: mlen = 28 (gdb) 97 sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 1: /x sum = 0x3c0c 3: len = 0 4: mlen = 28 (gdb) 98 sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 1: /x sum = 0x1fd2d 3: len = 0 4: mlen = 28 (gdb) 99 w += 16; 1: /x sum = 0x32963 3: len = 0 4: mlen = 28 (gdb) 102 while ((mlen -= 8) >= 0) { 1: /x sum = 0x32963 3: len = 0 4: mlen = 20 (gdb) 103 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = 0x32963 3: len = 0 4: mlen = <optimized out> (gdb) 104 w += 4; 1: /x sum = 0x44741 3: len = 0 4: mlen = <optimized out> (gdb) 103 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = 0x44741 3: len = 0 4: mlen = <optimized out> (gdb) 104 w += 4; 1: /x sum = 0x50b54 3: len = 0 4: mlen = <optimized out> (gdb) 103 sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 1: /x sum = 0x50b54 3: len = 0 4: mlen = <optimized out> (gdb) 104 w += 4; 1: /x sum = 0x5f8f6 3: len = 0 4: mlen = <optimized out> (gdb) 107 if (mlen == 0 && byte_swapped == 0) 1: /x sum = 0x5f8f6 3: len = 0 4: mlen = <optimized out> (gdb) 109 REDUCE; 1: /x sum = 0x5f8f6 3: len = 0 4: mlen = <optimized out> (gdb) 110 while ((mlen -= 2) >= 0) { 1: /x sum = 0xf8fb 3: len = 0 4: mlen = 2 (gdb) 111 sum += *w++; 1: /x sum = 0xf8fb 3: len = 0 4: mlen = <optimized out> (gdb) 110 while ((mlen -= 2) >= 0) { 1: /x sum = 0xfbfc 3: len = 0 4: mlen = <optimized out> (gdb) 111 sum += *w++; 1: /x sum = 0xfbfc 3: len = 0 4: mlen = <optimized out> (gdb) 110 while ((mlen -= 2) >= 0) { 1: /x sum = 0xffff 3: len = 0 4: mlen = <optimized out> (gdb) next 114 if (byte_swapped) { 1: /x sum = 0xffff 3: len = 0 4: mlen = <optimized out> (gdb) 125 } else if (mlen == -1) 1: /x sum = 0xffff 3: len = 0 4: mlen = <optimized out> (gdb) 130 if (len) { 1: /x sum = 0xffff 3: len = 0 4: mlen = -2 (gdb) 142 REDUCE; 1: /x sum = 0xffff 3: len = 0 4: mlen = <optimized out> (gdb) 143 return (~sum & 0xffff); 1: /x sum = 0xffff 3: len = <optimized out> 4: mlen = <optimized out> (gdb) tcp_input (m=0x558551242be0, iphlen=<optimized out>, inso=inso@entry=0x0) at ./tcp_input.c:322 322 off = ti->ti_off << 2; --> cksum works right at amd64 too ! ############ git clone https://gitlab.freedesktop.org/slirp/libslirp.git cd libslirp/ meson build ninja -C build -> does not build a executable ? ############ (gdb) step tcp_input (m=0x558551242be0, iphlen=20, inso=inso@entry=0x0) at ./tcp_input.c:259 259 DEBUG_CALL("tcp_input"); (gdb) next 260 DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", (gdb) 266 if (m == NULL) { (gdb) 281 tcpstat.tcps_rcvtotal++; (gdb) 286 ti = mtod(m, struct tcpiphdr *); (gdb) x/60xb m->m_hdr.mh_data 0x558551242c50: 0x45 0x00 0x28 0x00 0xfe 0x75 0x00 0x40 0x558551242c58: 0x40 0x06 0x46 0x06 0x0a 0x00 0x02 0x0e 0x558551242c60: 0xc0 0xa8 0xb2 0x01 0xb6 0xd2 0x00 0x50 0x558551242c68: 0xfb 0x4b 0xa6 0x32 0x00 0x00 0x00 0x00 0x558551242c70: 0xa0 0x02 0xfa 0xf0 0x13 0x4d 0x00 0x00 0x558551242c78: 0x02 0x04 0x05 0xb4 0x04 0x02 0x08 0x0a 0x558551242c80: 0x61 0x01 0x01 0x6b 0x00 0x00 0x00 0x00 0x558551242c88: 0x01 0x03 0x03 0x04 (gdb) next 287 if (iphlen > sizeof(struct ip )) { (gdb) 299 save_ip = *ip; (gdb) 313 if(cksum(m, len)) { (gdb) x/60xb m->m_hdr.mh_data 0x558551242c50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x558551242c58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x558551242c60: 0x00 0xa8 0x00 0x28 0xb6 0xd2 0x00 0x50 0x558551242c68: 0xfb 0x4b 0xa6 0x32 0x00 0x00 0x00 0x00 0x558551242c70: 0xa0 0x02 0xfa 0xf0 0x13 0x4d 0x00 0x00 0x558551242c78: 0x02 0x04 0x05 0xb4 0x04 0x02 0x08 0x0a 0x558551242c80: 0x61 0x01 0x01 0x6b 0x00 0x00 0x00 0x00 0x558551242c88: 0x01 0x03 0x03 0x04 (gdb) bt #0 tcp_input (m=0x558551242be0, iphlen=<optimized out>, inso=inso@entry=0x0) at ./tcp_input.c:313 #1 0x000055854f58399c in ip_input (m=<optimized out>) at ip_input.c:214 #2 0x000055854f58c01f in sl_dispatch (ttyp=ttyp@entry=0x55855123e2c0) at ./sl.c:127 #3 0x000055854f58c1ee in sl_input (ttyp=0x55855123e2c0, if_bptr=0x7ffddbe4f67e "\300\264\004\002\b\n`\354\303a", if_n=63) at ./sl.c:35 #4 0x000055854f581ed2 in if_input (ttyp=0x55855123e2c0) at ./if.c:191 #5 0x000055854f58567f in main_loop () at ./main.c:1158 #6 0x000055854f5757d7 in main (argc=3, argv=0x7ffddbe504f8) at ./main.c:95 (gdb) print sizeof(*ti) $12 = 56 <<<<<<<<<<< this is just 40 bytes on 32 bit (gdb) ptype /o struct tcpiphdr /* offset | size */ type = struct tcpiphdr { /* 0 | 32 */ struct ipovly { <<<<<<<<<<< this is just 20 bytes on 32 bit /* 0 | 8 */ caddr32_t ih_next; /* 8 | 8 */ caddr32_t ih_prev; /* 16 | 1 */ u_int8_t ih_x1; /* 17 | 1 */ u_int8_t ih_pr; /* 18 | 2 */ int16_t ih_len; /* 20 | 4 */ struct in_addr { /* 20 | 4 */ in_addr_t s_addr; /* total size (bytes): 4 */ } ih_src; /* 24 | 4 */ struct in_addr { /* 24 | 4 */ in_addr_t s_addr; /* total size (bytes): 4 */ } ih_dst; /* XXX 4-byte padding */ /* total size (bytes): 32 */ } ti_i; /* 32 | 20 */ struct tcphdr { /* 32 | 2 */ u_int16_t th_sport; /* 34 | 2 */ u_int16_t th_dport; /* 36 | 4 */ tcp_seq th_seq; /* 40 | 4 */ tcp_seq th_ack; /* 44: 0 | 4 */ u_int th_x2 : 4; /* 44: 4 | 4 */ u_int th_off : 4; /* 45 | 1 */ u_int8_t th_flags; /* 46 | 2 */ u_int16_t th_win; /* 48 | 2 */ u_int16_t th_sum; /* 50 | 2 */ u_int16_t th_urp; /* total size (bytes): 20 */ } ti_t; /* XXX 4-byte padding */ /* total size (bytes): 56 */ } (gdb) print sizeof(void*) $14 = 8 (gdb) print sizeof(struct ipovly) $15 = 32 (gdb) ptype /o struct ipovly /* offset | size */ type = struct ipovly { /* 0 | 8 */ caddr32_t ih_next; <<<<<<<<<<< this is just 4 bytes on 32 bit /* 8 | 8 */ caddr32_t ih_prev; <<<<<<<<<<< this is just 4 bytes on 32 bit /* 16 | 1 */ u_int8_t ih_x1; /* 17 | 1 */ u_int8_t ih_pr; /* 18 | 2 */ int16_t ih_len; /* 20 | 4 */ struct in_addr { /* 20 | 4 */ in_addr_t s_addr; /* total size (bytes): 4 */ } ih_src; /* 24 | 4 */ struct in_addr { /* 24 | 4 */ in_addr_t s_addr; /* total size (bytes): 4 */ } ih_dst; /* XXX 4-byte padding */ /* total size (bytes): 32 */ } (gdb) detach ############ https://gitlab.freedesktop.org/slirp/libslirp/-/commit/c11b407804272b71e5bdd7a2a9181c64c7a594ed https://gitlab.freedesktop.org/slirp/libslirp/-/commit/c11b407804272b71e5bdd7a2a9181c64c7a594ed.patch