//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;
}