mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 07:04:10 +08:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git
/klassert/ipsec-next Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2021-06-28 1) Remove an unneeded error assignment in esp4_gro_receive(). From Yang Li. 2) Add a new byseq state hashtable to find acquire states faster. From Sabrina Dubroca. 3) Remove some unnecessary variables in pfkey_create(). From zuoqilin. 4) Remove the unused description from xfrm_type struct. From Florian Westphal. 5) Fix a spelling mistake in the comment of xfrm_state_ok(). From gushengxian. 6) Replace hdr_off indirections by a small helper function. From Florian Westphal. 7) Remove xfrm4_output_finish and xfrm6_output_finish declarations, they are not used anymore.From Antony Antony. 8) Remove xfrm replay indirections. From Florian Westphal. Please pull or let me know if there are problems. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
1b077ce1c5
@ -42,6 +42,7 @@ struct netns_xfrm {
|
|||||||
struct hlist_head __rcu *state_bydst;
|
struct hlist_head __rcu *state_bydst;
|
||||||
struct hlist_head __rcu *state_bysrc;
|
struct hlist_head __rcu *state_bysrc;
|
||||||
struct hlist_head __rcu *state_byspi;
|
struct hlist_head __rcu *state_byspi;
|
||||||
|
struct hlist_head __rcu *state_byseq;
|
||||||
unsigned int state_hmask;
|
unsigned int state_hmask;
|
||||||
unsigned int state_num;
|
unsigned int state_num;
|
||||||
struct work_struct state_hash_work;
|
struct work_struct state_hash_work;
|
||||||
|
@ -145,6 +145,12 @@ enum {
|
|||||||
XFRM_MODE_FLAG_TUNNEL = 1,
|
XFRM_MODE_FLAG_TUNNEL = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum xfrm_replay_mode {
|
||||||
|
XFRM_REPLAY_MODE_LEGACY,
|
||||||
|
XFRM_REPLAY_MODE_BMP,
|
||||||
|
XFRM_REPLAY_MODE_ESN,
|
||||||
|
};
|
||||||
|
|
||||||
/* Full description of state of transformer. */
|
/* Full description of state of transformer. */
|
||||||
struct xfrm_state {
|
struct xfrm_state {
|
||||||
possible_net_t xs_net;
|
possible_net_t xs_net;
|
||||||
@ -154,6 +160,7 @@ struct xfrm_state {
|
|||||||
};
|
};
|
||||||
struct hlist_node bysrc;
|
struct hlist_node bysrc;
|
||||||
struct hlist_node byspi;
|
struct hlist_node byspi;
|
||||||
|
struct hlist_node byseq;
|
||||||
|
|
||||||
refcount_t refcnt;
|
refcount_t refcnt;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
@ -214,9 +221,8 @@ struct xfrm_state {
|
|||||||
struct xfrm_replay_state preplay;
|
struct xfrm_replay_state preplay;
|
||||||
struct xfrm_replay_state_esn *preplay_esn;
|
struct xfrm_replay_state_esn *preplay_esn;
|
||||||
|
|
||||||
/* The functions for replay detection. */
|
/* replay detection mode */
|
||||||
const struct xfrm_replay *repl;
|
enum xfrm_replay_mode repl_mode;
|
||||||
|
|
||||||
/* internal flag that only holds state for delayed aevent at the
|
/* internal flag that only holds state for delayed aevent at the
|
||||||
* moment
|
* moment
|
||||||
*/
|
*/
|
||||||
@ -296,18 +302,6 @@ struct km_event {
|
|||||||
struct net *net;
|
struct net *net;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xfrm_replay {
|
|
||||||
void (*advance)(struct xfrm_state *x, __be32 net_seq);
|
|
||||||
int (*check)(struct xfrm_state *x,
|
|
||||||
struct sk_buff *skb,
|
|
||||||
__be32 net_seq);
|
|
||||||
int (*recheck)(struct xfrm_state *x,
|
|
||||||
struct sk_buff *skb,
|
|
||||||
__be32 net_seq);
|
|
||||||
void (*notify)(struct xfrm_state *x, int event);
|
|
||||||
int (*overflow)(struct xfrm_state *x, struct sk_buff *skb);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xfrm_if_cb {
|
struct xfrm_if_cb {
|
||||||
struct xfrm_if *(*decode_session)(struct sk_buff *skb,
|
struct xfrm_if *(*decode_session)(struct sk_buff *skb,
|
||||||
unsigned short family);
|
unsigned short family);
|
||||||
@ -387,7 +381,6 @@ void xfrm_flush_gc(void);
|
|||||||
void xfrm_state_delete_tunnel(struct xfrm_state *x);
|
void xfrm_state_delete_tunnel(struct xfrm_state *x);
|
||||||
|
|
||||||
struct xfrm_type {
|
struct xfrm_type {
|
||||||
char *description;
|
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
@ -402,14 +395,12 @@ struct xfrm_type {
|
|||||||
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
|
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
|
||||||
int (*reject)(struct xfrm_state *, struct sk_buff *,
|
int (*reject)(struct xfrm_state *, struct sk_buff *,
|
||||||
const struct flowi *);
|
const struct flowi *);
|
||||||
int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int xfrm_register_type(const struct xfrm_type *type, unsigned short family);
|
int xfrm_register_type(const struct xfrm_type *type, unsigned short family);
|
||||||
void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family);
|
void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family);
|
||||||
|
|
||||||
struct xfrm_type_offload {
|
struct xfrm_type_offload {
|
||||||
char *description;
|
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
void (*encap)(struct xfrm_state *, struct sk_buff *pskb);
|
void (*encap)(struct xfrm_state *, struct sk_buff *pskb);
|
||||||
@ -1582,7 +1573,6 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb);
|
int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||||
int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb);
|
|
||||||
int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
|
int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
|
||||||
int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol);
|
int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol);
|
||||||
int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
|
int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
|
||||||
@ -1606,9 +1596,6 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
|
|||||||
__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
|
__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
|
||||||
__be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr);
|
__be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr);
|
||||||
int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb);
|
int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||||
int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb);
|
|
||||||
int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
|
|
||||||
u8 **prevhdr);
|
|
||||||
|
|
||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu);
|
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu);
|
||||||
@ -1722,6 +1709,12 @@ static inline int xfrm_policy_id2dir(u32 index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
|
void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq);
|
||||||
|
int xfrm_replay_check(struct xfrm_state *x, struct sk_buff *skb, __be32 net_seq);
|
||||||
|
void xfrm_replay_notify(struct xfrm_state *x, int event);
|
||||||
|
int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb);
|
||||||
|
int xfrm_replay_recheck(struct xfrm_state *x, struct sk_buff *skb, __be32 net_seq);
|
||||||
|
|
||||||
static inline int xfrm_aevent_is_on(struct net *net)
|
static inline int xfrm_aevent_is_on(struct net *net)
|
||||||
{
|
{
|
||||||
struct sock *nlsk;
|
struct sock *nlsk;
|
||||||
|
@ -554,7 +554,6 @@ static int ah4_rcv_cb(struct sk_buff *skb, int err)
|
|||||||
|
|
||||||
static const struct xfrm_type ah_type =
|
static const struct xfrm_type ah_type =
|
||||||
{
|
{
|
||||||
.description = "AH4",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_AH,
|
.proto = IPPROTO_AH,
|
||||||
.flags = XFRM_TYPE_REPLAY_PROT,
|
.flags = XFRM_TYPE_REPLAY_PROT,
|
||||||
|
@ -1198,7 +1198,6 @@ static int esp4_rcv_cb(struct sk_buff *skb, int err)
|
|||||||
|
|
||||||
static const struct xfrm_type esp_type =
|
static const struct xfrm_type esp_type =
|
||||||
{
|
{
|
||||||
.description = "ESP4",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_ESP,
|
.proto = IPPROTO_ESP,
|
||||||
.flags = XFRM_TYPE_REPLAY_PROT,
|
.flags = XFRM_TYPE_REPLAY_PROT,
|
||||||
|
@ -33,12 +33,11 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
|
|||||||
struct xfrm_state *x;
|
struct xfrm_state *x;
|
||||||
__be32 seq;
|
__be32 seq;
|
||||||
__be32 spi;
|
__be32 spi;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!pskb_pull(skb, offset))
|
if (!pskb_pull(skb, offset))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((err = xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq)) != 0)
|
if (xfrm_parse_spi(skb, IPPROTO_ESP, &spi, &seq) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
xo = xfrm_offload(skb);
|
xo = xfrm_offload(skb);
|
||||||
@ -343,7 +342,6 @@ static const struct net_offload esp4_offload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct xfrm_type_offload esp_type_offload = {
|
static const struct xfrm_type_offload esp_type_offload = {
|
||||||
.description = "ESP4 OFFLOAD",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_ESP,
|
.proto = IPPROTO_ESP,
|
||||||
.input_tail = esp_input_tail,
|
.input_tail = esp_input_tail,
|
||||||
|
@ -152,7 +152,6 @@ static int ipcomp4_rcv_cb(struct sk_buff *skb, int err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type ipcomp_type = {
|
static const struct xfrm_type ipcomp_type = {
|
||||||
.description = "IPCOMP4",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_COMP,
|
.proto = IPPROTO_COMP,
|
||||||
.init_state = ipcomp4_init_state,
|
.init_state = ipcomp4_init_state,
|
||||||
|
@ -42,7 +42,6 @@ static void ipip_destroy(struct xfrm_state *x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type ipip_type = {
|
static const struct xfrm_type ipip_type = {
|
||||||
.description = "IPIP",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_IPIP,
|
.proto = IPPROTO_IPIP,
|
||||||
.init_state = ipip_init_state,
|
.init_state = ipip_init_state,
|
||||||
|
@ -755,7 +755,6 @@ static int ah6_rcv_cb(struct sk_buff *skb, int err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type ah6_type = {
|
static const struct xfrm_type ah6_type = {
|
||||||
.description = "AH6",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_AH,
|
.proto = IPPROTO_AH,
|
||||||
.flags = XFRM_TYPE_REPLAY_PROT,
|
.flags = XFRM_TYPE_REPLAY_PROT,
|
||||||
@ -763,7 +762,6 @@ static const struct xfrm_type ah6_type = {
|
|||||||
.destructor = ah6_destroy,
|
.destructor = ah6_destroy,
|
||||||
.input = ah6_input,
|
.input = ah6_input,
|
||||||
.output = ah6_output,
|
.output = ah6_output,
|
||||||
.hdr_offset = xfrm6_find_1stfragopt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct xfrm6_protocol ah6_protocol = {
|
static struct xfrm6_protocol ah6_protocol = {
|
||||||
|
@ -1243,7 +1243,6 @@ static int esp6_rcv_cb(struct sk_buff *skb, int err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type esp6_type = {
|
static const struct xfrm_type esp6_type = {
|
||||||
.description = "ESP6",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_ESP,
|
.proto = IPPROTO_ESP,
|
||||||
.flags = XFRM_TYPE_REPLAY_PROT,
|
.flags = XFRM_TYPE_REPLAY_PROT,
|
||||||
@ -1251,7 +1250,6 @@ static const struct xfrm_type esp6_type = {
|
|||||||
.destructor = esp6_destroy,
|
.destructor = esp6_destroy,
|
||||||
.input = esp6_input,
|
.input = esp6_input,
|
||||||
.output = esp6_output,
|
.output = esp6_output,
|
||||||
.hdr_offset = xfrm6_find_1stfragopt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct xfrm6_protocol esp6_protocol = {
|
static struct xfrm6_protocol esp6_protocol = {
|
||||||
|
@ -377,7 +377,6 @@ static const struct net_offload esp6_offload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct xfrm_type_offload esp6_type_offload = {
|
static const struct xfrm_type_offload esp6_type_offload = {
|
||||||
.description = "ESP6 OFFLOAD",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_ESP,
|
.proto = IPPROTO_ESP,
|
||||||
.input_tail = esp6_input_tail,
|
.input_tail = esp6_input_tail,
|
||||||
|
@ -172,14 +172,12 @@ static int ipcomp6_rcv_cb(struct sk_buff *skb, int err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type ipcomp6_type = {
|
static const struct xfrm_type ipcomp6_type = {
|
||||||
.description = "IPCOMP6",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_COMP,
|
.proto = IPPROTO_COMP,
|
||||||
.init_state = ipcomp6_init_state,
|
.init_state = ipcomp6_init_state,
|
||||||
.destructor = ipcomp_destroy,
|
.destructor = ipcomp_destroy,
|
||||||
.input = ipcomp_input,
|
.input = ipcomp_input,
|
||||||
.output = ipcomp_output,
|
.output = ipcomp_output,
|
||||||
.hdr_offset = xfrm6_find_1stfragopt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct xfrm6_protocol ipcomp6_protocol = {
|
static struct xfrm6_protocol ipcomp6_protocol = {
|
||||||
|
@ -247,54 +247,6 @@ static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
|
|
||||||
u8 **nexthdr)
|
|
||||||
{
|
|
||||||
u16 offset = sizeof(struct ipv6hdr);
|
|
||||||
struct ipv6_opt_hdr *exthdr =
|
|
||||||
(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
|
|
||||||
const unsigned char *nh = skb_network_header(skb);
|
|
||||||
unsigned int packet_len = skb_tail_pointer(skb) -
|
|
||||||
skb_network_header(skb);
|
|
||||||
int found_rhdr = 0;
|
|
||||||
|
|
||||||
*nexthdr = &ipv6_hdr(skb)->nexthdr;
|
|
||||||
|
|
||||||
while (offset + 1 <= packet_len) {
|
|
||||||
|
|
||||||
switch (**nexthdr) {
|
|
||||||
case NEXTHDR_HOP:
|
|
||||||
break;
|
|
||||||
case NEXTHDR_ROUTING:
|
|
||||||
found_rhdr = 1;
|
|
||||||
break;
|
|
||||||
case NEXTHDR_DEST:
|
|
||||||
/*
|
|
||||||
* HAO MUST NOT appear more than once.
|
|
||||||
* XXX: It is better to try to find by the end of
|
|
||||||
* XXX: packet if HAO exists.
|
|
||||||
*/
|
|
||||||
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
|
|
||||||
net_dbg_ratelimited("mip6: hao exists already, override\n");
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found_rhdr)
|
|
||||||
return offset;
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += ipv6_optlen(exthdr);
|
|
||||||
*nexthdr = &exthdr->nexthdr;
|
|
||||||
exthdr = (struct ipv6_opt_hdr *)(nh + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mip6_destopt_init_state(struct xfrm_state *x)
|
static int mip6_destopt_init_state(struct xfrm_state *x)
|
||||||
{
|
{
|
||||||
if (x->id.spi) {
|
if (x->id.spi) {
|
||||||
@ -324,7 +276,6 @@ static void mip6_destopt_destroy(struct xfrm_state *x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type mip6_destopt_type = {
|
static const struct xfrm_type mip6_destopt_type = {
|
||||||
.description = "MIP6DESTOPT",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_DSTOPTS,
|
.proto = IPPROTO_DSTOPTS,
|
||||||
.flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
|
.flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
|
||||||
@ -333,7 +284,6 @@ static const struct xfrm_type mip6_destopt_type = {
|
|||||||
.input = mip6_destopt_input,
|
.input = mip6_destopt_input,
|
||||||
.output = mip6_destopt_output,
|
.output = mip6_destopt_output,
|
||||||
.reject = mip6_destopt_reject,
|
.reject = mip6_destopt_reject,
|
||||||
.hdr_offset = mip6_destopt_offset,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
|
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
@ -383,53 +333,6 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
|
|
||||||
u8 **nexthdr)
|
|
||||||
{
|
|
||||||
u16 offset = sizeof(struct ipv6hdr);
|
|
||||||
struct ipv6_opt_hdr *exthdr =
|
|
||||||
(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
|
|
||||||
const unsigned char *nh = skb_network_header(skb);
|
|
||||||
unsigned int packet_len = skb_tail_pointer(skb) -
|
|
||||||
skb_network_header(skb);
|
|
||||||
int found_rhdr = 0;
|
|
||||||
|
|
||||||
*nexthdr = &ipv6_hdr(skb)->nexthdr;
|
|
||||||
|
|
||||||
while (offset + 1 <= packet_len) {
|
|
||||||
|
|
||||||
switch (**nexthdr) {
|
|
||||||
case NEXTHDR_HOP:
|
|
||||||
break;
|
|
||||||
case NEXTHDR_ROUTING:
|
|
||||||
if (offset + 3 <= packet_len) {
|
|
||||||
struct ipv6_rt_hdr *rt;
|
|
||||||
rt = (struct ipv6_rt_hdr *)(nh + offset);
|
|
||||||
if (rt->type != 0)
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
found_rhdr = 1;
|
|
||||||
break;
|
|
||||||
case NEXTHDR_DEST:
|
|
||||||
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
|
|
||||||
return offset;
|
|
||||||
|
|
||||||
if (found_rhdr)
|
|
||||||
return offset;
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += ipv6_optlen(exthdr);
|
|
||||||
*nexthdr = &exthdr->nexthdr;
|
|
||||||
exthdr = (struct ipv6_opt_hdr *)(nh + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mip6_rthdr_init_state(struct xfrm_state *x)
|
static int mip6_rthdr_init_state(struct xfrm_state *x)
|
||||||
{
|
{
|
||||||
if (x->id.spi) {
|
if (x->id.spi) {
|
||||||
@ -456,7 +359,6 @@ static void mip6_rthdr_destroy(struct xfrm_state *x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type mip6_rthdr_type = {
|
static const struct xfrm_type mip6_rthdr_type = {
|
||||||
.description = "MIP6RT",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_ROUTING,
|
.proto = IPPROTO_ROUTING,
|
||||||
.flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
|
.flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
|
||||||
@ -464,7 +366,6 @@ static const struct xfrm_type mip6_rthdr_type = {
|
|||||||
.destructor = mip6_rthdr_destroy,
|
.destructor = mip6_rthdr_destroy,
|
||||||
.input = mip6_rthdr_input,
|
.input = mip6_rthdr_input,
|
||||||
.output = mip6_rthdr_output,
|
.output = mip6_rthdr_output,
|
||||||
.hdr_offset = mip6_rthdr_offset,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init mip6_init(void)
|
static int __init mip6_init(void)
|
||||||
|
@ -16,13 +16,6 @@
|
|||||||
#include <net/ip6_route.h>
|
#include <net/ip6_route.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
|
|
||||||
u8 **prevhdr)
|
|
||||||
{
|
|
||||||
return ip6_find_1stfragopt(skb, prevhdr);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(xfrm6_find_1stfragopt);
|
|
||||||
|
|
||||||
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
|
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
|
||||||
{
|
{
|
||||||
struct flowi6 fl6;
|
struct flowi6 fl6;
|
||||||
|
@ -291,7 +291,6 @@ static void xfrm6_tunnel_destroy(struct xfrm_state *x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_type xfrm6_tunnel_type = {
|
static const struct xfrm_type xfrm6_tunnel_type = {
|
||||||
.description = "IP6IP6",
|
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.proto = IPPROTO_IPV6,
|
.proto = IPPROTO_IPV6,
|
||||||
.init_state = xfrm6_tunnel_init_state,
|
.init_state = xfrm6_tunnel_init_state,
|
||||||
|
@ -141,7 +141,6 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol,
|
|||||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
struct pfkey_sock *pfk;
|
struct pfkey_sock *pfk;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
@ -150,10 +149,9 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol,
|
|||||||
if (protocol != PF_KEY_V2)
|
if (protocol != PF_KEY_V2)
|
||||||
return -EPROTONOSUPPORT;
|
return -EPROTONOSUPPORT;
|
||||||
|
|
||||||
err = -ENOMEM;
|
|
||||||
sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto, kern);
|
sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto, kern);
|
||||||
if (sk == NULL)
|
if (sk == NULL)
|
||||||
goto out;
|
return -ENOMEM;
|
||||||
|
|
||||||
pfk = pfkey_sk(sk);
|
pfk = pfkey_sk(sk);
|
||||||
mutex_init(&pfk->dump_lock);
|
mutex_init(&pfk->dump_lock);
|
||||||
@ -169,8 +167,6 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol,
|
|||||||
pfkey_insert(sk);
|
pfkey_insert(sk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pfkey_release(struct socket *sock)
|
static int pfkey_release(struct socket *sock)
|
||||||
|
@ -131,6 +131,13 @@ __xfrm_spi_hash(const xfrm_address_t *daddr, __be32 spi, u8 proto,
|
|||||||
return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
|
return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned int
|
||||||
|
__xfrm_seq_hash(u32 seq, unsigned int hmask)
|
||||||
|
{
|
||||||
|
unsigned int h = seq;
|
||||||
|
return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
|
static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
|
||||||
{
|
{
|
||||||
return (index ^ (index >> 8)) & hmask;
|
return (index ^ (index >> 8)) & hmask;
|
||||||
|
@ -612,7 +612,7 @@ lock:
|
|||||||
goto drop_unlock;
|
goto drop_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x->repl->check(x, skb, seq)) {
|
if (xfrm_replay_check(x, skb, seq)) {
|
||||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
|
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
|
||||||
goto drop_unlock;
|
goto drop_unlock;
|
||||||
}
|
}
|
||||||
@ -660,12 +660,12 @@ resume:
|
|||||||
/* only the first xfrm gets the encap type */
|
/* only the first xfrm gets the encap type */
|
||||||
encap_type = 0;
|
encap_type = 0;
|
||||||
|
|
||||||
if (x->repl->recheck(x, skb, seq)) {
|
if (xfrm_replay_recheck(x, skb, seq)) {
|
||||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
|
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
|
||||||
goto drop_unlock;
|
goto drop_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
x->repl->advance(x, seq);
|
xfrm_replay_advance(x, seq);
|
||||||
|
|
||||||
x->curlft.bytes += skb->len;
|
x->curlft.bytes += skb->len;
|
||||||
x->curlft.packets++;
|
x->curlft.packets++;
|
||||||
|
@ -77,6 +77,83 @@ static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
||||||
|
static int mip6_rthdr_offset(struct sk_buff *skb, u8 **nexthdr, int type)
|
||||||
|
{
|
||||||
|
const unsigned char *nh = skb_network_header(skb);
|
||||||
|
unsigned int offset = sizeof(struct ipv6hdr);
|
||||||
|
unsigned int packet_len;
|
||||||
|
int found_rhdr = 0;
|
||||||
|
|
||||||
|
packet_len = skb_tail_pointer(skb) - nh;
|
||||||
|
*nexthdr = &ipv6_hdr(skb)->nexthdr;
|
||||||
|
|
||||||
|
while (offset <= packet_len) {
|
||||||
|
struct ipv6_opt_hdr *exthdr;
|
||||||
|
|
||||||
|
switch (**nexthdr) {
|
||||||
|
case NEXTHDR_HOP:
|
||||||
|
break;
|
||||||
|
case NEXTHDR_ROUTING:
|
||||||
|
if (type == IPPROTO_ROUTING && offset + 3 <= packet_len) {
|
||||||
|
struct ipv6_rt_hdr *rt;
|
||||||
|
|
||||||
|
rt = (struct ipv6_rt_hdr *)(nh + offset);
|
||||||
|
if (rt->type != 0)
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
found_rhdr = 1;
|
||||||
|
break;
|
||||||
|
case NEXTHDR_DEST:
|
||||||
|
/* HAO MUST NOT appear more than once.
|
||||||
|
* XXX: It is better to try to find by the end of
|
||||||
|
* XXX: packet if HAO exists.
|
||||||
|
*/
|
||||||
|
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
|
||||||
|
net_dbg_ratelimited("mip6: hao exists already, override\n");
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_rhdr)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
|
||||||
|
offset);
|
||||||
|
offset += ipv6_optlen(exthdr);
|
||||||
|
if (offset > IPV6_MAXPLEN)
|
||||||
|
return -EINVAL;
|
||||||
|
*nexthdr = &exthdr->nexthdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static int xfrm6_hdr_offset(struct xfrm_state *x, struct sk_buff *skb, u8 **prevhdr)
|
||||||
|
{
|
||||||
|
switch (x->type->proto) {
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
||||||
|
case IPPROTO_DSTOPTS:
|
||||||
|
case IPPROTO_ROUTING:
|
||||||
|
return mip6_rthdr_offset(skb, prevhdr, x->type->proto);
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip6_find_1stfragopt(skb, prevhdr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Add encapsulation header.
|
/* Add encapsulation header.
|
||||||
*
|
*
|
||||||
* The IP header and mutable extension headers will be moved forward to make
|
* The IP header and mutable extension headers will be moved forward to make
|
||||||
@ -92,7 +169,7 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
iph = ipv6_hdr(skb);
|
iph = ipv6_hdr(skb);
|
||||||
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
|
skb_set_inner_transport_header(skb, skb_transport_offset(skb));
|
||||||
|
|
||||||
hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
|
hdr_len = xfrm6_hdr_offset(x, skb, &prevhdr);
|
||||||
if (hdr_len < 0)
|
if (hdr_len < 0)
|
||||||
return hdr_len;
|
return hdr_len;
|
||||||
skb_set_mac_header(skb,
|
skb_set_mac_header(skb,
|
||||||
@ -122,7 +199,7 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
|
|
||||||
iph = ipv6_hdr(skb);
|
iph = ipv6_hdr(skb);
|
||||||
|
|
||||||
hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
|
hdr_len = xfrm6_hdr_offset(x, skb, &prevhdr);
|
||||||
if (hdr_len < 0)
|
if (hdr_len < 0)
|
||||||
return hdr_len;
|
return hdr_len;
|
||||||
skb_set_mac_header(skb,
|
skb_set_mac_header(skb,
|
||||||
@ -448,7 +525,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = x->repl->overflow(x, skb);
|
err = xfrm_replay_overflow(x, skb);
|
||||||
if (err) {
|
if (err) {
|
||||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR);
|
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -3247,7 +3247,7 @@ xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 or more than 0 is returned when validation is succeeded (either bypass
|
* 0 or more than 0 is returned when validation is succeeded (either bypass
|
||||||
* because of optional transport mode, or next index of the mathced secpath
|
* because of optional transport mode, or next index of the matched secpath
|
||||||
* state with the template.
|
* state with the template.
|
||||||
* -1 is returned when no matching template is found.
|
* -1 is returned when no matching template is found.
|
||||||
* Otherwise "-2 - errored_index" is returned.
|
* Otherwise "-2 - errored_index" is returned.
|
||||||
|
@ -34,8 +34,11 @@ u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq)
|
|||||||
return seq_hi;
|
return seq_hi;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(xfrm_replay_seqhi);
|
EXPORT_SYMBOL(xfrm_replay_seqhi);
|
||||||
;
|
|
||||||
static void xfrm_replay_notify(struct xfrm_state *x, int event)
|
static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event);
|
||||||
|
static void xfrm_replay_notify_esn(struct xfrm_state *x, int event);
|
||||||
|
|
||||||
|
void xfrm_replay_notify(struct xfrm_state *x, int event)
|
||||||
{
|
{
|
||||||
struct km_event c;
|
struct km_event c;
|
||||||
/* we send notify messages in case
|
/* we send notify messages in case
|
||||||
@ -48,6 +51,17 @@ static void xfrm_replay_notify(struct xfrm_state *x, int event)
|
|||||||
* The state structure must be locked!
|
* The state structure must be locked!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
switch (x->repl_mode) {
|
||||||
|
case XFRM_REPLAY_MODE_LEGACY:
|
||||||
|
break;
|
||||||
|
case XFRM_REPLAY_MODE_BMP:
|
||||||
|
xfrm_replay_notify_bmp(x, event);
|
||||||
|
return;
|
||||||
|
case XFRM_REPLAY_MODE_ESN:
|
||||||
|
xfrm_replay_notify_esn(x, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case XFRM_REPLAY_UPDATE:
|
case XFRM_REPLAY_UPDATE:
|
||||||
if (!x->replay_maxdiff ||
|
if (!x->replay_maxdiff ||
|
||||||
@ -81,7 +95,7 @@ static void xfrm_replay_notify(struct xfrm_state *x, int event)
|
|||||||
x->xflags &= ~XFRM_TIME_DEFER;
|
x->xflags &= ~XFRM_TIME_DEFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
|
static int __xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct net *net = xs_net(x);
|
struct net *net = xs_net(x);
|
||||||
@ -98,14 +112,14 @@ static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (xfrm_aevent_is_on(net))
|
if (xfrm_aevent_is_on(net))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xfrm_replay_check(struct xfrm_state *x,
|
static int xfrm_replay_check_legacy(struct xfrm_state *x,
|
||||||
struct sk_buff *skb, __be32 net_seq)
|
struct sk_buff *skb, __be32 net_seq)
|
||||||
{
|
{
|
||||||
u32 diff;
|
u32 diff;
|
||||||
u32 seq = ntohl(net_seq);
|
u32 seq = ntohl(net_seq);
|
||||||
@ -136,14 +150,26 @@ err:
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
|
static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq);
|
||||||
|
static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq);
|
||||||
|
|
||||||
|
void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
|
||||||
{
|
{
|
||||||
u32 diff;
|
u32 diff, seq;
|
||||||
u32 seq = ntohl(net_seq);
|
|
||||||
|
switch (x->repl_mode) {
|
||||||
|
case XFRM_REPLAY_MODE_LEGACY:
|
||||||
|
break;
|
||||||
|
case XFRM_REPLAY_MODE_BMP:
|
||||||
|
return xfrm_replay_advance_bmp(x, net_seq);
|
||||||
|
case XFRM_REPLAY_MODE_ESN:
|
||||||
|
return xfrm_replay_advance_esn(x, net_seq);
|
||||||
|
}
|
||||||
|
|
||||||
if (!x->props.replay_window)
|
if (!x->props.replay_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
seq = ntohl(net_seq);
|
||||||
if (seq > x->replay.seq) {
|
if (seq > x->replay.seq) {
|
||||||
diff = seq - x->replay.seq;
|
diff = seq - x->replay.seq;
|
||||||
if (diff < x->props.replay_window)
|
if (diff < x->props.replay_window)
|
||||||
@ -157,7 +183,7 @@ static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xfrm_aevent_is_on(xs_net(x)))
|
if (xfrm_aevent_is_on(xs_net(x)))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
|
static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
@ -178,7 +204,7 @@ static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (xfrm_aevent_is_on(net))
|
if (xfrm_aevent_is_on(net))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -273,7 +299,7 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
|
|||||||
replay_esn->bmp[nr] |= (1U << bitnr);
|
replay_esn->bmp[nr] |= (1U << bitnr);
|
||||||
|
|
||||||
if (xfrm_aevent_is_on(xs_net(x)))
|
if (xfrm_aevent_is_on(xs_net(x)))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
|
static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
|
||||||
@ -416,7 +442,7 @@ static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xfrm_aevent_is_on(net))
|
if (xfrm_aevent_is_on(net))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -481,6 +507,21 @@ err:
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xfrm_replay_check(struct xfrm_state *x,
|
||||||
|
struct sk_buff *skb, __be32 net_seq)
|
||||||
|
{
|
||||||
|
switch (x->repl_mode) {
|
||||||
|
case XFRM_REPLAY_MODE_LEGACY:
|
||||||
|
break;
|
||||||
|
case XFRM_REPLAY_MODE_BMP:
|
||||||
|
return xfrm_replay_check_bmp(x, skb, net_seq);
|
||||||
|
case XFRM_REPLAY_MODE_ESN:
|
||||||
|
return xfrm_replay_check_esn(x, skb, net_seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfrm_replay_check_legacy(x, skb, net_seq);
|
||||||
|
}
|
||||||
|
|
||||||
static int xfrm_replay_recheck_esn(struct xfrm_state *x,
|
static int xfrm_replay_recheck_esn(struct xfrm_state *x,
|
||||||
struct sk_buff *skb, __be32 net_seq)
|
struct sk_buff *skb, __be32 net_seq)
|
||||||
{
|
{
|
||||||
@ -493,6 +534,22 @@ static int xfrm_replay_recheck_esn(struct xfrm_state *x,
|
|||||||
return xfrm_replay_check_esn(x, skb, net_seq);
|
return xfrm_replay_check_esn(x, skb, net_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xfrm_replay_recheck(struct xfrm_state *x,
|
||||||
|
struct sk_buff *skb, __be32 net_seq)
|
||||||
|
{
|
||||||
|
switch (x->repl_mode) {
|
||||||
|
case XFRM_REPLAY_MODE_LEGACY:
|
||||||
|
break;
|
||||||
|
case XFRM_REPLAY_MODE_BMP:
|
||||||
|
/* no special recheck treatment */
|
||||||
|
return xfrm_replay_check_bmp(x, skb, net_seq);
|
||||||
|
case XFRM_REPLAY_MODE_ESN:
|
||||||
|
return xfrm_replay_recheck_esn(x, skb, net_seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfrm_replay_check_legacy(x, skb, net_seq);
|
||||||
|
}
|
||||||
|
|
||||||
static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
|
static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
|
||||||
{
|
{
|
||||||
unsigned int bitnr, nr, i;
|
unsigned int bitnr, nr, i;
|
||||||
@ -548,7 +605,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
|
|||||||
replay_esn->bmp[nr] |= (1U << bitnr);
|
replay_esn->bmp[nr] |= (1U << bitnr);
|
||||||
|
|
||||||
if (xfrm_aevent_is_on(xs_net(x)))
|
if (xfrm_aevent_is_on(xs_net(x)))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XFRM_OFFLOAD
|
#ifdef CONFIG_XFRM_OFFLOAD
|
||||||
@ -560,7 +617,7 @@ static int xfrm_replay_overflow_offload(struct xfrm_state *x, struct sk_buff *sk
|
|||||||
__u32 oseq = x->replay.oseq;
|
__u32 oseq = x->replay.oseq;
|
||||||
|
|
||||||
if (!xo)
|
if (!xo)
|
||||||
return xfrm_replay_overflow(x, skb);
|
return __xfrm_replay_overflow(x, skb);
|
||||||
|
|
||||||
if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
|
if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
|
||||||
if (!skb_is_gso(skb)) {
|
if (!skb_is_gso(skb)) {
|
||||||
@ -585,7 +642,7 @@ static int xfrm_replay_overflow_offload(struct xfrm_state *x, struct sk_buff *sk
|
|||||||
x->replay.oseq = oseq;
|
x->replay.oseq = oseq;
|
||||||
|
|
||||||
if (xfrm_aevent_is_on(net))
|
if (xfrm_aevent_is_on(net))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -625,7 +682,7 @@ static int xfrm_replay_overflow_offload_bmp(struct xfrm_state *x, struct sk_buff
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xfrm_aevent_is_on(net))
|
if (xfrm_aevent_is_on(net))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -674,59 +731,39 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff
|
|||||||
replay_esn->oseq = oseq;
|
replay_esn->oseq = oseq;
|
||||||
|
|
||||||
if (xfrm_aevent_is_on(net))
|
if (xfrm_aevent_is_on(net))
|
||||||
x->repl->notify(x, XFRM_REPLAY_UPDATE);
|
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct xfrm_replay xfrm_replay_legacy = {
|
int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
.advance = xfrm_replay_advance,
|
{
|
||||||
.check = xfrm_replay_check,
|
switch (x->repl_mode) {
|
||||||
.recheck = xfrm_replay_check,
|
case XFRM_REPLAY_MODE_LEGACY:
|
||||||
.notify = xfrm_replay_notify,
|
break;
|
||||||
.overflow = xfrm_replay_overflow_offload,
|
case XFRM_REPLAY_MODE_BMP:
|
||||||
};
|
return xfrm_replay_overflow_offload_bmp(x, skb);
|
||||||
|
case XFRM_REPLAY_MODE_ESN:
|
||||||
|
return xfrm_replay_overflow_offload_esn(x, skb);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct xfrm_replay xfrm_replay_bmp = {
|
return xfrm_replay_overflow_offload(x, skb);
|
||||||
.advance = xfrm_replay_advance_bmp,
|
}
|
||||||
.check = xfrm_replay_check_bmp,
|
|
||||||
.recheck = xfrm_replay_check_bmp,
|
|
||||||
.notify = xfrm_replay_notify_bmp,
|
|
||||||
.overflow = xfrm_replay_overflow_offload_bmp,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct xfrm_replay xfrm_replay_esn = {
|
|
||||||
.advance = xfrm_replay_advance_esn,
|
|
||||||
.check = xfrm_replay_check_esn,
|
|
||||||
.recheck = xfrm_replay_recheck_esn,
|
|
||||||
.notify = xfrm_replay_notify_esn,
|
|
||||||
.overflow = xfrm_replay_overflow_offload_esn,
|
|
||||||
};
|
|
||||||
#else
|
#else
|
||||||
static const struct xfrm_replay xfrm_replay_legacy = {
|
int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
.advance = xfrm_replay_advance,
|
{
|
||||||
.check = xfrm_replay_check,
|
switch (x->repl_mode) {
|
||||||
.recheck = xfrm_replay_check,
|
case XFRM_REPLAY_MODE_LEGACY:
|
||||||
.notify = xfrm_replay_notify,
|
break;
|
||||||
.overflow = xfrm_replay_overflow,
|
case XFRM_REPLAY_MODE_BMP:
|
||||||
};
|
return xfrm_replay_overflow_bmp(x, skb);
|
||||||
|
case XFRM_REPLAY_MODE_ESN:
|
||||||
|
return xfrm_replay_overflow_esn(x, skb);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct xfrm_replay xfrm_replay_bmp = {
|
return __xfrm_replay_overflow(x, skb);
|
||||||
.advance = xfrm_replay_advance_bmp,
|
}
|
||||||
.check = xfrm_replay_check_bmp,
|
|
||||||
.recheck = xfrm_replay_check_bmp,
|
|
||||||
.notify = xfrm_replay_notify_bmp,
|
|
||||||
.overflow = xfrm_replay_overflow_bmp,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct xfrm_replay xfrm_replay_esn = {
|
|
||||||
.advance = xfrm_replay_advance_esn,
|
|
||||||
.check = xfrm_replay_check_esn,
|
|
||||||
.recheck = xfrm_replay_recheck_esn,
|
|
||||||
.notify = xfrm_replay_notify_esn,
|
|
||||||
.overflow = xfrm_replay_overflow_esn,
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int xfrm_init_replay(struct xfrm_state *x)
|
int xfrm_init_replay(struct xfrm_state *x)
|
||||||
@ -741,12 +778,12 @@ int xfrm_init_replay(struct xfrm_state *x)
|
|||||||
if (x->props.flags & XFRM_STATE_ESN) {
|
if (x->props.flags & XFRM_STATE_ESN) {
|
||||||
if (replay_esn->replay_window == 0)
|
if (replay_esn->replay_window == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
x->repl = &xfrm_replay_esn;
|
x->repl_mode = XFRM_REPLAY_MODE_ESN;
|
||||||
} else {
|
} else {
|
||||||
x->repl = &xfrm_replay_bmp;
|
x->repl_mode = XFRM_REPLAY_MODE_BMP;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
x->repl = &xfrm_replay_legacy;
|
x->repl_mode = XFRM_REPLAY_MODE_LEGACY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -78,10 +78,16 @@ xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr,
|
|||||||
return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
|
return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int xfrm_seq_hash(struct net *net, u32 seq)
|
||||||
|
{
|
||||||
|
return __xfrm_seq_hash(seq, net->xfrm.state_hmask);
|
||||||
|
}
|
||||||
|
|
||||||
static void xfrm_hash_transfer(struct hlist_head *list,
|
static void xfrm_hash_transfer(struct hlist_head *list,
|
||||||
struct hlist_head *ndsttable,
|
struct hlist_head *ndsttable,
|
||||||
struct hlist_head *nsrctable,
|
struct hlist_head *nsrctable,
|
||||||
struct hlist_head *nspitable,
|
struct hlist_head *nspitable,
|
||||||
|
struct hlist_head *nseqtable,
|
||||||
unsigned int nhashmask)
|
unsigned int nhashmask)
|
||||||
{
|
{
|
||||||
struct hlist_node *tmp;
|
struct hlist_node *tmp;
|
||||||
@ -106,6 +112,11 @@ static void xfrm_hash_transfer(struct hlist_head *list,
|
|||||||
nhashmask);
|
nhashmask);
|
||||||
hlist_add_head_rcu(&x->byspi, nspitable + h);
|
hlist_add_head_rcu(&x->byspi, nspitable + h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (x->km.seq) {
|
||||||
|
h = __xfrm_seq_hash(x->km.seq, nhashmask);
|
||||||
|
hlist_add_head_rcu(&x->byseq, nseqtable + h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +128,7 @@ static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
|
|||||||
static void xfrm_hash_resize(struct work_struct *work)
|
static void xfrm_hash_resize(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct net *net = container_of(work, struct net, xfrm.state_hash_work);
|
struct net *net = container_of(work, struct net, xfrm.state_hash_work);
|
||||||
struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
|
struct hlist_head *ndst, *nsrc, *nspi, *nseq, *odst, *osrc, *ospi, *oseq;
|
||||||
unsigned long nsize, osize;
|
unsigned long nsize, osize;
|
||||||
unsigned int nhashmask, ohashmask;
|
unsigned int nhashmask, ohashmask;
|
||||||
int i;
|
int i;
|
||||||
@ -137,6 +148,13 @@ static void xfrm_hash_resize(struct work_struct *work)
|
|||||||
xfrm_hash_free(nsrc, nsize);
|
xfrm_hash_free(nsrc, nsize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
nseq = xfrm_hash_alloc(nsize);
|
||||||
|
if (!nseq) {
|
||||||
|
xfrm_hash_free(ndst, nsize);
|
||||||
|
xfrm_hash_free(nsrc, nsize);
|
||||||
|
xfrm_hash_free(nspi, nsize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock_bh(&net->xfrm.xfrm_state_lock);
|
spin_lock_bh(&net->xfrm.xfrm_state_lock);
|
||||||
write_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
|
write_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
|
||||||
@ -144,15 +162,17 @@ static void xfrm_hash_resize(struct work_struct *work)
|
|||||||
nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
|
nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
|
||||||
odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net);
|
odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net);
|
||||||
for (i = net->xfrm.state_hmask; i >= 0; i--)
|
for (i = net->xfrm.state_hmask; i >= 0; i--)
|
||||||
xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask);
|
xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nseq, nhashmask);
|
||||||
|
|
||||||
osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net);
|
osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net);
|
||||||
ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net);
|
ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net);
|
||||||
|
oseq = xfrm_state_deref_prot(net->xfrm.state_byseq, net);
|
||||||
ohashmask = net->xfrm.state_hmask;
|
ohashmask = net->xfrm.state_hmask;
|
||||||
|
|
||||||
rcu_assign_pointer(net->xfrm.state_bydst, ndst);
|
rcu_assign_pointer(net->xfrm.state_bydst, ndst);
|
||||||
rcu_assign_pointer(net->xfrm.state_bysrc, nsrc);
|
rcu_assign_pointer(net->xfrm.state_bysrc, nsrc);
|
||||||
rcu_assign_pointer(net->xfrm.state_byspi, nspi);
|
rcu_assign_pointer(net->xfrm.state_byspi, nspi);
|
||||||
|
rcu_assign_pointer(net->xfrm.state_byseq, nseq);
|
||||||
net->xfrm.state_hmask = nhashmask;
|
net->xfrm.state_hmask = nhashmask;
|
||||||
|
|
||||||
write_seqcount_end(&net->xfrm.xfrm_state_hash_generation);
|
write_seqcount_end(&net->xfrm.xfrm_state_hash_generation);
|
||||||
@ -165,6 +185,7 @@ static void xfrm_hash_resize(struct work_struct *work)
|
|||||||
xfrm_hash_free(odst, osize);
|
xfrm_hash_free(odst, osize);
|
||||||
xfrm_hash_free(osrc, osize);
|
xfrm_hash_free(osrc, osize);
|
||||||
xfrm_hash_free(ospi, osize);
|
xfrm_hash_free(ospi, osize);
|
||||||
|
xfrm_hash_free(oseq, osize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
|
static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
|
||||||
@ -621,6 +642,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
|
|||||||
INIT_HLIST_NODE(&x->bydst);
|
INIT_HLIST_NODE(&x->bydst);
|
||||||
INIT_HLIST_NODE(&x->bysrc);
|
INIT_HLIST_NODE(&x->bysrc);
|
||||||
INIT_HLIST_NODE(&x->byspi);
|
INIT_HLIST_NODE(&x->byspi);
|
||||||
|
INIT_HLIST_NODE(&x->byseq);
|
||||||
hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
|
hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
|
||||||
x->mtimer.function = xfrm_timer_handler;
|
x->mtimer.function = xfrm_timer_handler;
|
||||||
timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0);
|
timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0);
|
||||||
@ -664,6 +686,8 @@ int __xfrm_state_delete(struct xfrm_state *x)
|
|||||||
list_del(&x->km.all);
|
list_del(&x->km.all);
|
||||||
hlist_del_rcu(&x->bydst);
|
hlist_del_rcu(&x->bydst);
|
||||||
hlist_del_rcu(&x->bysrc);
|
hlist_del_rcu(&x->bysrc);
|
||||||
|
if (x->km.seq)
|
||||||
|
hlist_del_rcu(&x->byseq);
|
||||||
if (x->id.spi)
|
if (x->id.spi)
|
||||||
hlist_del_rcu(&x->byspi);
|
hlist_del_rcu(&x->byspi);
|
||||||
net->xfrm.state_num--;
|
net->xfrm.state_num--;
|
||||||
@ -1148,6 +1172,10 @@ found:
|
|||||||
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
|
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
|
||||||
hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
|
hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
|
||||||
}
|
}
|
||||||
|
if (x->km.seq) {
|
||||||
|
h = xfrm_seq_hash(net, x->km.seq);
|
||||||
|
hlist_add_head_rcu(&x->byseq, net->xfrm.state_byseq + h);
|
||||||
|
}
|
||||||
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
|
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
|
||||||
hrtimer_start(&x->mtimer,
|
hrtimer_start(&x->mtimer,
|
||||||
ktime_set(net->xfrm.sysctl_acq_expires, 0),
|
ktime_set(net->xfrm.sysctl_acq_expires, 0),
|
||||||
@ -1263,6 +1291,12 @@ static void __xfrm_state_insert(struct xfrm_state *x)
|
|||||||
hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
|
hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (x->km.seq) {
|
||||||
|
h = xfrm_seq_hash(net, x->km.seq);
|
||||||
|
|
||||||
|
hlist_add_head_rcu(&x->byseq, net->xfrm.state_byseq + h);
|
||||||
|
}
|
||||||
|
|
||||||
hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
|
hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
|
||||||
if (x->replay_maxage)
|
if (x->replay_maxage)
|
||||||
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
|
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
|
||||||
@ -1932,20 +1966,18 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
|
|||||||
|
|
||||||
static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
|
static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int h = xfrm_seq_hash(net, seq);
|
||||||
|
struct xfrm_state *x;
|
||||||
|
|
||||||
for (i = 0; i <= net->xfrm.state_hmask; i++) {
|
hlist_for_each_entry_rcu(x, net->xfrm.state_byseq + h, byseq) {
|
||||||
struct xfrm_state *x;
|
if (x->km.seq == seq &&
|
||||||
|
(mark & x->mark.m) == x->mark.v &&
|
||||||
hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
|
x->km.state == XFRM_STATE_ACQ) {
|
||||||
if (x->km.seq == seq &&
|
xfrm_state_hold(x);
|
||||||
(mark & x->mark.m) == x->mark.v &&
|
return x;
|
||||||
x->km.state == XFRM_STATE_ACQ) {
|
|
||||||
xfrm_state_hold(x);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2145,7 +2177,7 @@ static void xfrm_replay_timer_handler(struct timer_list *t)
|
|||||||
|
|
||||||
if (x->km.state == XFRM_STATE_VALID) {
|
if (x->km.state == XFRM_STATE_VALID) {
|
||||||
if (xfrm_aevent_is_on(xs_net(x)))
|
if (xfrm_aevent_is_on(xs_net(x)))
|
||||||
x->repl->notify(x, XFRM_REPLAY_TIMEOUT);
|
xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
|
||||||
else
|
else
|
||||||
x->xflags |= XFRM_TIME_DEFER;
|
x->xflags |= XFRM_TIME_DEFER;
|
||||||
}
|
}
|
||||||
@ -2660,6 +2692,9 @@ int __net_init xfrm_state_init(struct net *net)
|
|||||||
net->xfrm.state_byspi = xfrm_hash_alloc(sz);
|
net->xfrm.state_byspi = xfrm_hash_alloc(sz);
|
||||||
if (!net->xfrm.state_byspi)
|
if (!net->xfrm.state_byspi)
|
||||||
goto out_byspi;
|
goto out_byspi;
|
||||||
|
net->xfrm.state_byseq = xfrm_hash_alloc(sz);
|
||||||
|
if (!net->xfrm.state_byseq)
|
||||||
|
goto out_byseq;
|
||||||
net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
|
net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
|
||||||
|
|
||||||
net->xfrm.state_num = 0;
|
net->xfrm.state_num = 0;
|
||||||
@ -2669,6 +2704,8 @@ int __net_init xfrm_state_init(struct net *net)
|
|||||||
&net->xfrm.xfrm_state_lock);
|
&net->xfrm.xfrm_state_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_byseq:
|
||||||
|
xfrm_hash_free(net->xfrm.state_byspi, sz);
|
||||||
out_byspi:
|
out_byspi:
|
||||||
xfrm_hash_free(net->xfrm.state_bysrc, sz);
|
xfrm_hash_free(net->xfrm.state_bysrc, sz);
|
||||||
out_bysrc:
|
out_bysrc:
|
||||||
@ -2688,6 +2725,8 @@ void xfrm_state_fini(struct net *net)
|
|||||||
WARN_ON(!list_empty(&net->xfrm.state_all));
|
WARN_ON(!list_empty(&net->xfrm.state_all));
|
||||||
|
|
||||||
sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
|
sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
|
||||||
|
WARN_ON(!hlist_empty(net->xfrm.state_byseq));
|
||||||
|
xfrm_hash_free(net->xfrm.state_byseq, sz);
|
||||||
WARN_ON(!hlist_empty(net->xfrm.state_byspi));
|
WARN_ON(!hlist_empty(net->xfrm.state_byspi));
|
||||||
xfrm_hash_free(net->xfrm.state_byspi, sz);
|
xfrm_hash_free(net->xfrm.state_byspi, sz);
|
||||||
WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
|
WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
|
||||||
|
Loading…
Reference in New Issue
Block a user