diff --git a/Makefile.am b/Makefile.am index 0e5998ae..ff2ce329 100644 --- a/Makefile.am +++ b/Makefile.am @@ -315,6 +315,7 @@ noinst_HEADERS = \ include/linux-private/linux/xfrm.h \ include/nl-aux-core/nl-core.h \ include/nl-aux-route/nl-route.h \ + include/nl-aux-xfrm/nl-xfrm.h \ include/nl-default.h \ include/nl-priv-dynamic-core/cache-api.h \ include/nl-priv-dynamic-core/nl-core.h \ diff --git a/include/base/nl-base-utils.h b/include/base/nl-base-utils.h index fb6bdf2d..6dd9c49f 100644 --- a/include/base/nl-base-utils.h +++ b/include/base/nl-base-utils.h @@ -663,6 +663,17 @@ static inline void *_nl_memdup(const void *ptr, size_t len) /*****************************************************************************/ +static inline size_t _nl_addr_family_to_size(int addr_family) +{ + if (addr_family == AF_INET) + return sizeof(in_addr_t); + if (addr_family == AF_INET6) + return sizeof(struct in6_addr); + return 0; +} + +/*****************************************************************************/ + typedef union { in_addr_t addr4; struct in_addr a4; diff --git a/include/nl-aux-core/nl-core.h b/include/nl-aux-core/nl-core.h index 36bce3a0..5b34bcb0 100644 --- a/include/nl-aux-core/nl-core.h +++ b/include/nl-aux-core/nl-core.h @@ -49,4 +49,11 @@ void nl_socket_free(struct nl_sock *); _NL_AUTO_DEFINE_FCN_TYPED0(struct nl_sock *, _nl_auto_nl_socket_fcn, nl_socket_free); +struct nl_addr *nl_addr_build(int, const void *, size_t); + +static inline struct nl_addr *_nl_addr_build(int family, const void *buf) +{ + return nl_addr_build(family, buf, _nl_addr_family_to_size(family)); +} + #endif /* NETLINK_NL_AUTO_H_ */ diff --git a/include/nl-aux-xfrm/README.md b/include/nl-aux-xfrm/README.md new file mode 100644 index 00000000..9a4b6e2f --- /dev/null +++ b/include/nl-aux-xfrm/README.md @@ -0,0 +1,18 @@ +include/nl-aux-xfrm +=================== + +This contains private/internal helpers that depend on the public libnl-3 (core) +and libnl-xfrm-3. + +Itself, it must only rely on C, include/base/ and public headers of libnl-3 (core) +and libnl-xfrm-3. + +They can be used by all internal code that uses the public API of both libnl-3 (core) +and libnl-xfrm-3. + +It can also be used by lib/xfrm itself (that is, the implementation of +libnl-xfrm-3). + +It must not be used in public headers, it's internal only. + +Currently this is header-only, it does not require any additional linking. diff --git a/include/nl-aux-xfrm/nl-xfrm.h b/include/nl-aux-xfrm/nl-xfrm.h new file mode 100644 index 00000000..0f7e7a71 --- /dev/null +++ b/include/nl-aux-xfrm/nl-xfrm.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ + +#ifndef __NETLINK_NL_AUX_XFRM_NL_XFRM_H__ +#define __NETLINK_NL_AUX_XFRM_NL_XFRM_H__ + +#include "base/nl-base-utils.h" + +struct xfrmnl_sp; +void xfrmnl_sp_put(struct xfrmnl_sp *sp); +#define _nl_auto_xfrmnl_sp _nl_auto(_nl_auto_xfrmnl_sp_fcn) +_NL_AUTO_DEFINE_FCN_TYPED0(struct xfrmnl_sp *, _nl_auto_xfrmnl_sp_fcn, + xfrmnl_sp_put); + +struct xfrmnl_sa; +void xfrmnl_sa_put(struct xfrmnl_sa *sa); +#define _nl_auto_xfrmnl_sa _nl_auto(_nl_auto_xfrmnl_sa_fcn) +_NL_AUTO_DEFINE_FCN_TYPED0(struct xfrmnl_sa *, _nl_auto_xfrmnl_sa_fcn, + xfrmnl_sa_put); + +struct xfrmnl_ae; +void xfrmnl_ae_put(struct xfrmnl_ae *ae); +#define _nl_auto_xfrmnl_ae _nl_auto(_nl_auto_xfrmnl_ae_fcn) +_NL_AUTO_DEFINE_FCN_TYPED0(struct xfrmnl_ae *, _nl_auto_xfrmnl_ae_fcn, + xfrmnl_ae_put); + +#endif /* __NETLINK_NL_AUX_XFRM_NL_XFRM_H__ */ diff --git a/lib/xfrm/ae.c b/lib/xfrm/ae.c index 4f56690e..9af73a87 100644 --- a/lib/xfrm/ae.c +++ b/lib/xfrm/ae.c @@ -133,6 +133,8 @@ #include "nl-priv-dynamic-core/object-api.h" #include "nl-priv-dynamic-core/nl-core.h" #include "nl-priv-dynamic-core/cache-api.h" +#include "nl-aux-core/nl-core.h" +#include "nl-aux-xfrm/nl-xfrm.h" /** @cond SKIP */ @@ -522,29 +524,30 @@ static struct nla_policy xfrm_ae_policy[XFRMA_MAX+1] = { int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result) { - struct xfrmnl_ae* ae; + _nl_auto_xfrmnl_ae struct xfrmnl_ae *ae = NULL; struct nlattr *tb[XFRMA_MAX + 1]; struct xfrm_aevent_id* ae_id; int err; ae = xfrmnl_ae_alloc(); - if (!ae) { - err = -NLE_NOMEM; - goto errout; - } + if (!ae) + return -NLE_NOMEM; ae->ce_msgtype = n->nlmsg_type; ae_id = nlmsg_data(n); err = nlmsg_parse(n, sizeof(struct xfrm_aevent_id), tb, XFRMA_MAX, xfrm_ae_policy); if (err < 0) - goto errout; + return err; - ae->sa_id.daddr = nl_addr_build(ae_id->sa_id.family, &ae_id->sa_id.daddr, sizeof (ae_id->sa_id.daddr)); + if (!(ae->sa_id.daddr = + _nl_addr_build(ae_id->sa_id.family, &ae_id->sa_id.daddr))) + return -NLE_NOMEM; ae->sa_id.family= ae_id->sa_id.family; ae->sa_id.spi = ntohl(ae_id->sa_id.spi); ae->sa_id.proto = ae_id->sa_id.proto; - ae->saddr = nl_addr_build(ae_id->sa_id.family, &ae_id->saddr, sizeof (ae_id->saddr)); + if (!(ae->saddr = _nl_addr_build(ae_id->sa_id.family, &ae_id->saddr))) + return -NLE_NOMEM; ae->reqid = ae_id->reqid; ae->flags = ae_id->flags; ae->ce_mask |= (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_FAMILY | XFRM_AE_ATTR_SPI | @@ -560,6 +563,7 @@ int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result) if (tb[XFRMA_LTIME_VAL]) { struct xfrm_lifetime_cur* cur = nla_data(tb[XFRMA_LTIME_VAL]); + ae->lifetime_cur.bytes = cur->bytes; ae->lifetime_cur.packets = cur->packets; ae->lifetime_cur.add_time = cur->add_time; @@ -581,10 +585,8 @@ int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result) struct xfrm_replay_state_esn* esn = nla_data (tb[XFRMA_REPLAY_ESN_VAL]); uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * esn->bmp_len); - if ((ae->replay_state_esn = calloc (1, len)) == NULL) { - err = -ENOMEM; - goto errout; - } + if ((ae->replay_state_esn = calloc (1, len)) == NULL) + return -NLE_NOMEM; ae->replay_state_esn->oseq = esn->oseq; ae->replay_state_esn->seq = esn->seq; ae->replay_state_esn->oseq_hi = esn->oseq_hi; @@ -605,12 +607,8 @@ int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result) ae->replay_state_esn = NULL; } - *result = ae; + *result = _nl_steal_pointer(&ae); return 0; - -errout: - xfrmnl_ae_put(ae); - return err; } static int xfrm_ae_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, diff --git a/lib/xfrm/sa.c b/lib/xfrm/sa.c index 44faa896..0970b441 100644 --- a/lib/xfrm/sa.c +++ b/lib/xfrm/sa.c @@ -54,6 +54,8 @@ #include "nl-priv-dynamic-core/object-api.h" #include "nl-priv-dynamic-core/nl-core.h" #include "nl-priv-dynamic-core/cache-api.h" +#include "nl-aux-core/nl-core.h" +#include "nl-aux-xfrm/nl-xfrm.h" /** @cond SKIP */ @@ -770,18 +772,17 @@ static int xfrm_sa_request_update(struct nl_cache *c, struct nl_sock *h) int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) { - struct xfrmnl_sa* sa; + _nl_auto_nl_addr struct nl_addr *addr1 = NULL; + _nl_auto_nl_addr struct nl_addr *addr2 = NULL; + _nl_auto_xfrmnl_sa struct xfrmnl_sa *sa = NULL; struct nlattr *tb[XFRMA_MAX + 1]; struct xfrm_usersa_info* sa_info; struct xfrm_user_expire* ue; int len, err; - struct nl_addr* addr; sa = xfrmnl_sa_alloc(); - if (!sa) { - err = -NLE_NOMEM; - goto errout; - } + if (!sa) + return -NLE_NOMEM; sa->ce_msgtype = n->nlmsg_type; if (n->nlmsg_type == XFRM_MSG_EXPIRE) @@ -802,26 +803,18 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) err = nlmsg_parse(n, sizeof(struct xfrm_usersa_info), tb, XFRMA_MAX, xfrm_sa_policy); if (err < 0) - goto errout; + return err; - if (sa_info->sel.family == AF_INET) - addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.daddr.a4, sizeof (sa_info->sel.daddr.a4)); - else - addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.daddr.a6, sizeof (sa_info->sel.daddr.a6)); - nl_addr_set_prefixlen (addr, sa_info->sel.prefixlen_d); - xfrmnl_sel_set_daddr (sa->sel, addr); - /* Drop the reference count from the above set operation */ - nl_addr_put(addr); + if (!(addr1 = _nl_addr_build(sa_info->sel.family, &sa_info->sel.daddr))) + return -NLE_NOMEM; + nl_addr_set_prefixlen (addr1, sa_info->sel.prefixlen_d); + xfrmnl_sel_set_daddr (sa->sel, addr1); xfrmnl_sel_set_prefixlen_d (sa->sel, sa_info->sel.prefixlen_d); - if (sa_info->sel.family == AF_INET) - addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.saddr.a4, sizeof (sa_info->sel.saddr.a4)); - else - addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.saddr.a6, sizeof (sa_info->sel.saddr.a6)); - nl_addr_set_prefixlen (addr, sa_info->sel.prefixlen_s); - xfrmnl_sel_set_saddr (sa->sel, addr); - /* Drop the reference count from the above set operation */ - nl_addr_put(addr); + if (!(addr2 = _nl_addr_build(sa_info->sel.family, &sa_info->sel.saddr))) + return -NLE_NOMEM; + nl_addr_set_prefixlen (addr2, sa_info->sel.prefixlen_s); + xfrmnl_sel_set_saddr (sa->sel, addr2); xfrmnl_sel_set_prefixlen_s (sa->sel, sa_info->sel.prefixlen_s); xfrmnl_sel_set_dport (sa->sel, ntohs(sa_info->sel.dport)); @@ -834,18 +827,14 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) xfrmnl_sel_set_userid (sa->sel, sa_info->sel.user); sa->ce_mask |= XFRM_SA_ATTR_SEL; - if (sa_info->family == AF_INET) - sa->id.daddr = nl_addr_build (sa_info->family, &sa_info->id.daddr.a4, sizeof (sa_info->id.daddr.a4)); - else - sa->id.daddr = nl_addr_build (sa_info->family, &sa_info->id.daddr.a6, sizeof (sa_info->id.daddr.a6)); + if (!(sa->id.daddr = _nl_addr_build(sa_info->family, &sa_info->id.daddr))) + return -NLE_NOMEM; sa->id.spi = ntohl(sa_info->id.spi); sa->id.proto = sa_info->id.proto; sa->ce_mask |= (XFRM_SA_ATTR_DADDR | XFRM_SA_ATTR_SPI | XFRM_SA_ATTR_PROTO); - if (sa_info->family == AF_INET) - sa->saddr = nl_addr_build (sa_info->family, &sa_info->saddr.a4, sizeof (sa_info->saddr.a4)); - else - sa->saddr = nl_addr_build (sa_info->family, &sa_info->saddr.a6, sizeof (sa_info->saddr.a6)); + if (!(sa->saddr = _nl_addr_build(sa_info->family, &sa_info->saddr))) + return -NLE_NOMEM; sa->ce_mask |= XFRM_SA_ATTR_SADDR; sa->lft->soft_byte_limit = sa_info->lft.soft_byte_limit; @@ -881,36 +870,30 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) if (tb[XFRMA_ALG_AEAD]) { struct xfrm_algo_aead* aead = nla_data(tb[XFRMA_ALG_AEAD]); + len = sizeof (struct xfrmnl_algo_aead) + ((aead->alg_key_len + 7) / 8); if ((sa->aead = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy ((void *)sa->aead, (void *)aead, len); sa->ce_mask |= XFRM_SA_ATTR_ALG_AEAD; } if (tb[XFRMA_ALG_AUTH_TRUNC]) { struct xfrm_algo_auth* auth = nla_data(tb[XFRMA_ALG_AUTH_TRUNC]); + len = sizeof (struct xfrmnl_algo_auth) + ((auth->alg_key_len + 7) / 8); if ((sa->auth = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy ((void *)sa->auth, (void *)auth, len); sa->ce_mask |= XFRM_SA_ATTR_ALG_AUTH; } if (tb[XFRMA_ALG_AUTH] && !sa->auth) { struct xfrm_algo* auth = nla_data(tb[XFRMA_ALG_AUTH]); + len = sizeof (struct xfrmnl_algo_auth) + ((auth->alg_key_len + 7) / 8); if ((sa->auth = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; strcpy(sa->auth->alg_name, auth->alg_name); memcpy(sa->auth->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); sa->auth->alg_key_len = auth->alg_key_len; @@ -919,43 +902,36 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) if (tb[XFRMA_ALG_CRYPT]) { struct xfrm_algo* crypt = nla_data(tb[XFRMA_ALG_CRYPT]); + len = sizeof (struct xfrmnl_algo) + ((crypt->alg_key_len + 7) / 8); if ((sa->crypt = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy ((void *)sa->crypt, (void *)crypt, len); sa->ce_mask |= XFRM_SA_ATTR_ALG_CRYPT; } if (tb[XFRMA_ALG_COMP]) { struct xfrm_algo* comp = nla_data(tb[XFRMA_ALG_COMP]); + len = sizeof (struct xfrmnl_algo) + ((comp->alg_key_len + 7) / 8); if ((sa->comp = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy ((void *)sa->comp, (void *)comp, len); sa->ce_mask |= XFRM_SA_ATTR_ALG_COMP; } if (tb[XFRMA_ENCAP]) { struct xfrm_encap_tmpl* encap = nla_data(tb[XFRMA_ENCAP]); + len = sizeof (struct xfrmnl_encap_tmpl); if ((sa->encap = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; sa->encap->encap_type = encap->encap_type; sa->encap->encap_sport = ntohs(encap->encap_sport); sa->encap->encap_dport = ntohs(encap->encap_dport); - if (sa_info->family == AF_INET) - sa->encap->encap_oa = nl_addr_build (sa_info->family, &encap->encap_oa.a4, sizeof (encap->encap_oa.a4)); - else - sa->encap->encap_oa = nl_addr_build (sa_info->family, &encap->encap_oa.a6, sizeof (encap->encap_oa.a6)); + if (!(sa->encap->encap_oa = _nl_addr_build(sa_info->family, + &encap->encap_oa))) + return -NLE_NOMEM; sa->ce_mask |= XFRM_SA_ATTR_ENCAP; } @@ -965,21 +941,15 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) } if (tb[XFRMA_COADDR]) { - if (sa_info->family == AF_INET) - { - sa->coaddr = nl_addr_build(sa_info->family, nla_data(tb[XFRMA_COADDR]), - sizeof (uint32_t)); - } - else - { - sa->coaddr = nl_addr_build(sa_info->family, nla_data(tb[XFRMA_COADDR]), - sizeof (uint32_t) * 4); - } + if (!(sa->coaddr = _nl_addr_build( + sa_info->family, nla_data(tb[XFRMA_COADDR])))) + return -NLE_NOMEM; sa->ce_mask |= XFRM_SA_ATTR_COADDR; } if (tb[XFRMA_MARK]) { struct xfrm_mark* m = nla_data(tb[XFRMA_MARK]); + sa->mark.m = m->m; sa->mark.v = m->v; sa->ce_mask |= XFRM_SA_ATTR_MARK; @@ -987,12 +957,10 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) if (tb[XFRMA_SEC_CTX]) { struct xfrm_user_sec_ctx* sec_ctx = nla_data(tb[XFRMA_SEC_CTX]); + len = sizeof (struct xfrmnl_user_sec_ctx) + sec_ctx->ctx_len; if ((sa->sec_ctx = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy (sa->sec_ctx, sec_ctx, len); sa->ce_mask |= XFRM_SA_ATTR_SECCTX; } @@ -1009,12 +977,10 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) if (tb[XFRMA_REPLAY_ESN_VAL]) { struct xfrm_replay_state_esn* esn = nla_data (tb[XFRMA_REPLAY_ESN_VAL]); + len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * esn->bmp_len); if ((sa->replay_state_esn = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy ((void *)sa->replay_state_esn, (void *)esn, len); sa->ce_mask |= XFRM_SA_ATTR_REPLAY_STATE; } @@ -1032,24 +998,16 @@ int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result) struct xfrm_user_offload *offload; len = sizeof(struct xfrmnl_user_offload); - - if ((sa->user_offload = calloc(1, len)) == NULL) { - err = -NLE_NOMEM; - goto errout; - } - + if ((sa->user_offload = calloc(1, len)) == NULL) + return -NLE_NOMEM; offload = nla_data(tb[XFRMA_OFFLOAD_DEV]); sa->user_offload->ifindex = offload->ifindex; sa->user_offload->flags = offload->flags; sa->ce_mask |= XFRM_SA_ATTR_OFFLOAD_DEV; } - *result = sa; + *result = _nl_steal_pointer(&sa); return 0; - -errout: - xfrmnl_sa_put(sa); - return err; } static int xfrm_sa_update_cache (struct nl_cache *cache, struct nl_object *obj, diff --git a/lib/xfrm/sp.c b/lib/xfrm/sp.c index 5a96ac93..e98339c0 100644 --- a/lib/xfrm/sp.c +++ b/lib/xfrm/sp.c @@ -53,6 +53,8 @@ #include "nl-priv-dynamic-core/object-api.h" #include "nl-priv-dynamic-core/nl-core.h" #include "nl-priv-dynamic-core/cache-api.h" +#include "nl-aux-core/nl-core.h" +#include "nl-aux-xfrm/nl-xfrm.h" struct xfrmnl_userpolicy_type { uint8_t type; @@ -561,53 +563,37 @@ static int xfrm_sp_request_update(struct nl_cache *c, struct nl_sock *h) int xfrmnl_sp_parse(struct nlmsghdr *n, struct xfrmnl_sp **result) { - struct xfrmnl_sp *sp; + _nl_auto_nl_addr struct nl_addr *addr1 = NULL; + _nl_auto_nl_addr struct nl_addr *addr2 = NULL; + _nl_auto_xfrmnl_sp struct xfrmnl_sp *sp = NULL; struct nlattr *tb[XFRMA_MAX + 1]; struct xfrm_userpolicy_info *sp_info; int len, err; - struct nl_addr* addr; sp = xfrmnl_sp_alloc(); - if (!sp) { - err = -NLE_NOMEM; - goto errout; - } + if (!sp) + return -NLE_NOMEM; sp->ce_msgtype = n->nlmsg_type; if (n->nlmsg_type == XFRM_MSG_DELPOLICY) - { sp_info = (struct xfrm_userpolicy_info*)((char *)nlmsg_data(n) + sizeof (struct xfrm_userpolicy_id) + NLA_HDRLEN); - } else - { sp_info = nlmsg_data(n); - } err = nlmsg_parse(n, sizeof(struct xfrm_userpolicy_info), tb, XFRMA_MAX, xfrm_sp_policy); if (err < 0) - { - printf ("parse error: %d \n", err); - goto errout; - } + return err; - if (sp_info->sel.family == AF_INET) - addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.daddr.a4, sizeof (sp_info->sel.daddr.a4)); - else - addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.daddr.a6, sizeof (sp_info->sel.daddr.a6)); - nl_addr_set_prefixlen (addr, sp_info->sel.prefixlen_d); - xfrmnl_sel_set_daddr (sp->sel, addr); - /* Drop the reference count from the above set operation */ - nl_addr_put(addr); + if (!(addr1 = _nl_addr_build(sp_info->sel.family, &sp_info->sel.daddr))) + return -NLE_NOMEM; + nl_addr_set_prefixlen (addr1, sp_info->sel.prefixlen_d); + xfrmnl_sel_set_daddr (sp->sel, addr1); xfrmnl_sel_set_prefixlen_d (sp->sel, sp_info->sel.prefixlen_d); - if (sp_info->sel.family == AF_INET) - addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.saddr.a4, sizeof (sp_info->sel.saddr.a4)); - else - addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.saddr.a6, sizeof (sp_info->sel.saddr.a6)); - nl_addr_set_prefixlen (addr, sp_info->sel.prefixlen_s); - xfrmnl_sel_set_saddr (sp->sel, addr); - /* Drop the reference count from the above set operation */ - nl_addr_put(addr); + if (!(addr2 = _nl_addr_build(sp_info->sel.family, &sp_info->sel.saddr))) + return -NLE_NOMEM; + nl_addr_set_prefixlen (addr2, sp_info->sel.prefixlen_s); + xfrmnl_sel_set_saddr (sp->sel, addr2); xfrmnl_sel_set_prefixlen_s (sp->sel, sp_info->sel.prefixlen_s); xfrmnl_sel_set_dport (sp->sel, ntohs (sp_info->sel.dport)); @@ -648,18 +634,17 @@ int xfrmnl_sp_parse(struct nlmsghdr *n, struct xfrmnl_sp **result) if (tb[XFRMA_SEC_CTX]) { struct xfrm_user_sec_ctx* ctx = nla_data(tb[XFRMA_SEC_CTX]); + len = sizeof (struct xfrmnl_user_sec_ctx) + ctx->ctx_len; if ((sp->sec_ctx = calloc (1, len)) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } + return -NLE_NOMEM; memcpy ((void *)sp->sec_ctx, (void *)ctx, len); sp->ce_mask |= XFRM_SP_ATTR_SECCTX; } if (tb[XFRMA_POLICY_TYPE]) { struct xfrm_userpolicy_type* up = nla_data(tb[XFRMA_POLICY_TYPE]); + memcpy ((void *)&sp->uptype, (void *)up, sizeof (struct xfrm_userpolicy_type)); sp->ce_mask |= XFRM_SP_ATTR_POLTYPE; } @@ -669,34 +654,25 @@ int xfrmnl_sp_parse(struct nlmsghdr *n, struct xfrmnl_sp **result) struct xfrmnl_user_tmpl* sputmpl; uint32_t i; uint32_t num_tmpls = nla_len(tb[XFRMA_TMPL]) / sizeof (*tmpl); - struct nl_addr* addr; for (i = 0; (i < num_tmpls) && (tmpl); i ++, tmpl++) { + _nl_auto_nl_addr struct nl_addr *addr1 = NULL; + _nl_auto_nl_addr struct nl_addr *addr2 = NULL; + if ((sputmpl = xfrmnl_user_tmpl_alloc ()) == NULL) - { - err = -NLE_NOMEM; - goto errout; - } - - if (tmpl->family == AF_INET) - addr = nl_addr_build(tmpl->family, &tmpl->id.daddr.a4, sizeof (tmpl->id.daddr.a4)); - else - addr = nl_addr_build(tmpl->family, &tmpl->id.daddr.a6, sizeof (tmpl->id.daddr.a6)); - xfrmnl_user_tmpl_set_daddr (sputmpl, addr); - /* Drop the reference count from the above set operation */ - nl_addr_put(addr); + return -NLE_NOMEM; + + if (!(addr1 = _nl_addr_build(tmpl->family, &tmpl->id.daddr))) + return -NLE_NOMEM; + xfrmnl_user_tmpl_set_daddr (sputmpl, addr1); xfrmnl_user_tmpl_set_spi (sputmpl, ntohl(tmpl->id.spi)); xfrmnl_user_tmpl_set_proto (sputmpl, tmpl->id.proto); xfrmnl_user_tmpl_set_family (sputmpl, tmpl->family); - if (tmpl->family == AF_INET) - addr = nl_addr_build(tmpl->family, &tmpl->saddr.a4, sizeof (tmpl->saddr.a4)); - else - addr = nl_addr_build(tmpl->family, &tmpl->saddr.a6, sizeof (tmpl->saddr.a6)); - xfrmnl_user_tmpl_set_saddr (sputmpl, addr); - /* Drop the reference count from the above set operation */ - nl_addr_put(addr); + if (!(addr2 = _nl_addr_build(tmpl->family, &tmpl->saddr))) + return -NLE_NOMEM; + xfrmnl_user_tmpl_set_saddr (sputmpl, addr2); xfrmnl_user_tmpl_set_reqid (sputmpl, tmpl->reqid); xfrmnl_user_tmpl_set_mode (sputmpl, tmpl->mode); @@ -718,12 +694,8 @@ int xfrmnl_sp_parse(struct nlmsghdr *n, struct xfrmnl_sp **result) sp->ce_mask |= XFRM_SP_ATTR_MARK; } - *result = sp; + *result = _nl_steal_pointer(&sp); return 0; - -errout: - xfrmnl_sp_put(sp); - return err; } static int xfrm_sp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,