October 30, 2022

BSD TCP/IP for Kyu - the "dtom" macro

This is in tcp_subr.c in tcp_close().

I have now copied and made minor changes to the source files I need. They compile, and with just a few warnings. One of these involves the dtom() macro, which is called in one place in tcp_close() in tcp_subr.c

Ignoring the details of the call for now, let's consider the macro. It is found in mbuf.h

#define dtom(x)         ((struct mbuf *)((int)(x) & ~(MSIZE-1)))
#define mtod(m,t)       ((t)((m)->m_data))
Note that mtod() is just fine, with the fringe benefit of casting the m_data field to whatever type is appropriate.

The dtom() macro gets XXX notes even in the original BSD files. My compiler warns that I am converting a pointer to an integer and then warns that I am converting it back again. This clearly will not work on some architectures and is a somewhat questionable trick that depends on the alignment of the mbuf structures when they are allocated.

Looking at code in NetBSD-2.0, dtom() had already been done away with.

Looking at code in NetBSD-1.3, the call that used dtom() in tcp_close() had been rewritten without a call to dtom(). It now looks like this:

        if (tp->t_template)
                FREE(tp->t_template, M_MBUF);
In the Net/3 code it is:
       if (tp->t_template)
                (void) m_free(dtom(tp->t_template));
In NetBSD-1.3 "FREE" is a macro in sys/malloc.h.

But why the dtom in the first place. Does t_template point to something of a different sort? Do they actually do something smart and keep track of the mbuf itself in NetBSD? In either case, tp is a pointer to a "struct tcpcb" and in both cases we see:

struct  tcpiphdr *t_template;

Aha! The vital change is in tcp_template(). In the Net/3 code, the code uses m_get() to allocate an mbuf then does n = mtod(m, struct tcpiphdr *); to get a pointer to the innards. But in NetBSD, the code does this:

MALLOC(n, struct tcpiphdr *, sizeof (struct tcpiphdr), M_MBUF, M_NOWAIT);
It allocates just the tcpip header it needs, so there is no need to use dtom to find the enclosing mbuf.

There are interesting issues with FREE and MALLOC in sys/malloc.h -- in particular the M_MBUF "type" thing. Just how the tcpip header qualifies as an mbuf in this context is foggy to me. What it is doing is to keep a "cache" of MBUF objects that have been freed in a linked list so they can just be handed out again. This makes sense and is a fine idea, but is the tcpiphdr big enough to serve as an mbuf in some future allocation? Apparently so.

I solve this in my own way. I put a static tcpip structure inside of the tcpcb structure and modify tcp_template to simply set the pointer to this. It will never need to be deallocated. Then I do away with the dtom macro entirely.

I have to reorder the header files in almost all the C source files so they include tcpip.h before tcp_var.h and then things are good.


Have any comments? Questions? Drop me a line!

Kyu / [email protected]