⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 af_inet.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
字号:
/* af_inet.c * linqianghe@163.com * 2006-09-06 */#include <linux/module.h>#include <linux/in.h>#include "log.h"#include "af_inet.h"#include "dummy_ipv4.h"#include "inet_common.h"#include "protocol.h"#include "myip.h"#include "dev.h"#include "devinet.h"static int myinet_create(struct socket *sock, int protocol);static struct net_proto_family myinet_family_ops = {	.family = MY_PF_INET,	.create = myinet_create,	.owner	= THIS_MODULE,};static struct list_head myinetsw[SOCK_MAX];static DEFINE_SPINLOCK( myinetsw_lock );const struct proto_ops myinet_dummy_ops = {	.family = MY_PF_INET,	.owner = THIS_MODULE,	.release = myinet_release,	.sendmsg =	myinet_sendmsg,	.recvmsg =	mysock_common_recvmsg,	.ioctl =	myinet_ioctl,};static struct inet_protosw myinetsw_array[] ={	{		.type =			SOCK_DUMMY,		.protocol =		IPPROTO_DUMMY,		.prot =			&dummy_prot,		.ops =			&myinet_dummy_ops,		.capability =	-1,		.no_check =		0,		.flags =		INET_PROTOSW_PERMANENT,	}};#define INETSW_ARRAY_LEN (sizeof(myinetsw_array) / sizeof(struct inet_protosw))static struct net_protocol dummy_protocol = {	.handler =	dummy_rcv,};#ifdef MYIPV4_DEBUGstatic void dump_protolist( struct proto *prot_node ){	struct proto *prot;	struct list_head *head = prot_node->node.prev;	PR_TRACE("all the protocol registered in the kernel...\n");	list_for_each_entry( prot, head, node ){		if( prot != NULL )			PR_TRACE("%s\n", prot->name );	}	PR_TRACE("done!\n"); }#else#define dump_protolist( prot_node )#endifstatic int wrap_sock_register( struct net_proto_family *ops ){#ifdef MYIPV4_DEBUG	if( sock_register( ops ) == 0 ){		PR_DEEP_DEBUG( "Registered debug protocol family: %d\n", MY_PF_INET );		return 0;	}	PR_ERR( "find an empty family %d for myipv4 debug failed!\n", MY_PF_INET );	return -EEXIST;#else	sock_unregister( PF_INET );		//unregister the kernel's inet family, can't recover.	if( sock_register( ops ) != 0 ){		PR_ERR( "replace the kernel's inet family failed!\n");		return -ENOBUFS;	}	PR_NOTICE( "replaced kernel's inet family: %d\n", PF_INET );	return 0;#endif	}void myinet_register_protosw(struct inet_protosw *p){	struct list_head *lh;	struct inet_protosw *answer;	int protocol = p->protocol;	struct list_head *last_perm;	spin_lock_bh( &myinetsw_lock );	if (p->type >= SOCK_MAX)		goto out_illegal;	answer = NULL;	last_perm = &myinetsw[p->type];	list_for_each( lh, &myinetsw[p->type] ){		answer = list_entry( lh, struct inet_protosw, list );		if( INET_PROTOSW_PERMANENT & answer->flags ){			if( protocol == answer->protocol )				break;			last_perm = lh;		}		answer = NULL;	}	if( answer )		goto out_permanent;	list_add_rcu( &p->list, last_perm );out:	spin_unlock_bh( &myinetsw_lock );	synchronize_net();	return;out_permanent:	PR_ERR( "Attempt to override permanent protocol %d.\n", protocol );	goto out;out_illegal:	PR_ERR( "Ignoring attempt to register invalid socket type %d.\n", p->type );	goto out;}void myinet_unregister_protosw( struct inet_protosw *p ){	if( INET_PROTOSW_PERMANENT & p->flags ){		PR_ERR( "Attempt to unregister permanent protocol %d.\n", p->protocol );	}else{		spin_lock_bh( &myinetsw_lock );		list_del_rcu( &p->list );		spin_unlock_bh( &myinetsw_lock );		synchronize_net();	}}void myinet_sock_destruct(struct sock *sk){	struct inet_sock *inet = inet_sk(sk);	__skb_queue_purge(&sk->sk_receive_queue);	__skb_queue_purge(&sk->sk_error_queue);	if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {		PR_DEBUG( "Attempt to release TCP socket in state %d %p\n",						sk->sk_state, sk );		return;	}	if (!sock_flag(sk, SOCK_DEAD)) {		PR_DEBUG( "Attempt to release alive inet socket %p\n", sk );		return;	}	PR_DEBUG( "sk_rmem_alloc: %d\n", atomic_read(&sk->sk_rmem_alloc) );	BUG_TRAP( !atomic_read(&sk->sk_rmem_alloc) );	BUG_TRAP( !atomic_read(&sk->sk_wmem_alloc) );	BUG_TRAP( !sk->sk_wmem_queued );	BUG_TRAP( !sk->sk_forward_alloc );	kfree( inet->opt );	dst_release( sk->sk_dst_cache );	sk_refcnt_debug_dec( sk );}static int myinet_create( struct socket *sock, int protocol ){	struct sock *sk;	struct inet_protosw *answer;	struct proto *answer_prot;	char answer_no_check;	struct inet_sock *inet;	unsigned char answer_flags;	struct list_head *p;	int err;	PR_DEBUG( "create a socket, type: %d, protocol: %d\n", sock->type, protocol );	sock->state = SS_UNCONNECTED;	answer = NULL;	err = -ESOCKTNOSUPPORT;	rcu_read_lock();	list_for_each_rcu( p, &myinetsw[sock->type] ){		answer = list_entry( p, struct inet_protosw, list );		if( protocol == answer->protocol ){			if( protocol != IPPROTO_IP )				break;		}else{			if( IPPROTO_IP == protocol ){				protocol = answer->protocol;				break;			}			if( IPPROTO_IP == answer->protocol )				break;		}		err = -EPROTONOSUPPORT;		answer = NULL;	}	if( answer == NULL )		goto out_rcu_unlock;	else		PR_DEEP_DEBUG( "match a socket type in myinetsw, type: %d, protocol: %d\n", 							answer->type, answer->protocol );	err = -EPERM;	if( answer->capability > 0 && !capable(answer->capability) )		goto out_rcu_unlock;	sock->ops = answer->ops;	answer_prot = answer->prot;	answer_no_check = answer->no_check;	answer_flags = answer->flags;	rcu_read_unlock();	BUG_TRAP( answer_prot->slab != NULL );	err = -ENOBUFS;	sk = sk_alloc( myinet_family_ops.family, GFP_KERNEL, answer_prot, 1 );	if( sk == NULL ){		PR_ERR( "alloc a sock failed!\n" );		goto out;	}	err = 0;	sk->sk_no_check = answer_no_check;	if (INET_PROTOSW_REUSE & answer_flags)		sk->sk_reuse = 1;	inet = inet_sk(sk);	inet->is_icsk = INET_PROTOSW_ICSK & answer_flags;	if( SOCK_RAW == sock->type ){		inet->num = protocol;		if( IPPROTO_RAW == protocol )			inet->hdrincl = 1;	}	inet->id = 0;	sock_init_data(sock, sk);	sk->sk_destruct	   = myinet_sock_destruct;	sk->sk_family	   = myinet_family_ops.family;	sk->sk_protocol	   = protocol;	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;	inet->uc_ttl	= -1;	inet->mc_loop	= 1;	inet->mc_ttl	= 1;	inet->mc_index	= 0;	inet->mc_list	= NULL;	sk_refcnt_debug_inc(sk);	if( inet->num || sk->sk_protocol == IPPROTO_DUMMY ) {		inet->sport = htons(inet->num);		sk->sk_prot->hash(sk);	}	if (sk->sk_prot->init) {		err = sk->sk_prot->init(sk);		if (err)			sk_common_release(sk);	}	PR_DEBUG( "create the socket %d:%d finished, the ret: %d\n", sock->type, protocol, err );out:	return err;out_rcu_unlock:	rcu_read_unlock();	goto out;}static int myinet_autobind(struct sock *sk){	struct inet_sock *inet;	lock_sock(sk);	inet = inet_sk(sk);	if( !inet->num ){		if( sk->sk_prot->get_port(sk, 0) ){			release_sock(sk);			return -EAGAIN;		}		inet->sport = htons(inet->num);	}	release_sock(sk);	return 0;}int myinet_release( struct socket *sock ){	struct sock *sk = sock->sk;	PR_DEBUG( "release the sock: %p\n", sk );	if (sk) {		long timeout = 0;		if( sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING) )			timeout = sk->sk_lingertime;		sock->sk = NULL;		sk->sk_prot->close( sk, timeout );	}	return 0;}int myinet_sendmsg(struct kiocb *iocb, struct socket *sock, 				struct msghdr *msg, size_t size){	struct sock *sk = sock->sk;	if( !inet_sk(sk)->num && myinet_autobind(sk) )		return -EAGAIN;	return sk->sk_prot->sendmsg( iocb, sk, msg, size );}int mysock_common_recvmsg(struct kiocb *iocb, struct socket *sock,				struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	int addr_len = 0;	int err;	err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,				   flags & ~MSG_DONTWAIT, &addr_len);	if (err >= 0)		msg->msg_namelen = addr_len;	return err;}int myinet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	int err = 0;	switch (cmd) {		case SIOCGSTAMP:			//err = sock_get_timestamp(sk, (struct timeval __user *)arg);			break;		case SIOCADDRT:		case SIOCDELRT:		case SIOCRTMSG:			//err = ip_rt_ioctl(cmd, (void __user *)arg);			break;		case SIOCDARP:		case SIOCGARP:		case SIOCSARP:			err = myarp_ioctl(cmd, (void __user *)arg);			break;		case SIOCGIFADDR:		case SIOCSIFADDR:		case SIOCGIFBRDADDR:		case SIOCSIFBRDADDR:		case SIOCGIFNETMASK:		case SIOCSIFNETMASK:		case SIOCGIFDSTADDR:		case SIOCSIFDSTADDR:		case SIOCSIFPFLAGS:		case SIOCGIFPFLAGS:		case SIOCSIFFLAGS:			err = mydevinet_ioctl(cmd, (void __user *)arg);			break;		default:			err = -ENOIOCTLCMD;			if( sk->sk_prot->ioctl )				err = sk->sk_prot->ioctl(sk, cmd, arg);			if( err == -ENOIOCTLCMD )				err = mydev_ioctl( cmd, (void *)arg );			break;	}	return err;}struct packet_type myip_packet_type = {	.type = __constant_htons(ETH_P_IP),	.func = myip_rcv,};static int myinet_init(void){	struct list_head *r;	struct inet_protosw *q;	int rc = -EINVAL;	PR_DEBUG("loading the module myinet...\n");	rc = proto_register( &dummy_prot, 1 );	if( rc ){		PR_ERR( "register dummy protocol failed!\n");		goto out;	}	PR_DEEP_DEBUG( "Registered dummy protocol successed!\n" );	if( wrap_sock_register(&myinet_family_ops) != 0 )		goto unregister_dummy;	if( myinet_add_protocol( &dummy_protocol, IPPROTO_DUMMY ) < 0 )		PR_ERR("Cannot add DUMMY protocol\n");	PR_DEEP_DEBUG( "add dummy protocol successed!\n");	for( r = &myinetsw[0]; r < &myinetsw[SOCK_MAX]; ++r )		INIT_LIST_HEAD(r);	for( q = myinetsw_array; q < &myinetsw_array[INETSW_ARRAY_LEN]; ++q ){		PR_DEEP_DEBUG( "register protocol to myinetsw: type: %d, protocol: %d\n",						q->type, q->protocol );		myinet_register_protosw( q );	}	mydev_add_pack( &myip_packet_type );	PR_DEBUG("loading the module myinet finished.\n");	goto out;unregister_dummy:	proto_unregister( &dummy_prot );out:	return rc;}static void __exit myinet_exit(void){	mydev_remove_pack( &myip_packet_type );	proto_unregister( &dummy_prot );	sock_unregister( myinet_family_ops.family );	myinet_del_protocol( &dummy_protocol, IPPROTO_DUMMY );}module_init(myinet_init);module_exit(myinet_exit);MODULE_LICENSE("Dual BSD/GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -