📄 af_inet.c
字号:
goto out_permanent; /* Add the new entry after the last permanent entry if any, so that * the new entry does not override a permanent entry when matched with * a wild-card protocol. But it is allowed to override any existing * non-permanent entry. This means that when we remove this entry, the * system automatically returns to the old behavior. */ 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;}void inet_unregister_protosw(struct inet_protosw *p){ if (INET_PROTOSW_PERMANENT & p->flags) { printk(KERN_ERR "Attempt to unregister permanent protocol %d.\n", p->protocol); } else { spin_lock_bh(&inetsw_lock); list_del_rcu(&p->list); spin_unlock_bh(&inetsw_lock); synchronize_net(); }}/* * Shall we try to damage output packets if routing dev changes? */int sysctl_ip_dynaddr __read_mostly;static int inet_sk_reselect_saddr(struct sock *sk){ struct inet_sock *inet = inet_sk(sk); int err; struct rtable *rt; __be32 old_saddr = inet->saddr; __be32 new_saddr; __be32 daddr = inet->daddr; if (inet->opt && inet->opt->srr) daddr = inet->opt->faddr; /* Query new route. */ err = ip_route_connect(&rt, daddr, 0, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, sk->sk_protocol, inet->sport, inet->dport, sk, 0); if (err) return err; sk_setup_caps(sk, &rt->u.dst); new_saddr = rt->rt_src; if (new_saddr == old_saddr) return 0; if (sysctl_ip_dynaddr > 1) { printk(KERN_INFO "%s(): shifting inet->" "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n", __FUNCTION__, NIPQUAD(old_saddr), NIPQUAD(new_saddr)); } inet->saddr = inet->rcv_saddr = new_saddr; /* * XXX The only one ugly spot where we need to * XXX really change the sockets identity after * XXX it has entered the hashes. -DaveM * * Besides that, it does not check for connection * uniqueness. Wait for troubles. */ __sk_prot_rehash(sk); return 0;}int inet_sk_rebuild_header(struct sock *sk){ struct inet_sock *inet = inet_sk(sk); struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); __be32 daddr; int err; /* Route is OK, nothing to do. */ if (rt) return 0; /* Reroute. */ daddr = inet->daddr; if (inet->opt && inet->opt->srr) daddr = inet->opt->faddr;{ struct flowi fl = { .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, .tos = RT_CONN_FLAGS(sk), }, }, .proto = sk->sk_protocol, .uli_u = { .ports = { .sport = inet->sport, .dport = inet->dport, }, }, }; security_sk_classify_flow(sk, &fl); err = ip_route_output_flow(&rt, &fl, sk, 0);} if (!err) sk_setup_caps(sk, &rt->u.dst); else { /* Routing failed... */ sk->sk_route_caps = 0; /* * Other protocols have to map its equivalent state to TCP_SYN_SENT. * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme */ if (!sysctl_ip_dynaddr || sk->sk_state != TCP_SYN_SENT || (sk->sk_userlocks & SOCK_BINDADDR_LOCK) || (err = inet_sk_reselect_saddr(sk)) != 0) sk->sk_err_soft = -err; } return err;}EXPORT_SYMBOL(inet_sk_rebuild_header);static int inet_gso_send_check(struct sk_buff *skb){ struct iphdr *iph; struct net_protocol *ops; int proto; int ihl; int err = -EINVAL; if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) goto out; iph = skb->nh.iph; ihl = iph->ihl * 4; if (ihl < sizeof(*iph)) goto out; if (unlikely(!pskb_may_pull(skb, ihl))) goto out; skb->h.raw = __skb_pull(skb, ihl); iph = skb->nh.iph; proto = iph->protocol & (MAX_INET_PROTOS - 1); err = -EPROTONOSUPPORT; rcu_read_lock(); ops = rcu_dereference(inet_protos[proto]); if (likely(ops && ops->gso_send_check)) err = ops->gso_send_check(skb); rcu_read_unlock();out: return err;}static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features){ struct sk_buff *segs = ERR_PTR(-EINVAL); struct iphdr *iph; struct net_protocol *ops; int proto; int ihl; int id; if (unlikely(skb_shinfo(skb)->gso_type & ~(SKB_GSO_TCPV4 | SKB_GSO_UDP | SKB_GSO_DODGY | SKB_GSO_TCP_ECN | 0))) goto out; if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) goto out; iph = skb->nh.iph; ihl = iph->ihl * 4; if (ihl < sizeof(*iph)) goto out; if (unlikely(!pskb_may_pull(skb, ihl))) goto out; skb->h.raw = __skb_pull(skb, ihl); iph = skb->nh.iph; id = ntohs(iph->id); proto = iph->protocol & (MAX_INET_PROTOS - 1); segs = ERR_PTR(-EPROTONOSUPPORT); rcu_read_lock(); ops = rcu_dereference(inet_protos[proto]); if (likely(ops && ops->gso_segment)) segs = ops->gso_segment(skb, features); rcu_read_unlock(); if (!segs || unlikely(IS_ERR(segs))) goto out; skb = segs; do { iph = skb->nh.iph; iph->id = htons(id++); iph->tot_len = htons(skb->len - skb->mac_len); iph->check = 0; iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); } while ((skb = skb->next));out: return segs;}#ifdef CONFIG_IP_MULTICASTstatic struct net_protocol igmp_protocol = { .handler = igmp_rcv,};#endifstatic struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, .gso_send_check = tcp_v4_gso_send_check, .gso_segment = tcp_tso_segment, .no_policy = 1,};static struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, .no_policy = 1,};static struct net_protocol icmp_protocol = { .handler = icmp_rcv,};static int __init init_ipv4_mibs(void){ net_statistics[0] = alloc_percpu(struct linux_mib); net_statistics[1] = alloc_percpu(struct linux_mib); ip_statistics[0] = alloc_percpu(struct ipstats_mib); ip_statistics[1] = alloc_percpu(struct ipstats_mib); icmp_statistics[0] = alloc_percpu(struct icmp_mib); icmp_statistics[1] = alloc_percpu(struct icmp_mib); tcp_statistics[0] = alloc_percpu(struct tcp_mib); tcp_statistics[1] = alloc_percpu(struct tcp_mib); udp_statistics[0] = alloc_percpu(struct udp_mib); udp_statistics[1] = alloc_percpu(struct udp_mib); udplite_statistics[0] = alloc_percpu(struct udp_mib); udplite_statistics[1] = alloc_percpu(struct udp_mib); if (! (net_statistics[0] && net_statistics[1] && ip_statistics[0] && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] && udp_statistics[0] && udp_statistics[1] && udplite_statistics[0] && udplite_statistics[1] ) ) return -ENOMEM; (void) tcp_mib_init(); return 0;}static int ipv4_proc_init(void);/* * IP protocol layer initialiser */static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv, .gso_send_check = inet_gso_send_check, .gso_segment = inet_gso_segment,};static int __init inet_init(void){ struct sk_buff *dummy_skb; struct inet_protosw *q; struct list_head *r; int rc = -EINVAL; BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)); rc = proto_register(&tcp_prot, 1); if (rc) goto out; rc = proto_register(&udp_prot, 1); if (rc) goto out_unregister_tcp_proto; rc = proto_register(&raw_prot, 1); if (rc) goto out_unregister_udp_proto; /* * Tell SOCKET that we are alive... */ rc = sock_register(&inet_family_ops); if (rc) { BUG(); } /* * Add all the base protocols. */ if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n"); if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n"); if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");#ifdef CONFIG_IP_MULTICAST if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");#endif /* Register the socket-side information for inet_create. */ for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r) INIT_LIST_HEAD(r); for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q) inet_register_protosw(q); /* * Set the ARP module up */ arp_init(); /* * Set the IP module up */ ip_init(); tcp_v4_init(&inet_family_ops); /* Setup TCP slab cache for open requests. */ tcp_init(); /* Add UDP-Lite (RFC 3828) */ udplite4_register(); /* * Set the ICMP layer up */ icmp_init(&inet_family_ops); /* * Initialise the multicast router */#if defined(CONFIG_IP_MROUTE) ip_mr_init();#endif /* * Initialise per-cpu ipv4 mibs */ if(init_ipv4_mibs()) printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; ipv4_proc_init(); ipfrag_init(); dev_add_pack(&ip_packet_type); rc = 0;out: return rc;out_unregister_udp_proto: proto_unregister(&udp_prot);out_unregister_tcp_proto: proto_unregister(&tcp_prot); goto out;}fs_initcall(inet_init);/* ------------------------------------------------------------------------ */#ifdef CONFIG_PROC_FSstatic int __init ipv4_proc_init(void){ int rc = 0; if (raw_proc_init()) goto out_raw; if (tcp4_proc_init()) goto out_tcp; if (udp4_proc_init()) goto out_udp; if (fib_proc_init()) goto out_fib; if (ip_misc_proc_init()) goto out_misc;out: return rc;out_misc: fib_proc_exit();out_fib: udp4_proc_exit();out_udp: tcp4_proc_exit();out_tcp: raw_proc_exit();out_raw: rc = -ENOMEM; goto out;}#else /* CONFIG_PROC_FS */static int __init ipv4_proc_init(void){ return 0;}#endif /* CONFIG_PROC_FS */MODULE_ALIAS_NETPROTO(PF_INET);EXPORT_SYMBOL(inet_accept);EXPORT_SYMBOL(inet_bind);EXPORT_SYMBOL(inet_dgram_connect);EXPORT_SYMBOL(inet_dgram_ops);EXPORT_SYMBOL(inet_getname);EXPORT_SYMBOL(inet_ioctl);EXPORT_SYMBOL(inet_listen);EXPORT_SYMBOL(inet_register_protosw);EXPORT_SYMBOL(inet_release);EXPORT_SYMBOL(inet_sendmsg);EXPORT_SYMBOL(inet_shutdown);EXPORT_SYMBOL(inet_sock_destruct);EXPORT_SYMBOL(inet_stream_connect);EXPORT_SYMBOL(inet_stream_ops);EXPORT_SYMBOL(inet_unregister_protosw);EXPORT_SYMBOL(net_statistics);EXPORT_SYMBOL(sysctl_ip_nonlocal_bind);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -