//inet模块初始化
//inet功能以模块的形式提供
//1.sock_register(inet_family_ops)向socket注册地址族,保存在net_families数组中,socket通过地址族查找对应的inet_family_ops
//2.struct inet_protosw 由l4使用,表示地址族(协议族)中某一具体协议的操作,保存在inetsw链表数组中,通过协议类型查找对应的协议操作
//3.struct net_protocol 由l3使用,表示l4协议的回调函数,l3通过l3报头中的协议字段,在inet_protos数组中查找对应l4回调函数。
static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protosw *q;
struct list_head *r;
int rc = -EINVAL;
//如果inet控制块的大小 > skb提供的控制块的大小
if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
goto out;
}
//tcp sock SLAB 缓存
rc = sk_alloc_slab(&tcp_prot, "tcp_sock");
if (rc) {
sk_alloc_slab_error(&tcp_prot);
goto out;
}
//udp sock SLAB 缓存
rc = sk_alloc_slab(&udp_prot, "udp_sock");
if (rc) {
sk_alloc_slab_error(&udp_prot);
goto out_tcp_free_slab;
}
//raw sock SLBA缓存
rc = sk_alloc_slab(&raw_prot, "raw_sock");
if (rc) {
sk_alloc_slab_error(&raw_prot);
goto out_udp_free_slab;
}
//向sock注册af_inet服务
(void)sock_register(&inet_family_ops);
//注册l4协议,l3接收到数据包时,通过协议字段,找到对应的上层协议的回调函数
//xxx_protocol用于向下提供服务
if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)//icmp
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)//udp
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)//tcp
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)//igmp
printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
#endif
//初始化inetsw数组,其中每一个元素为一个链表头
//inetsw用链表的形式组织af_inet地址族中的所有协议
//inetsw中的每一个链表头,代表一种套接字类型(type)
//链表中的一个元素,对应一个具体的协议(protocal)
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)//SOCK_MAX = 11
INIT_LIST_HEAD(r);
//inet默认提供的协议,静态编码在inetsw_array数组中,
//先通过inet_register_protosw,将其从inetsw_array添加到inetsw中
//注册af_inet下不同套接字类型,提供的各种协议,用于向上提供服务
for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
inet_register_protosw(q);
//arp子系统初始化
arp_init();
//ip子系统初始化
ip_init();
//tcp子系统初始化
tcp_v4_init(&inet_family_ops);
tcp_init();
//icmp子系统初始化
icmp_init(&inet_family_ops);
//ip多播初始化
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
//snmp的mibs初始化
if(init_ipv4_mibs())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ;
//ip在proc中的初始化
ipv4_proc_init();
//ip分片/合并子系统初始化
ipfrag_init();
rc = 0;
out:
return rc;
out_tcp_free_slab:
sk_free_slab(&tcp_prot);
out_udp_free_slab:
sk_free_slab(&udp_prot);
goto out;
}
//已模块形式提供ip功能
module_init(inet_init);
//注册协议族or地址族
//inet为af_inet
2.1 int sock_register(struct net_proto_family *ops)
{
int err;
//族编号大于最大的族号(32目前)
if (ops->family >= NPROTO) {
printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);
return -ENOBUFS;
}
net_family_write_lock();
err = -EEXIST;
//将协议族注册到net_families数组中
if (net_families[ops->family] == NULL) {
net_families[ops->family]=ops;
err = 0;
}
net_family_write_unlock();
printk(KERN_INFO "NET: Registered protocol family %d\n",
ops->family);
return err;
}
2.2
//linux中,协议族等于地址族
#define PF_UNSPEC AF_UNSPEC
#define PF_UNIX AF_UNIX
#define PF_LOCAL AF_LOCAL
#define PF_INET AF_INET
#define PF_AX25 AF_AX25
#define PF_IPX AF_IPX
#define PF_APPLETALK AF_APPLETALK
#define PF_NETROM AF_NETROM
#define PF_BRIDGE AF_BRIDGE
#define PF_ATMPVC AF_ATMPVC
#define PF_X25 AF_X25
#define PF_INET6 AF_INET6
#define PF_ROSE AF_ROSE
#define PF_DECnet AF_DECnet
#define PF_NETBEUI AF_NETBEUI
#define PF_SECURITY AF_SECURITY
#define PF_KEY AF_KEY
#define PF_NETLINK AF_NETLINK
#define PF_ROUTE AF_ROUTE
#define PF_PACKET AF_PACKET
#define PF_ASH AF_ASH
#define PF_ECONET AF_ECONET
#define PF_ATMSVC AF_ATMSVC
#define PF_SNA AF_SNA
#define PF_IRDA AF_IRDA
#define PF_PPPOX AF_PPPOX
#define PF_WANPIPE AF_WANPIPE
#define PF_LLC AF_LLC
#define PF_BLUETOOTH AF_BLUETOOTH
#define PF_MAX AF_MAX
//注册inet协议族特定协议的数据处理handler
//在下层接收到数据时,根据协议号,查找指定的处理handler
//protocol可取值为;
enum {
IPPROTO_IP = 0, /* Dummy protocol for TCP */
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
IPPROTO_TCP = 6, /* Transmission Control Protocol */
IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
IPPROTO_PUP = 12, /* PUP protocol */
IPPROTO_UDP = 17, /* User Datagram Protocol */
IPPROTO_IDP = 22, /* XNS IDP protocol */
IPPROTO_RSVP = 46, /* RSVP protocol */
IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
IPPROTO_AH = 51, /* Authentication Header protocol */
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
IPPROTO_COMP = 108, /* Compression Header protocol */
IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
IPPROTO_RAW = 255, /* Raw IP packets */
IPPROTO_MAX
};
3.1 int inet_add_protocol(struct net_protocol *prot, unsigned char protocol)
{
int hash, ret;
//哈希协议号
hash = protocol & (MAX_INET_PROTOS - 1);
spin_lock_bh(&inet_proto_lock);
//协议号唯一
if (inet_protos[hash]) {
ret = -1;
} else {
//将协议处理handler保存到inet_protos数组中
inet_protos[hash] = prot;
ret = 0;
}
spin_unlock_bh(&inet_proto_lock);
return ret;
}
//注册特定inet协议与socket interface交互的控制块
4.1 void inet_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(&inetsw_lock);
//套接字类型 不应该超过 系统支持的最大类型号(socket type)
if (p->type >= SOCK_MAX)
goto out_illegal;
answer = NULL;
//对应套接字类型在inetsw中的列表头
last_perm = &inetsw[p->type];
//遍历该套接字类型的所有协议控制块
list_for_each(lh, &inetsw[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(&inetsw_lock);
//同步
synchronize_net();
return;
out_permanent:
printk(KERN_ERR "Attempt to override permanent protocol %d.\n",
protocol);
goto out;
out_illegal:
printk(KERN_ERR
"Ignoring attempt to register invalid socket type %d.\n",
p->type);
goto out;
}