MDCHAIN(9)

πŸ’– MDCHAIN(9) πŸ’–

okay bestie, sit DOWN, because we're about to talk about mdchain β€” the Kernel Developer's Manual page that lives in section 9 and is literally your group chat for taking an mbuf chain apart into whatever data types you want 🧚✨


✨ NAME ✨

mdchain, md_initm, md_done, md_append_record, md_next_record, md_get_uint8, md_get_uint16, md_get_uint16be, md_get_uint16le, md_get_uint32, md_get_uint32be, md_get_uint32le, md_get_int64, md_get_int64be, md_get_int64le, md_get_mem, md_get_mbuf, md_get_uio β€” it's giving "a whole little set of functions whose entire job is to dissect an mbuf chain into various data types" πŸ’…


🌸 SYNOPSIS 🌸

first things first, you gotta have the goods:

options LIBMCHAIN
kldload libmchain

then the includes, no skipping:

#include <sys/param.h>
#include <sys/uio.h>
#include <sys/mchain.h>

and here's the whole squad, signatures verbatim because we do NOT play with function prototypes:

void
md_initm(struct mdchain *mdp, struct mbuf *m);

void
md_done(struct mdchain *mdp);

void
md_append_record(struct mdchain *mdp, struct mbuf *top);

int
md_next_record(struct mdchain *mdp);

int
md_get_uint8(struct mdchain *mdp, uint8_t *x);

int
md_get_uint16(struct mdchain *mdp, uint16_t *x);

int
md_get_uint16be(struct mdchain *mdp, uint16_t *x);

int
md_get_uint16le(struct mdchain *mdp, uint16_t *x);

int
md_get_uint32(struct mdchain *mdp, uint32_t *x);

int
md_get_uint32be(struct mdchain *mdp, uint32_t *x);

int
md_get_uint32le(struct mdchain *mdp, uint32_t *x);

int
md_get_int64(struct mdchain *mdp, int64_t *x);

int
md_get_int64be(struct mdchain *mdp, int64_t *x);

int
md_get_int64le(struct mdchain *mdp, int64_t *x);

int
md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type);

int
md_get_mbuf(struct mdchain *mdp, int size, struct mbuf **m);

int
md_get_uio(struct mdchain *mdp, struct uio *uiop, int size);

πŸ¦‹ DESCRIPTION πŸ¦‹

so these functions are the ones you call when you want to decompose mbuf chains into various data types. that's the whole vibe. 🫢

the mdchain structure is your working context β€” your little backstage pass β€” and you should initialize it through a call of the mb_initm() function. it has these fields:

  • md_top (struct mbuf *) β€” a pointer to the top of the parsed mbuf chain. the head of the whole operation πŸ‘‘
  • md_cur (struct mbuf *) β€” a pointer to the currently parsed mbuf. the one currently on stage ✨
  • md_pas (int) β€” offset in the current mbuf.

the md_done() function disposes of an mbuf chain pointed to by the mdp->md_top field and sets the field to NULL. clean exit, no loose ends, iconic πŸ’…


the md_append_record() appends a new mbuf chain using m_nextpkt field to form a single linked list of mbuf chains. and if the mdp->md_top field is NULL? then this function behaves exactly as the md_initm() function does. no cap.


the md_next_record() function extracts the next mbuf chain and disposes the current one, if any. for a new mbuf chain it calls the md_initm() function. and if there is no data left? the function returns ENOENT. 😭


okay so all the md_get_*() functions perform an actual copy of the data from an mbuf chain. and the ones with le or be suffixes will perform conversion to the little- or big-endian data formats. periodt.


the md_get_mem() function copies size bytes of data specified by the source argument from an mbuf chain. the type argument specifies the method used to perform a copy, and can be one of the following:

  • MB_MSYSTEM β€” use the bcopy() function.
  • MB_MUSER β€” use the copyin(9) function.
  • MB_MINLINE β€” use an "inline" loop which does not call any function. speed, but make it homemade ⚑

and if target is NULL, an actual copy is not performed and the function just skips the given number of bytes. sneaky but valid πŸ™ˆ


πŸ’€ RETURN VALUES πŸ’€

all int functions return zero if successful, otherwise an error code is returned.

⚠️ note: after failure of any function, an mbuf chain is left in the broken state and only the md_done() function can safely be called to destroy it. like… it's broken broken. do not touch it with anything else, bestie, that's the rule 🚨

🌈 EXAMPLES 🌈

here's how it actually looks in the wild:

struct mdchain *mdp;
struct mbuf *m;
uint16_t length;
uint8_t byte;

receive(so, &m);
md_initm(mdp, m);
if (md_get_uint8(mdp, &byte) != 0 ||
    md_get_uint16le(mdp, &length) != 0)
        error = EBADRPC;
mb_done(mdp);

see how EBADRPC shows up if either getter trips? yeah. ate. πŸ”₯


πŸ‘€ SEE ALSO πŸ‘€


πŸŽ€ AUTHORS πŸŽ€

this manual page was written by Boris Popov <bp@FreeBSD.org>. king behavior, honestly πŸ‘‘


and that's the whole page, bestie πŸ’œ this one comes from Debian, dated February 28, 2001 β€” yes, 2001, she's a vintage icon and she still serves πŸ¦‹βœ¨

πŸ“¦ where this page comes from