一个比较完整的协议族添加实例(2.6.29测试通过)

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <net/sock.h>
#include <linux/skbuff.h>

#define err(msg) printk("<0>""%s/n", msg)

#define AF_DRIVER 30

static int priv_family_create(struct net *net,struct socket *sock, int protocol);
static int socket_release(struct socket *sock);
static int socket_sendmsg(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *m, size_t total_len);
static void proto_close(struct sock *sk, long timeout);
static int proto_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len);
static int proto_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                        size_t len, int noblock, int flags, int *addr_len);

static struct net_proto_family priv_family =
{
        .family = AF_DRIVER,
        .owner = THIS_MODULE,
        .create = priv_family_create,
};

static struct proto_ops priv_socket_ops =
{
        .family = AF_DRIVER,
        .owner = THIS_MODULE,
        .release = socket_release,
        .sendmsg = socket_sendmsg,
        .recvmsg = sock_common_recvmsg,
};

static struct proto priv_proto_ops =
{
        .name = "privproto",
        .owner = THIS_MODULE,
        .close = proto_close,
        .sendmsg = proto_sendmsg,
        .recvmsg = proto_recvmsg,
        .obj_size = sizeof(struct sock),
};

static struct sk_buff_head buffqueue; /* goatsucker: store data buffer queue */

static int priv_family_create(struct net *net, struct socket *sock, int protocol)
{
        struct sock *sk;
        int err;

        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        sock->state = SS_UNCONNECTED;
        sock->ops = &priv_socket_ops;
        err = -ENOBUFS;
        sk = sk_alloc(net,AF_DRIVER, GFP_KERNEL, &priv_proto_ops);
        if (!sk)
        {
                err("sk_alloc");
                goto alloc_err;
        }

        sock_init_data(sock, sk); /* goatsucker: init sk_refcnt = 1 */
        sk->sk_family = AF_DRIVER;
        sk->sk_protocol = protocol;

        return 0;
alloc_err:
        return err;
}

/* goatsucker: socket_release/socket_sendmsg/socket_recvmsg is bsd layer represent */

static int socket_release(struct socket *sock)
{
        struct sock *sk = sock->sk;

        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        if (sk)
        {
                sock->sk = NULL;
                sk->sk_prot->close(sk, 0);
        }

        return 0;
}

static int socket_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len)
{
        struct sock *sk = sock->sk;

        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        return sk->sk_prot->sendmsg(iocb, sk, m, total_len);
}

/* goatsucker: proto_close/proto_sendmsg/proto_recvmsg is transmit layer represent */

static void priv_destroy_sock(struct sock *sk)
{
        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        skb_queue_purge(&sk->sk_receive_queue);
        skb_queue_purge(&sk->sk_error_queue);
        skb_queue_purge(&sk->sk_write_queue);
        sock_put(sk);
}

static void proto_close(struct sock *sk, long timeout)
{
        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        lock_sock(sk);
        sock_hold(sk); /* goatsucker: increment sk->sk_refcnt */
        sock_orphan(sk);
        release_sock(sk);

        local_bh_disable();
        bh_lock_sock(sk);
        priv_destroy_sock(sk);
        bh_unlock_sock(sk);
        local_bh_enable();
        sock_put(sk);
}

static int proto_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len)
{
        struct sk_buff *skb;

        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        skb = alloc_skb(len, GFP_KERNEL);
        if (!skb)
        {
                err("alloc_skb");
                return -1;
        }

        if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len) != 0)
        {
                err("memcpy_fromiovec");
                goto memcpy_err;
        }
        skb_queue_tail(&buffqueue, skb);

        return 0;
memcpy_err:
        kfree_skb(skb);
        return -EFAULT;
}

static int proto_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                        size_t len, int noblock, int flags, int *addr_len)
{
        struct sk_buff *skb;
        int copied;

        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
          dump_stack();
        skb = skb_dequeue(&buffqueue);
        if (skb)
        {
                if (memcpy_toiovec(msg->msg_iov, skb->data, skb->len) != 0)
                {
                        err("memcpy_toiovec");
                        kfree_skb(skb);
                        return -EFAULT;
                }

                copied = skb->len;
                kfree_skb(skb);
                return copied;
        }

        return 0;
}

static int privproto_init(void)
{
        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        skb_queue_head_init(&buffqueue);

        if (proto_register(&priv_proto_ops, 1) != 0)
        {
                err("proto_register");
                return -1;
        }

        if (sock_register(&priv_family) != 0)
        {
                err("sock_register");
                goto sock_err;
        }

        return 0;
sock_err:
        proto_unregister(&priv_proto_ops);
        return -1;
}

static void privproto_exit(void)
{
        printk("<0>""FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        sock_unregister(AF_DRIVER);
        proto_unregister(&priv_proto_ops);
        skb_queue_purge(&buffqueue);
}

module_init(privproto_init);
module_exit(privproto_exit);

MODULE_LICENSE("GPL");

 

=======================================================================================

测试程序

=======================================================================================

 

#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


#define err(msg) printf("%s/n", msg)
#define AF_DRIVER 30



int main(void)

{
        int sockfd;
        char buff[1024], data[] = "goatsucker";
        ssize_t nread;

        printf("FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        sockfd = socket(AF_DRIVER, SOCK_STREAM, IPPROTO_TCP);
        if (sockfd == -1)
        {
                perror("socket");
                return -1;
        }

        printf("FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
          send(sockfd,buff,sizeof(buff),0);
        if (write(sockfd, "goatsucker", strlen(data)) == -1)
        {
                perror("write");
                goto err;
        }

        printf("FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);
        memset(buff, '/0', sizeof(buff));
        printf("FUNCTION %s | LINE %d/n",__FUNCTION__,__LINE__);

          recv(sockfd,buff,sizeof(buff),0);
        nread = read(sockfd, buff, sizeof(buff));
        if (nread == -1)
        {
                perror("read");
                goto err;
        }

        else
                printf("strlen(buff) = %d, %s/n", strlen(buff), buff);

        close(sockfd);
        return 0;

err:
        close(sockfd);
        return -1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值