Sunday, July 10, 2022

[SOLVED] How do I fill out the iov_iter structure for use with msghdr?

Issue

I am trying to send a UDP packet from a driver using sock_sendmsg().

There are several guides on how to use sock_sendmsg() and msghdr to fill out at a UDP packet and transmit it, but they are all for older kernel versions. Sometime between 3.13 and 4.8, the struct msghdr changed from:

struct msghdr {
    void    *   msg_name;   /* Socket name          */
    int     msg_namelen;    /* Length of name       */
    struct iovec *  msg_iov;    /* Data blocks          */
    __kernel_size_t msg_iovlen; /* Number of blocks     */
    void    *   msg_control;    /* Per protocol magic (eg BSD file descriptor passing) */
    __kernel_size_t msg_controllen; /* Length of cmsg list */
    unsigned int    msg_flags;
};

To:

struct msghdr {
    void        *msg_name;  /* ptr to socket address structure */
    int     msg_namelen;    /* size of socket address structure */
    struct iov_iter msg_iter;   /* data */
    void        *msg_control;   /* ancillary data */
    __kernel_size_t msg_controllen; /* ancillary data buffer length */
    unsigned int    msg_flags;  /* flags on received message */
    struct kiocb    *msg_iocb;  /* ptr to iocb for async requests */
};

Instead of setting msg_iov to point to an iovec with the data:

struct msghdr msg = {};
struct iovec iov = {}; 

iov.iov_base = data;
iov.iov_len = dataLen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;

There is now an iov_iter structure:

struct iov_iter {
    int type;
    size_t iov_offset;
    size_t count;
    union {
        const struct iovec *iov;
        const struct kvec *kvec;
        const struct bio_vec *bvec;
        struct pipe_inode_info *pipe;
    };
    union {
        unsigned long nr_segs;
        struct {
            int idx;
            int start_idx;
        };
    };
};

How do I fill out the iov_iter structure inside of msghdr with data so that I can pass it to sock_sendmsg?


Solution

After some playing around and reading the guide posted by Ctx (lwn.net/Articles/625077), I figured it out.

unsigned long nr_segments = 1;
size_t count = 1;
struct msghdr msg = {};
struct iovec iov = {}; 

iov.iov_base = data;
iov.iov_len = dataLen;

iov_iter_init(&msg.msg_iter, READ, &iov, nr_segments, count);


Answered By - charlesw
Answer Checked By - Marie Seifert (WPSolving Admin)