From 51e4e0fd047e331a7778b7959c31fe6881304ec8 Mon Sep 17 00:00:00 2001 From: duxbbo Date: Mon, 25 Jul 2022 07:04:58 +0000 Subject: [PATCH] add uapi Signed-off-by: duxbbo --- code/linux/include/uapi/linux/newip_route.h | 30 ++ code/linux/include/uapi/linux/nip.h | 47 +++ code/linux/include/uapi/linux/nip_icmp.h | 26 ++ code/linux/net/newip/Kconfig | 16 + code/linux/net/newip/Makefile | 13 + code/linux/net/newip/icmp.c | 68 +++ code/linux/net/newip/ninet_connection_sock.c | 102 +++++ code/linux/net/newip/ninet_hashtables.c | 417 +++++++++++++++++++ 8 files changed, 719 insertions(+) create mode 100644 code/linux/include/uapi/linux/newip_route.h create mode 100644 code/linux/include/uapi/linux/nip.h create mode 100644 code/linux/include/uapi/linux/nip_icmp.h create mode 100644 code/linux/net/newip/Kconfig create mode 100644 code/linux/net/newip/Makefile create mode 100644 code/linux/net/newip/icmp.c create mode 100644 code/linux/net/newip/ninet_connection_sock.c create mode 100644 code/linux/net/newip/ninet_hashtables.c diff --git a/code/linux/include/uapi/linux/newip_route.h b/code/linux/include/uapi/linux/newip_route.h new file mode 100644 index 0000000..8b8e70e --- /dev/null +++ b/code/linux/include/uapi/linux/newip_route.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * Linux NewIP INET implementation + * + * Based on include/uapi/linux/ipv6_route.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _UAPI_LINUX_NEWIP_ROUTE_H +#define _UAPI_LINUX_NEWIP_ROUTE_H + +#include + +struct nip_rtmsg { + struct nip_addr rtmsg_dst; + struct nip_addr rtmsg_src; + struct nip_addr rtmsg_gateway; + char dev_name[10]; + unsigned int rtmsg_type; + int rtmsg_ifindex; + unsigned int rtmsg_metric; + unsigned long rtmsg_info; + unsigned int rtmsg_flags; +}; +#endif /* _UAPI_LINUX_NEWIP_ROUTE_H */ diff --git a/code/linux/include/uapi/linux/nip.h b/code/linux/include/uapi/linux/nip.h new file mode 100644 index 0000000..465b229 --- /dev/null +++ b/code/linux/include/uapi/linux/nip.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * Based on include/uapi/linux/ipv6.h + * Based on include/uapi/linux/in6.h + */ +#ifndef _UAPI_NEWIP_H +#define _UAPI_NEWIP_H + +#include +#include +#include +#include +#include + +struct nip_ifreq { + struct nip_addr ifrn_addr; + int ifrn_ifindex; +}; + +/* The following structure must be larger than V4. System calls use V4. + * If the definition is smaller than V4, the read process will have memory overruns + * v4: include\linux\socket.h --> sockaddr (16Byte) + */ +#define POD_SOCKADDR_SIZE 3 +struct sockaddr_nin { + unsigned short sin_family; /* [2Byte] AF_NINET */ + unsigned short sin_port; /* [2Byte] Transport layer port, big-endian */ + struct nip_addr sin_addr; /* [9Byte] NIP address */ + + unsigned char sin_zero[POD_SOCKADDR_SIZE]; /* [3Byte] Byte alignment */ +}; + +struct nip_devreq { + char nip_ifr_name[IFNAMSIZ]; /* if name, e.g. "eth0", "wlan0" */ + + union { + struct sockaddr_nin addr; + short flags; + } devreq; +}; + +#define nip_dev_addr devreq.addr /* nip address */ +#define nip_dev_flags devreq.flags /* net device flags */ + +#endif /*_UAPI_NEWIP_H*/ diff --git a/code/linux/include/uapi/linux/nip_icmp.h b/code/linux/include/uapi/linux/nip_icmp.h new file mode 100644 index 0000000..7970fe1 --- /dev/null +++ b/code/linux/include/uapi/linux/nip_icmp.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the NewIP ICMP protocol. + * + * Based on include/uapi/linux/icmp.h + */ +#ifndef _UAPI_LINUX_NIP_ICMP_H +#define _UAPI_LINUX_NIP_ICMP_H + +#include +#include + +struct nip_icmp_hdr { + __u8 nip_icmp_type; + __u8 nip_icmp_code; + __sum16 nip_icmp_cksum; +}; + +#endif diff --git a/code/linux/net/newip/Kconfig b/code/linux/net/newip/Kconfig new file mode 100644 index 0000000..85b1982 --- /dev/null +++ b/code/linux/net/newip/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (c) 2022 Huawei Device Co., Ltd. +# +# NewIP configuration +# + +# NewIP as module will cause a CRASH if you try to unload it +menuconfig NEWIP + tristate "The NewIP protocol" + default y + help + Support for NewIP. + + To compile this protocol support as a module, choose M here: the + module will be called NewIP. diff --git a/code/linux/net/newip/Makefile b/code/linux/net/newip/Makefile new file mode 100644 index 0000000..c97368e --- /dev/null +++ b/code/linux/net/newip/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2022 Huawei Device Co., Ltd. +# +# Makefile for the Linux newip layer +# + +obj-$(CONFIG_NEWIP) += newip.o + + +newip-objs := nip_addr.o nip_hdr_encap.o nip_hdr_decap.o nip_checksum.o af_ninet.o nip_input.o udp.o protocol.o nip_output.o datagram.o nip_addrconf.o nip_addrconf_core.o route.o nip_fib.o nip_fib_rules.o nndisc.o icmp.o tcp_nip_parameter.o +newip-objs += tcp_nip.o ninet_connection_sock.o ninet_hashtables.o tcp_nip_output.o tcp_nip_input.o tcp_nip_timer.o nip_sockglue.o +EXTRA_CFLAGS := -I$(src)/include diff --git a/code/linux/net/newip/icmp.c b/code/linux/net/newip/icmp.c new file mode 100644 index 0000000..11c3ff7 --- /dev/null +++ b/code/linux/net/newip/icmp.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * Internet Control Message Protocol (NewIP ICMP) + * Linux NewIP INET implementation + * + * Based on net/ipv6/icmp.c + * Based on net/ipv4/af_inet.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nip_hdr.h" + +int nip_icmp_rcv(struct sk_buff *skb) +{ + int ret = 0; + struct nip_icmp_hdr *hdr = nip_icmp_header(skb); + u8 type = hdr->nip_icmp_type; + + DEBUG("rcv newip icmp packet. type = %u\n", type); + switch (type) { + case NIP_ARP_NS: + case NIP_ARP_NA: + ret = nndisc_rcv(skb); + break; + default: + DEBUG("nip icmp packet type error\n"); + } + return ret; +} + +static void nip_icmp_err(struct sk_buff *skb, + struct ninet_skb_parm *opt, + u8 type, uint8_t code, + int offset, __be32 info) +{ +} + +static const struct ninet_protocol nip_icmp_protocol = { + .handler = nip_icmp_rcv, + .err_handler = nip_icmp_err, + .flags = 0, +}; + +int __init nip_icmp_init(void) +{ + int ret; + + ret = ninet_add_protocol(&nip_icmp_protocol, IPPROTO_NIP_ICMP); + return ret; +} diff --git a/code/linux/net/newip/ninet_connection_sock.c b/code/linux/net/newip/ninet_connection_sock.c new file mode 100644 index 0000000..cfff906 --- /dev/null +++ b/code/linux/net/newip/ninet_connection_sock.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Support for NewIP INET connection oriented protocols. + * + * Based on net/ipv4/inet_connection_sock.c + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function + * Timeout handler for request processing, used to retransmit SYN+ACK + * Parameter + * t: Request control block + */ +static void ninet_reqsk_timer_handler(struct timer_list *t) +{ + struct request_sock *req = from_timer(req, t, rsk_timer); + struct sock *sk_listener = req->rsk_listener; + struct net *net = sock_net(sk_listener); + struct inet_connection_sock *icsk = inet_csk(sk_listener); + struct request_sock_queue *queue = &icsk->icsk_accept_queue; + int max_retries, thresh; + + /* Defines the maximum number of retransmissions. Thresh defaults to 5 */ + max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; + thresh = max_retries; + + /* Check timeout times. SYN+ACK retransmission times +1 */ + if (req->num_timeout <= thresh) { + unsigned long timeo; + + req->rsk_ops->rtx_syn_ack(sk_listener, req); + req->num_retrans++; + /* If the number of times out is still 0, the number is increased by 1 + * to determine whether it is the first time out + */ + if (req->num_timeout++ == 0) + atomic_dec(&queue->young); + timeo = min(TCP_TIMEOUT_INIT, TCP_RTO_MAX); + mod_timer(&req->rsk_timer, jiffies + timeo); + return; + } + + inet_csk_reqsk_queue_drop_and_put(sk_listener, req); +} + +/* Function + * Add request_SOCK to the connection queue and ehash table, + * and set the SYNACK timeout retransmission timer + * Parameter + * sk: Transmission control block + * req: Connection request block + * timeout: The initial timeout period + */ +void ninet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, + unsigned long timeout) +{ + req->num_retrans = 0; + req->num_timeout = 0; + req->sk = NULL; + + timer_setup(&req->rsk_timer, ninet_reqsk_timer_handler, + TIMER_PINNED); + mod_timer(&req->rsk_timer, jiffies + timeout); + + inet_ehash_insert(req_to_sk(req), NULL, NULL); + + smp_wmb(); /* memory barrier */ + refcount_set(&req->rsk_refcnt, TCP_NUM_2 + 1); + + inet_csk_reqsk_queue_added(sk); +} + +/* Function + * Check whether the socket conflicts with the linked list. If no, 0 is returned + * Parameter + * sk: The transport control block to listen + * tb: bind bucket, sock list for storing bind + */ +int ninet_csk_bind_conflict(const struct sock *sk, + const struct inet_bind_bucket *tb, bool relax) +{ + return 0; +} + diff --git a/code/linux/net/newip/ninet_hashtables.c b/code/linux/net/newip/ninet_hashtables.c new file mode 100644 index 0000000..0e3419b --- /dev/null +++ b/code/linux/net/newip/ninet_hashtables.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Generic NewIP INET transport hashtables + * + * Based on net/ipv4/inet_hashtables.c + * Based on net/ipv6/inet6_hashtables.c + * Based on include/net/ip.h + * Based on include/net/ipv6.h + */ +#include +#include + +#include +#include +#include +#include +#include + +static inline u32 nip_portaddr_hash(const struct net *net, + const struct nip_addr *saddr, + unsigned int port) +{ + u32 v = (__force u32)saddr->nip_addr_field32[0] ^ (__force u32)saddr->nip_addr_field32[1]; + + return jhash_1word(v, net_hash_mix(net)) ^ port; +} + +static u32 __nip_addr_jhash(const struct nip_addr *a, const u32 initval) +{ + u32 v = (__force u32)a->nip_addr_field32[0] ^ (__force u32)a->nip_addr_field32[1]; + + return jhash_3words(v, + (__force u32)a->nip_addr_field32[0], + (__force u32)a->nip_addr_field32[1], + initval); +} + +static struct inet_listen_hashbucket * +ninet_lhash2_bucket_sk(struct inet_hashinfo *h, struct sock *sk) +{ + u32 hash = nip_portaddr_hash(sock_net(sk), + &sk->sk_nip_rcv_saddr, + inet_sk(sk)->inet_num); + return inet_lhash2_bucket(h, hash); +} + +static void ninet_hash2(struct inet_hashinfo *h, struct sock *sk) +{ + struct inet_listen_hashbucket *ilb2; + + if (!h->lhash2) + return; + + ilb2 = ninet_lhash2_bucket_sk(h, sk); + + spin_lock(&ilb2->lock); + hlist_add_head_rcu(&inet_csk(sk)->icsk_listen_portaddr_node, &ilb2->head); + + ilb2->count++; + spin_unlock(&ilb2->lock); +} + +/* Function + * Returns the hash value based on the passed argument + * Parameter + * net: The namespace + * laddr: The destination address + * lport: Destination port + * faddr: Source address + * fport: Source port + */ +u32 ninet_ehashfn(const struct net *net, + const struct nip_addr *laddr, const u16 lport, + const struct nip_addr *faddr, const __be16 fport) +{ + static u32 ninet_ehash_secret __read_mostly; + static u32 ninet_hash_secret __read_mostly; + + u32 lhash, fhash; + + net_get_random_once(&ninet_ehash_secret, sizeof(ninet_ehash_secret)); + net_get_random_once(&ninet_hash_secret, sizeof(ninet_hash_secret)); + + /* Ipv6 uses S6_ADdr32 [3], the last 32bits of the address */ + lhash = (__force u32)laddr->nip_addr_field32[0]; + fhash = __nip_addr_jhash(faddr, ninet_hash_secret); + + return __ninet_ehashfn(lhash, lport, fhash, fport, + ninet_ehash_secret + net_hash_mix(net)); +} + +/* Function + * The socket is put into the Listen hash in case the server finds + the socket in the second handshake + * Parameter + * sk: Transmission control block + * osk: old socket + */ +int __ninet_hash(struct sock *sk, struct sock *osk) +{ + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; + struct inet_listen_hashbucket *ilb; + int err = 0; + + if (sk->sk_state != TCP_LISTEN) { + inet_ehash_nolisten(sk, osk, NULL); + return 0; + } + WARN_ON(!sk_unhashed(sk)); + ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; + + spin_lock(&ilb->lock); + + __sk_nulls_add_node_rcu(sk, &ilb->nulls_head); + + ninet_hash2(hashinfo, sk); + ilb->count++; + sock_set_flag(sk, SOCK_RCU_FREE); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + + spin_unlock(&ilb->lock); + + return err; +} + +int ninet_hash(struct sock *sk) +{ + int err = 0; + + if (sk->sk_state != TCP_CLOSE) { + local_bh_disable(); + err = __ninet_hash(sk, NULL); + local_bh_enable(); + } + + return err; +} + +static void ninet_unhash2(struct inet_hashinfo *h, struct sock *sk) +{ + struct inet_listen_hashbucket *ilb2; + + if (!h->lhash2 || + WARN_ON_ONCE(hlist_unhashed(&inet_csk(sk)->icsk_listen_portaddr_node))) + return; + + ilb2 = ninet_lhash2_bucket_sk(h, sk); + + spin_lock(&ilb2->lock); + hlist_del_init_rcu(&inet_csk(sk)->icsk_listen_portaddr_node); + ilb2->count--; + spin_unlock(&ilb2->lock); +} + +void ninet_unhash(struct sock *sk) +{ + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; + struct inet_listen_hashbucket *ilb = NULL; + spinlock_t *lock; /* Spin lock (note deleted alarm) */ + + if (sk_unhashed(sk)) + return; + + if (sk->sk_state == TCP_LISTEN) { + ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; + lock = &ilb->lock; + } else { + lock = inet_ehash_lockp(hashinfo, sk->sk_hash); + } + spin_lock_bh(lock); + if (sk_unhashed(sk)) + goto unlock; + + if (ilb) { + ninet_unhash2(hashinfo, sk); + ilb->count--; + } + __sk_nulls_del_node_init_rcu(sk); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + +unlock: + spin_unlock_bh(lock); +} + +/* Function + * Find transport control blocks based on address and port in the ehash table. + * If found, three handshakes have been made and a connection has been established, + * and normal communication can proceed. + * Parameter + * net: The namespace + * hashinfo: A global scalar of type tcp_hashinfo that stores tcp_SOCK(including ESTABLISHED, + * listen, and bind) for various states of the current system. + * saddr: Source address + * sport: Source port + * daddr: The destination address + * hnum: Destination port + */ +struct sock *__ninet_lookup_established(struct net *net, + struct inet_hashinfo *hashinfo, + const struct nip_addr *saddr, + const __be16 sport, + const struct nip_addr *daddr, + const u16 hnum, + const int dif) +{ + struct sock *sk; + const struct hlist_nulls_node *node; + + const __portpair ports = INET_COMBINED_PORTS(sport, hnum); + + unsigned int hash = ninet_ehashfn(net, daddr, hnum, saddr, sport); + unsigned int slot = hash & hashinfo->ehash_mask; + + struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; + +begin: + sk_nulls_for_each_rcu(sk, node, &head->chain) { + DEBUG("%s: sk->sk_hash:%u", __func__, sk->sk_hash); + DEBUG("%s: dif:%d", __func__, dif); + if (sk->sk_hash != hash) + continue; + if (!NINET_MATCH(sk, net, saddr, daddr, ports, dif)) + continue; + if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) { + DEBUG("[nip]%s:sk->sk_refcnt == 0!!!!\n", __func__); + goto out; + } + + if (unlikely(!NINET_MATCH(sk, net, saddr, daddr, ports, dif))) { + sock_gen_put(sk); + goto begin; + } + DEBUG("%s: find sock in ehash table!", __func__); + goto found; + } + if (get_nulls_value(node) != slot) + goto begin; +out: + sk = NULL; +found: + return sk; +} + +static inline int nip_tcp_compute_score(struct sock *sk, struct net *net, + const unsigned short hnum, + const struct nip_addr *daddr, + const int dif, int sdif) +{ + int score = -1; + + if (inet_sk(sk)->inet_num == hnum && sk->sk_family == PF_NINET && + net_eq(sock_net(sk), net)) { + score = 1; + if (!nip_addr_eq(&sk->sk_nip_rcv_saddr, &nip_any_addr)) { + if (!nip_addr_eq(&sk->sk_nip_rcv_saddr, daddr)) + return -1; + score++; + } + if (!inet_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) + return -1; + score++; + if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) + score++; + } + + return score; +} + +static struct sock *ninet_lhash2_lookup(struct net *net, + struct inet_listen_hashbucket *ilb2, + struct sk_buff *skb, int doff, + const struct nip_addr *saddr, __be16 sport, + const struct nip_addr *daddr, const unsigned short hnum, + const int dif, const int sdif) +{ + struct inet_connection_sock *icsk; + struct sock *sk, *result = NULL; + int score, hiscore = 0, matches = 0, reuseport = 0; + u32 phash = 0; + + inet_lhash2_for_each_icsk_rcu(icsk, &ilb2->head) { + sk = (struct sock *)icsk; + score = nip_tcp_compute_score(sk, net, hnum, daddr, dif, sdif); + if (score > hiscore) { + DEBUG("%s: find sock in lhash table", __func__); + result = sk; + hiscore = score; + reuseport = sk->sk_reuseport; + if (reuseport) { + DEBUG("%s: find reuseport sock in lhash table", __func__); + phash = ninet_ehashfn(net, daddr, hnum, saddr, sport); + matches = 1; + } + } else if (score == hiscore && reuseport) { + matches++; + if (reciprocal_scale(phash, matches) == 0) + result = sk; + phash = next_pseudo_random32(phash); + } + } + return result; +} + +struct sock *ninet_lookup_listener(struct net *net, + struct inet_hashinfo *hashinfo, + struct sk_buff *skb, int doff, + const struct nip_addr *saddr, + const __be16 sport, const struct nip_addr *daddr, + const unsigned short hnum, const int dif, const int sdif) +{ + struct inet_listen_hashbucket *ilb2; + struct sock *result = NULL; + unsigned int hash2 = nip_portaddr_hash(net, daddr, hnum); + + ilb2 = inet_lhash2_bucket(hashinfo, hash2); + + result = ninet_lhash2_lookup(net, ilb2, skb, doff, + saddr, sport, daddr, hnum, + dif, sdif); + if (result) + goto done; + + hash2 = nip_portaddr_hash(net, &nip_any_addr, hnum); + ilb2 = inet_lhash2_bucket(hashinfo, hash2); + + result = ninet_lhash2_lookup(net, ilb2, skb, doff, + saddr, sport, &nip_any_addr, hnum, + dif, sdif); +done: + if (IS_ERR(result)) + return NULL; + return result; +} + +/* Check whether the quad information in sock is bound by ehash. If not, + * the SK is inserted into the ehash and 0 is returned + */ +static int __ninet_check_established(struct inet_timewait_death_row *death_row, + struct sock *sk, const __u16 lport, + struct inet_timewait_sock **twp) +{ + struct inet_hashinfo *hinfo = death_row->hashinfo; + struct inet_sock *inet = inet_sk(sk); + struct nip_addr *daddr = &sk->sk_nip_rcv_saddr; + struct nip_addr *saddr = &sk->sk_nip_daddr; + int dif = sk->sk_bound_dev_if; + struct net *net = sock_net(sk); + const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); + unsigned int hash = ninet_ehashfn(net, daddr, lport, + saddr, inet->inet_dport); + struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); + spinlock_t *lock = inet_ehash_lockp(hinfo, hash); + struct sock *sk2; + const struct hlist_nulls_node *node; + + spin_lock(lock); + + sk_nulls_for_each(sk2, node, &head->chain) { + if (sk2->sk_hash != hash) + continue; + + if (likely(NINET_MATCH(sk2, net, + saddr, daddr, ports, dif))) { + DEBUG("%s: found same sk in ehash!\n", __func__); + goto not_unique; + } + } + + /* Must record num and sport now. Otherwise we will see + * in hash table socket with a funny identity. + */ + DEBUG("%s: add tcp sock into ehash table. sport=%u\n", + __func__, lport); + inet->inet_num = lport; + inet->inet_sport = htons(lport); + sk->sk_hash = hash; + WARN_ON(!sk_unhashed(sk)); + __sk_nulls_add_node_rcu(sk, &head->chain); + + spin_unlock(lock); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + return 0; + +not_unique: + spin_unlock(lock); + return -EADDRNOTAVAIL; +} + +static u64 ninet_sk_port_offset(const struct sock *sk) +{ + const struct inet_sock *inet = inet_sk(sk); + + return secure_newip_port_ephemeral(sk->sk_nip_rcv_saddr.nip_addr_field32, + sk->sk_nip_daddr.nip_addr_field32, + inet->inet_dport); +} + +/* Bind local ports randomly */ +int ninet_hash_connect(struct inet_timewait_death_row *death_row, + struct sock *sk) +{ + u64 port_offset = 0; + + if (!inet_sk(sk)->inet_num) + port_offset = ninet_sk_port_offset(sk); + + return __inet_hash_connect(death_row, sk, port_offset, + __ninet_check_established); +} + -- Gitee