Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
768 views
in Technique[技术] by (71.8m points)

sockets - Sending UDP packet in Linux Kernel

For a project, I'm trying to send UDP packets from Linux kernel-space. I'm currently 'hard-coding' my code into the kernel (which I appreciate isn't the best/neatest way) but I'm trying to get a simple test to work (sending "TEST"). It should be mentioned I'm a newbie to kernel hacking - I'm not that clued up on many principles and techniques!

Every time my code gets run the system hangs and I have to reboot - no mouse/keyboard response and the scroll and caps lock key lights flash together - I'm not sure what this means, but I'm assuming it's a kernel panic?

The repeat_send code is unnecessary for this test code, yet when it's working I want to send large messages that may require multiple 'send's - I'm not sure that if could be a cause of my issues?

N.B. This code is being inserted into neighbour.c of linux-source/net/core/ origin, hence the use of NEIGH_PRINTK1, it's just a macro wrapper round printk.

I'm really banging my head against a brick wall here, I can't spot anything obvious, can anyone point me in the right direction (or spot that blindingly obvious error!)?

Here's what I have so far:

void mymethod()
{
    struct socket sock;
    struct sockaddr_in addr_in;
    int ret_val;
    unsigned short port = htons(2048);
    unsigned int host = in_aton("192.168.1.254");
    unsigned int length = 5;
    char *buf = "TEST";
    struct msghdr msg;
    struct iovec iov;
    int len = 0, written = 0, left = length;
    mm_segment_t oldmm;

    NEIGH_PRINTK1("forwarding sk_buff at: %p.
", skb);

    if ((ret_val = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
        NEIGH_PRINTK1("Error during creation of socket; terminating. code: %d
", ret_val);
        return;
    }

    memset(&addr_in, 0, sizeof(struct sockaddr_in));
    addr_in.sin_family=AF_INET;
    addr_in.sin_port = port;
    addr_in.sin_addr.s_addr = host;

    if((ret_val = sock.ops->bind(&sock, (struct sockaddr *)&addr_in, sizeof(struct sockaddr_in))) < 0) {
    NEIGH_PRINTK1("Error trying to bind socket. code: %d
", ret_val);
    goto close;
    }

    memset(&msg, 0, sizeof(struct msghdr));
    msg.msg_flags = 0;
    msg.msg_name = &addr_in;
    msg.msg_namelen = sizeof(struct sockaddr_in);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = NULL;
    msg.msg_controllen = 0;

repeat_send:
    msg.msg_iov->iov_len = left;
    msg.msg_iov->iov_base = (char *)buf + written;

    oldmm = get_fs(); 
    set_fs(KERNEL_DS);
    len = sock_sendmsg(&sock, &msg, left);
    set_fs(oldmm);

    if (len == -ERESTARTSYS)
        goto repeat_send;
    if (len > 0) {
        written += len;
        left -= len;
        if (left)
            goto repeat_send;
    }

close:
    sock_release(&sock);
}

Any help would be hugely appreciated, thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You may find it easier to use the netpoll API for UDP. Take a look at netconsole for an example of how it's used. The APIs you're using are more intended for userspace (you should never have to play with segment descriptors to send network data!)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...