首先要了解一下Linux的系统调用: 系统调用就是用户空间应用程序和内核提供的服务之间的接口。服务是由linux内核提供的,无法直接调用。因此必须使用一个进程来跨越用户空间和内核之间的界限。这让我想起了android进程间通讯机制IBinder就是做这么个事情的。当然也有其他方式跨越用户空间与内核的,比如通过软中断来实现。 以dhcp创建socket为例: 从上面可以看出socket通过swi产生了软中断,r7保存中断号(eabi的一个规范)。Unistd.h中定义了各个中断号。(参考android-2.0\bionic\libc\arch-arm\syscalls\socket.s)内核代码版本2.6.28.6。 #define __NR_socket (__NR_SYSCALL_BASE+281) __NR_socket中断号对应的处理函数为: Sys_socket 这可以从arch\arm\kernel\call.s中找到: /* 280 */ CALL(sys_waitid) CALL(sys_socket) CALL(ABI(sys_bind, sys_oabi_bind)) CALL(ABI(sys_connect, sys_oabi_connect)) CALL(sys_listen)
Sys_socket在中断表中的位置与定义的中断号一致,这样当产生软中断时,直接通过中断号查找system_call_table就能关联相应的处理函数。(参考vector_swi软中断入口) system_call_table生成可以参考arch\arm\kernel\entry-common.s中代码: 。。。。。。。。。。 #define CALL(x) .long x 。。。。。。。。。 .type sys_call_table, #object ENTRY(sys_call_table) #include "calls.S" #undef ABI #undef OBSOLETE
Sys_socket实现可以参考(net\socket.c): SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)。 将宏SYSCALL_DEFINE3展开即可得到。
Socket创建与bind操作 了解了linux system call后再来看socket的创建就比较简单了,从上面可知,应用程序调用socket后最终通过软中断call sys_socket。Sys_socket 在net/socket.c中定义: SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) { 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
retval = sock_create(family, type, protocol, &sock); if (retval < 0) goto out;
retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); if (retval < 0) goto out_release; 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 }
int sock_create(int family, int type, int protocol, struct socket **res) { return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); }
static int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern) { 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 err = security_socket_create(family, type, protocol, kern); //检查应用是否有权限创建socket等 if (err) return err; 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 sock = sock_alloc(); if (!sock) { if (net_ratelimit()) printk(KERN_WARNING "socket: no more sockets\n"); return -ENFILE; /* Not exactly a match, but its the closest posix thing */ }
sock->type = type; 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 rcu_read_lock(); pf = rcu_dereference(net_families[family]); //获取net protocal family以PF_PACKET为例 err = -EAFNOSUPPORT; //packet_init调用sock_register(&packet_family_ops); if (!pf) //注册PF_PACKET socket协议类别。 goto out_release; 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 err = pf->create(net, sock, protocol); //调用packet_creat函数af_packet.c if (err < 0) goto out_module_put; 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 }
static int packet_create(struct net *net, struct socket *sock, int protocol) { 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 err = -ENOBUFS; sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto); if (sk == NULL) goto out;
sock->ops = &packet_ops; //比如SOCK_DGRAM if (sock->type == SOCK_PACKET) sock->ops = &packet_ops_spkt;
sock_init_data(sock, sk);
po = pkt_sk(sk); sk->sk_family = PF_PACKET; po->num = proto; //网络协议比如TCP_IP:0x8000 ARP:0x0806
sk->sk_destruct = packet_sock_destruct; sk_refcnt_debug_inc(sk);
/* * Attach a protocol block */
spin_lock_init(&po->bind_lock); mutex_init(&po->pg_vec_lock); po->prot_hook.func = packet_rcv; //添加接收处理函数,当底层通过neif_rx通知上层有数据时,最终会 //会调用此function if (sock->type == SOCK_PACKET) po->prot_hook.func = packet_rcv_spkt;
po->prot_hook.af_packet_priv = sk;
if (proto) { po->prot_hook.type = proto; dev_add_pack(&po->prot_hook); //dev_add_pack 看一下这个函数的说明就知道,他的作用 sock_hold(sk); //在网络协议栈中增加协议的处理函数。 po->running = 1; } 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 } |
联系客服