MODULE_AUTHOR("Cast of dozens");
MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
MODULE_LICENSE("GPL");
/* The inetsw6 table contains everything that inet6_create needs to * build a new socket.
*/ staticstruct list_head inetsw6[SOCK_MAX]; static DEFINE_SPINLOCK(inetsw6_lock);
staticint inet6_create(struct net *net, struct socket *sock, int protocol, int kern)
{ struct inet_sock *inet; struct ipv6_pinfo *np; struct sock *sk; struct inet_protosw *answer; struct proto *answer_prot; unsignedchar answer_flags; int try_loading_module = 0; int err;
if (protocol < 0 || protocol >= IPPROTO_MAX) return -EINVAL;
/* Look for the requested type/protocol pair. */
lookup_protocol:
err = -ESOCKTNOSUPPORT;
rcu_read_lock();
list_for_each_entry_rcu(answer, &inetsw6[sock->type], list) {
err = 0; /* Check the non-wild match. */ if (protocol == answer->protocol) { if (protocol != IPPROTO_IP) break;
} else { /* Check for the two wild cases. */ if (IPPROTO_IP == protocol) {
protocol = answer->protocol; break;
} if (IPPROTO_IP == answer->protocol) break;
}
err = -EPROTONOSUPPORT;
}
if (err) { if (try_loading_module < 2) {
rcu_read_unlock(); /* * Be more specific, e.g. net-pf-10-proto-132-type-1 * (net-pf-PF_INET6-proto-IPPROTO_SCTP-type-SOCK_STREAM)
*/ if (++try_loading_module == 1)
request_module("net-pf-%d-proto-%d-type-%d",
PF_INET6, protocol, sock->type); /* * Fall back to generic, e.g. net-pf-10-proto-132 * (net-pf-PF_INET6-proto-IPPROTO_SCTP)
*/ else
request_module("net-pf-%d-proto-%d",
PF_INET6, protocol); goto lookup_protocol;
} else goto out_rcu_unlock;
}
if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc))
inet->pmtudisc = IP_PMTUDISC_DONT; else
inet->pmtudisc = IP_PMTUDISC_WANT;
if (inet->inet_num) { /* It assumes that any protocol which allows * the user to assign a number at socket * creation time automatically shares.
*/
inet->inet_sport = htons(inet->inet_num);
err = sk->sk_prot->hash(sk); if (err) goto out_sk_release;
} if (sk->sk_prot->init) {
err = sk->sk_prot->init(sk); if (err) goto out_sk_release;
}
rcu_read_lock(); if (__ipv6_addr_needs_scope_id(addr_type)) { if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) { /* Override any existing binding, if another one * is supplied by user.
*/
sk->sk_bound_dev_if = addr->sin6_scope_id;
}
/* Binding to link-local address requires an interface */ if (!sk->sk_bound_dev_if) {
err = -EINVAL; goto out_unlock;
}
}
if (sk->sk_bound_dev_if) {
dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); if (!dev) {
err = -ENODEV; goto out_unlock;
}
}
/* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent.
*/
v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { if (!ipv6_can_nonlocal_bind(net, inet) &&
!ipv6_chk_addr(net, &addr->sin6_addr,
dev, 0)) {
err = -EADDRNOTAVAIL; goto out_unlock;
}
}
rcu_read_unlock();
}
}
int inet6_bind_sk(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
u32 flags = BIND_WITH_LOCK; conststruct proto *prot; int err = 0;
/* IPV6_ADDRFORM can change sk->sk_prot under us. */
prot = READ_ONCE(sk->sk_prot); /* If the socket has its own bind function then use it. */ if (prot->bind) return prot->bind(sk, uaddr, addr_len);
if (addr_len < SIN6_LEN_RFC2133) return -EINVAL;
/* BPF prog is run before any checks are done so that if the prog * changes context in a wrong way it will be caught.
*/
err = BPF_CGROUP_RUN_PROG_INET_BIND_LOCK(sk, uaddr, &addr_len,
CGROUP_INET6_BIND, &flags); if (err) return err;
int inet6_register_protosw(struct inet_protosw *p)
{ struct list_head *lh; struct inet_protosw *answer; struct list_head *last_perm; int protocol = p->protocol; int ret;
spin_lock_bh(&inetsw6_lock);
ret = -EINVAL; if (p->type >= SOCK_MAX) goto out_illegal;
/* If we are trying to override a permanent protocol, bail. */
answer = NULL;
ret = -EPERM;
last_perm = &inetsw6[p->type];
list_for_each(lh, &inetsw6[p->type]) {
answer = list_entry(lh, struct inet_protosw, list);
/* Check only the non-wild match. */ if (INET_PROTOSW_PERMANENT & answer->flags) { if (protocol == answer->protocol) break;
last_perm = lh;
}
answer = NULL;
} if (answer) 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);
ret = 0;
out:
spin_unlock_bh(&inetsw6_lock); return ret;
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;
}
EXPORT_SYMBOL(inet6_register_protosw);
/* By default, rate limit error messages. * Except for pmtu discovery, it would break it. * proc_do_large_bitmap needs pointer to the bitmap.
*/
bitmap_set(net->ipv6.sysctl.icmpv6_ratemask, 0, ICMPV6_ERRMSG_MAX + 1);
bitmap_clear(net->ipv6.sysctl.icmpv6_ratemask, ICMPV6_PKT_TOOBIG, 1);
net->ipv6.sysctl.icmpv6_ratemask_ptr = net->ipv6.sysctl.icmpv6_ratemask;
/* Register the socket-side information for inet6_create. */ for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
INIT_LIST_HEAD(r);
raw_hashinfo_init(&raw_v6_hashinfo);
if (disable_ipv6_mod) {
pr_info("Loaded, but administratively disabled, reboot required to enable\n"); goto out;
}
err = proto_register(&tcpv6_prot, 1); if (err) goto out;
err = proto_register(&udpv6_prot, 1); if (err) goto out_unregister_tcp_proto;
err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto;
err = proto_register(&rawv6_prot, 1); if (err) goto out_unregister_udplite_proto;
err = proto_register(&pingv6_prot, 1); if (err) goto out_unregister_raw_proto;
/* We MUST register RAW sockets before we create the ICMP6, * IGMP6, or NDISC control sockets.
*/
err = rawv6_init(); if (err) goto out_unregister_ping_proto;
/* Register the family here so that the init calls below will * be able to create sockets. (?? is this dangerous ??)
*/
err = sock_register(&inet6_family_ops); if (err) goto out_sock_register_fail;
/* * ipngwg API draft makes clear that the correct semantics * for TCP and UDP is to consider one TCP and UDP instance * in a host available by both INET and INET6 APIs and * able to communicate via both network protocols.
*/
err = register_pernet_subsys(&inet6_net_ops); if (err) goto register_pernet_fail;
err = ip6_mr_init(); if (err) goto ipmr_fail;
err = icmpv6_init(); if (err) goto icmp_fail;
err = ndisc_init(); if (err) goto ndisc_fail;
err = igmp6_init(); if (err) goto igmp_fail;
err = ipv6_netfilter_init(); if (err) goto netfilter_fail; /* Create /proc/foo6 entries. */ #ifdef CONFIG_PROC_FS
err = -ENOMEM; if (raw6_proc_init()) goto proc_raw6_fail; if (udplite6_proc_init()) goto proc_udplite6_fail; if (ipv6_misc_proc_init()) goto proc_misc6_fail; if (if6_proc_init()) goto proc_if6_fail; #endif
err = ip6_route_init(); if (err) goto ip6_route_fail;
err = ndisc_late_init(); if (err) goto ndisc_late_fail;
err = ip6_flowlabel_init(); if (err) goto ip6_flowlabel_fail;
err = ipv6_anycast_init(); if (err) goto ipv6_anycast_fail;
err = addrconf_init(); if (err) goto addrconf_fail;
err = ipv6_frag_init(); if (err) goto ipv6_frag_fail;
/* Init v6 transport protocols. */
err = udpv6_init(); if (err) goto udpv6_fail;
err = udplitev6_init(); if (err) goto udplitev6_fail;
err = udpv6_offload_init(); if (err) goto udpv6_offload_fail;
err = tcpv6_init(); if (err) goto tcpv6_fail;
err = ipv6_packet_init(); if (err) goto ipv6_packet_fail;
err = pingv6_init(); if (err) goto pingv6_fail;
err = calipso_init(); if (err) goto calipso_fail;
err = seg6_init(); if (err) goto seg6_fail;
err = rpl_init(); if (err) goto rpl_fail;
err = ioam6_init(); if (err) goto ioam6_fail;
err = igmp6_late_init(); if (err) goto igmp6_late_err;
#ifdef CONFIG_SYSCTL
err = ipv6_sysctl_register(); if (err) goto sysctl_fail; #endif
/* ensure that ipv6 stubs are visible only after ipv6 is ready */
wmb();
ipv6_stub = &ipv6_stub_impl;
ipv6_bpf_stub = &ipv6_bpf_stub_impl;
out: return err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.