📄 af_inet.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 + -