📄 ipv6.c
字号:
{ return ipv6_addr_any(&addr->v6.sin6_addr);}/* Should this be available for binding? */static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp){ int type; struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) return 1; if (type == IPV6_ADDR_MAPPED) { if (sp && !sp->v4mapped) return 0; if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0; sctp_v6_map_v4(addr); return sctp_get_af_specific(AF_INET)->available(addr, sp); } if (!(type & IPV6_ADDR_UNICAST)) return 0; return ipv6_chk_addr(&init_net, in6, NULL, 0);}/* This function checks if the address is a valid address to be used for * SCTP. * * Output: * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp, const struct sk_buff *skb){ int ret = ipv6_addr_type(&addr->v6.sin6_addr); /* Support v4-mapped-v6 address. */ if (ret == IPV6_ADDR_MAPPED) { /* Note: This routine is used in input, so v4-mapped-v6 * are disallowed here when there is no sctp_sock. */ if (!sp || !sp->v4mapped) return 0; if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0; sctp_v6_map_v4(addr); return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb); } /* Is this a non-unicast address */ if (!(ret & IPV6_ADDR_UNICAST)) return 0; return 1;}/* What is the scope of 'addr'? */static sctp_scope_t sctp_v6_scope(union sctp_addr *addr){ int v6scope; sctp_scope_t retval; /* The IPv6 scope is really a set of bit fields. * See IFA_* in <net/if_inet6.h>. Map to a generic SCTP scope. */ v6scope = ipv6_addr_scope(&addr->v6.sin6_addr); switch (v6scope) { case IFA_HOST: retval = SCTP_SCOPE_LOOPBACK; break; case IFA_LINK: retval = SCTP_SCOPE_LINK; break; case IFA_SITE: retval = SCTP_SCOPE_PRIVATE; break; default: retval = SCTP_SCOPE_GLOBAL; break; } return retval;}/* Create and initialize a new sk for the socket to be returned by accept(). */static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct sctp_association *asoc){ struct inet_sock *inet = inet_sk(sk); struct sock *newsk; struct inet_sock *newinet; struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot); if (!newsk) goto out; sock_init_data(NULL, newsk); newsk->sk_type = SOCK_STREAM; newsk->sk_prot = sk->sk_prot; newsk->sk_no_check = sk->sk_no_check; newsk->sk_reuse = sk->sk_reuse; newsk->sk_destruct = inet_sock_destruct; newsk->sk_family = PF_INET6; newsk->sk_protocol = IPPROTO_SCTP; newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; newsk->sk_shutdown = sk->sk_shutdown; sock_reset_flag(sk, SOCK_ZAPPED); newsctp6sk = (struct sctp6_sock *)newsk; inet_sk(newsk)->pinet6 = &newsctp6sk->inet6; sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped; newinet = inet_sk(newsk); newnp = inet6_sk(newsk); memcpy(newnp, np, sizeof(struct ipv6_pinfo)); /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() * and getpeername(). */ newinet->sport = inet->sport; newnp->saddr = np->saddr; newnp->rcv_saddr = np->rcv_saddr; newinet->dport = htons(asoc->peer.port); sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk); /* Init the ipv4 part of the socket since we can have sockets * using v6 API for ipv4. */ newinet->uc_ttl = -1; newinet->mc_loop = 1; newinet->mc_ttl = 1; newinet->mc_index = 0; newinet->mc_list = NULL; if (ipv4_config.no_pmtu_disc) newinet->pmtudisc = IP_PMTUDISC_DONT; else newinet->pmtudisc = IP_PMTUDISC_WANT; sk_refcnt_debug_inc(newsk); if (newsk->sk_prot->init(newsk)) { sk_common_release(newsk); newsk = NULL; }out: return newsk;}/* Map v4 address to mapped v6 address */static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr){ if (sp->v4mapped && AF_INET == addr->sa.sa_family) sctp_v4_map_v6(addr);}/* Where did this skb come from? */static int sctp_v6_skb_iif(const struct sk_buff *skb){ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb; return opt->iif;}/* Was this packet marked by Explicit Congestion Notification? */static int sctp_v6_is_ce(const struct sk_buff *skb){ return *((__u32 *)(ipv6_hdr(skb))) & htonl(1 << 20);}/* Dump the v6 addr to the seq file. */static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr){ seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));}/* Initialize a PF_INET6 socket msg_name. */static void sctp_inet6_msgname(char *msgname, int *addr_len){ struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)msgname; sin6->sin6_family = AF_INET6; sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = 0; /*FIXME */ *addr_len = sizeof(struct sockaddr_in6);}/* Initialize a PF_INET msgname from a ulpevent. */static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addrlen){ struct sockaddr_in6 *sin6, *sin6from; if (msgname) { union sctp_addr *addr; struct sctp_association *asoc; asoc = event->asoc; sctp_inet6_msgname(msgname, addrlen); sin6 = (struct sockaddr_in6 *)msgname; sin6->sin6_port = htons(asoc->peer.port); addr = &asoc->peer.primary_addr; /* Note: If we go to a common v6 format, this code * will change. */ /* Map ipv4 address into v4-mapped-on-v6 address. */ if (sctp_sk(asoc->base.sk)->v4mapped && AF_INET == addr->sa.sa_family) { sctp_v4_map_v6((union sctp_addr *)sin6); sin6->sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; return; } sin6from = &asoc->peer.primary_addr.v6; ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id = sin6from->sin6_scope_id; }}/* Initialize a msg_name from an inbound skb. */static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len){ struct sctphdr *sh; struct sockaddr_in6 *sin6; if (msgname) { sctp_inet6_msgname(msgname, addr_len); sin6 = (struct sockaddr_in6 *)msgname; sh = sctp_hdr(skb); sin6->sin6_port = sh->source; /* Map ipv4 address into v4-mapped-on-v6 address. */ if (sctp_sk(skb->sk)->v4mapped && ip_hdr(skb)->version == 4) { sctp_v4_map_v6((union sctp_addr *)sin6); sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr; return; } /* Otherwise, just copy the v6 address. */ ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { struct sctp_ulpevent *ev = sctp_skb2event(skb); sin6->sin6_scope_id = ev->iif; } }}/* Do we support this AF? */static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp){ switch (family) { case AF_INET6: return 1; /* v4-mapped-v6 addresses */ case AF_INET: if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped) return 1; default: return 0; }}/* Address matching with wildcards allowed. This extra level * of indirection lets us choose whether a PF_INET6 should * disallow any v4 addresses if we so choose. */static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2, struct sctp_sock *opt){ struct sctp_af *af1, *af2; af1 = sctp_get_af_specific(addr1->sa.sa_family); af2 = sctp_get_af_specific(addr2->sa.sa_family); if (!af1 || !af2) return 0; /* Today, wildcard AF_INET/AF_INET6. */ if (sctp_is_any(addr1) || sctp_is_any(addr2)) return 1; if (addr1->sa.sa_family != addr2->sa.sa_family) return 0; return af1->cmp_addr(addr1, addr2);}/* Verify that the provided sockaddr looks bindable. Common verification, * has already been taken care of. */static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr){ struct sctp_af *af; /* ASSERT: address family has already been verified. */ if (addr->sa.sa_family != AF_INET6) af = sctp_get_af_specific(addr->sa.sa_family); else { int type = ipv6_addr_type(&addr->v6.sin6_addr); struct net_device *dev; if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; if (!ipv6_chk_addr(&init_net, &addr->v6.sin6_addr, dev, 0)) { dev_put(dev); return 0; } dev_put(dev); } af = opt->pf->af; } return af->available(addr, opt);}/* Verify that the provided sockaddr looks sendable. Common verification, * has already been taken care of. */static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr){ struct sctp_af *af = NULL; /* ASSERT: address family has already been verified. */ if (addr->sa.sa_family != AF_INET6) af = sctp_get_af_specific(addr->sa.sa_family); else { int type = ipv6_addr_type(&addr->v6.sin6_addr); struct net_device *dev; if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; dev_put(dev); } af = opt->pf->af; } return af != NULL;}/* Fill in Supported Address Type information for INIT and INIT-ACK * chunks. Note: In the future, we may want to look at sock options * to determine whether a PF_INET6 socket really wants to have IPV4 * addresses. * Returns number of addresses supported. */static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, __be16 *types){ types[0] = SCTP_PARAM_IPV4_ADDRESS; types[1] = SCTP_PARAM_IPV6_ADDRESS; return 2;}static const struct proto_ops inet6_seqpacket_ops = { .family = PF_INET6, .owner = THIS_MODULE, .release = inet6_release, .bind = inet6_bind, .connect = inet_dgram_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, .getname = inet6_getname, .poll = sctp_poll, .ioctl = inet6_ioctl, .listen = sctp_inet_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap,#ifdef CONFIG_COMPAT .compat_setsockopt = compat_sock_common_setsockopt, .compat_getsockopt = compat_sock_common_getsockopt,#endif};static struct inet_protosw sctpv6_seqpacket_protosw = { .type = SOCK_SEQPACKET, .protocol = IPPROTO_SCTP, .prot = &sctpv6_prot, .ops = &inet6_seqpacket_ops, .capability = -1, .no_check = 0, .flags = SCTP_PROTOSW_FLAG};static struct inet_protosw sctpv6_stream_protosw = { .type = SOCK_STREAM, .protocol = IPPROTO_SCTP, .prot = &sctpv6_prot, .ops = &inet6_seqpacket_ops, .capability = -1, .no_check = 0, .flags = SCTP_PROTOSW_FLAG,};static int sctp6_rcv(struct sk_buff *skb){ return sctp_rcv(skb) ? -1 : 0;}static struct inet6_protocol sctpv6_protocol = { .handler = sctp6_rcv, .err_handler = sctp_v6_err, .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,};static struct sctp_af sctp_af_inet6 = { .sa_family = AF_INET6, .sctp_xmit = sctp_v6_xmit, .setsockopt = ipv6_setsockopt, .getsockopt = ipv6_getsockopt, .get_dst = sctp_v6_get_dst, .get_saddr = sctp_v6_get_saddr, .copy_addrlist = sctp_v6_copy_addrlist, .from_skb = sctp_v6_from_skb, .from_sk = sctp_v6_from_sk, .to_sk_saddr = sctp_v6_to_sk_saddr, .to_sk_daddr = sctp_v6_to_sk_daddr, .from_addr_param = sctp_v6_from_addr_param, .to_addr_param = sctp_v6_to_addr_param, .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, .inaddr_any = sctp_v6_inaddr_any, .is_any = sctp_v6_is_any, .available = sctp_v6_available, .skb_iif = sctp_v6_skb_iif, .is_ce = sctp_v6_is_ce, .seq_dump_addr = sctp_v6_seq_dump_addr, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6),#ifdef CONFIG_COMPAT .compat_setsockopt = compat_ipv6_setsockopt, .compat_getsockopt = compat_ipv6_getsockopt,#endif};static struct sctp_pf sctp_pf_inet6 = { .event_msgname = sctp_inet6_event_msgname, .skb_msgname = sctp_inet6_skb_msgname, .af_supported = sctp_inet6_af_supported, .cmp_addr = sctp_inet6_cmp_addr, .bind_verify = sctp_inet6_bind_verify, .send_verify = sctp_inet6_send_verify, .supported_addrs = sctp_inet6_supported_addrs, .create_accept_sk = sctp_v6_create_accept_sk, .addr_v4map = sctp_v6_addr_v4map, .af = &sctp_af_inet6,};/* Initialize IPv6 support and register with socket layer. */void sctp_v6_pf_init(void){ /* Register the SCTP specific PF_INET6 functions. */ sctp_register_pf(&sctp_pf_inet6, PF_INET6); /* Register the SCTP specific AF_INET6 functions. */ sctp_register_af(&sctp_af_inet6);}void sctp_v6_pf_exit(void){ list_del(&sctp_af_inet6.list);}/* Initialize IPv6 support and register with socket layer. */int sctp_v6_protosw_init(void){ int rc; rc = proto_register(&sctpv6_prot, 1); if (rc) return rc; /* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */ inet6_register_protosw(&sctpv6_seqpacket_protosw); inet6_register_protosw(&sctpv6_stream_protosw); return 0;}void sctp_v6_protosw_exit(void){ inet6_unregister_protosw(&sctpv6_seqpacket_protosw); inet6_unregister_protosw(&sctpv6_stream_protosw); proto_unregister(&sctpv6_prot);}/* Register with inet6 layer. */int sctp_v6_add_protocol(void){ /* Register notifier for inet6 address additions/deletions. */ register_inet6addr_notifier(&sctp_inet6addr_notifier); if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0) return -EAGAIN; return 0;}/* Unregister with inet6 layer. */void sctp_v6_del_protocol(void){ inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP); unregister_inet6addr_notifier(&sctp_inet6addr_notifier);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -