Use netlink_reserve() helper function in XFRM to simplify message construction
authorMartin Willi <martin@revosec.ch>
Fri, 15 Mar 2013 14:05:00 +0000 (15:05 +0100)
committerMartin Willi <martin@revosec.ch>
Fri, 15 Mar 2013 15:02:01 +0000 (16:02 +0100)
src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c

index 4752316..1c4b603 100644 (file)
 #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + \
                                                                                   NLMSG_ALIGN(sizeof(x))))
 /**
- * Returns a pointer to the next rtattr following rta.
- * !!! Do not use this to parse messages. Use RTA_NEXT and RTA_OK instead !!!
- */
-#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + \
-                                                                                        RTA_ALIGN((rta)->rta_len)))
-/**
  * Returns the total size of attached rta data
  * (after 'usual' netlink data x like 'struct xfrm_usersa_info')
  */
@@ -1223,8 +1217,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        sa->lft.soft_use_expires_seconds = 0;
        sa->lft.hard_use_expires_seconds = 0;
 
-       struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info);
-
        switch (enc_alg)
        {
                case ENCR_UNDEFINED:
@@ -1257,24 +1249,17 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
                                 encryption_algorithm_names, enc_alg, enc_key.len * 8);
 
-                       rthdr->rta_type = XFRMA_ALG_AEAD;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) +
-                                                                               enc_key.len);
-                       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +
-                                                        RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AEAD,
+                                                                  sizeof(*algo) + enc_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr);
                        algo->alg_key_len = enc_key.len * 8;
                        algo->alg_icv_len = icv_size;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                        algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
                        memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
-
-                       rthdr = XFRM_RTA_NEXT(rthdr);
                        break;
                }
                default:
@@ -1291,22 +1276,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
                                 encryption_algorithm_names, enc_alg, enc_key.len * 8);
 
-                       rthdr->rta_type = XFRMA_ALG_CRYPT;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len);
-                       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +
-                                                        RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_CRYPT,
+                                                                  sizeof(*algo) + enc_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo*)RTA_DATA(rthdr);
                        algo->alg_key_len = enc_key.len * 8;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                        algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
                        memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
-
-                       rthdr = XFRM_RTA_NEXT(rthdr);
                }
        }
 
@@ -1344,17 +1323,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                        /* the kernel uses SHA256 with 96 bit truncation by default,
                         * use specified truncation size supported by newer kernels.
                         * also use this for untruncated MD5 and SHA1. */
-                       rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) +
-                                                                               int_key.len);
-                       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +
-                                                        RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC,
+                                                                  sizeof(*algo) + int_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr);
                        algo->alg_key_len = int_key.len * 8;
                        algo->alg_trunc_len = trunc_len;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
@@ -1365,27 +1339,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                {
                        struct xfrm_algo* algo;
 
-                       rthdr->rta_type = XFRMA_ALG_AUTH;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len);
-                       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +
-                                                        RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH,
+                                                                  sizeof(*algo) + int_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo*)RTA_DATA(rthdr);
                        algo->alg_key_len = int_key.len * 8;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                        algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
                        memcpy(algo->alg_key, int_key.ptr, int_key.len);
                }
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (ipcomp != IPCOMP_NONE)
        {
-               rthdr->rta_type = XFRMA_ALG_COMP;
+               struct xfrm_algo* algo;
+
                alg_name = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp);
                if (alg_name == NULL)
                {
@@ -1396,34 +1366,26 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                DBG2(DBG_KNL, "  using compression algorithm %N",
                         ipcomp_transform_names, ipcomp);
 
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_COMP,
+                                                          sizeof(*algo));
+               if (!algo)
                {
                        goto failed;
                }
-
-               struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
                algo->alg_key_len = 0;
                strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
-
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (encap)
        {
                struct xfrm_encap_tmpl *tmpl;
 
-               rthdr->rta_type = XFRMA_ENCAP;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
+               if (!tmpl)
                {
                        goto failed;
                }
-
-               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
                tmpl->encap_type = UDP_ENCAP_ESPINUDP;
                tmpl->encap_sport = htons(src->get_port(src));
                tmpl->encap_dport = htons(dst->get_port(dst));
@@ -1438,43 +1400,32 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                 * No. The reason the kernel ignores NAT-OA is that it recomputes
                 * (or, rather, just ignores) the checksum. If packets pass the IPsec
                 * checks it marks them "checksum ok" so OA isn't needed. */
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (mark.value)
        {
                struct xfrm_mark *mrk;
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        goto failed;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (tfc)
        {
                u_int32_t *tfcpad;
 
-               rthdr->rta_type = XFRMA_TFCPAD;
-               rthdr->rta_len = RTA_LENGTH(sizeof(u_int32_t));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               tfcpad = netlink_reserve(hdr, sizeof(request), XFRMA_TFCPAD,
+                                                                sizeof(*tfcpad));
+               if (!tfcpad)
                {
                        goto failed;
                }
-
-               tfcpad = (u_int32_t*)RTA_DATA(rthdr);
                *tfcpad = tfc;
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (protocol != IPPROTO_COMP)
@@ -1485,24 +1436,18 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                         * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */
                        struct xfrm_replay_state_esn *replay;
 
-                       rthdr->rta_type = XFRMA_REPLAY_ESN_VAL;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) +
-                                                                               (this->replay_window + 7) / 8);
-                       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +
-                                                        RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       replay = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL,
+                                                       sizeof(*replay) + (this->replay_window + 7) / 8);
+                       if (!replay)
                        {
                                goto failed;
                        }
-
-                       replay = (struct xfrm_replay_state_esn*)RTA_DATA(rthdr);
                        /* bmp_len contains number uf __u32's */
                        replay->bmp_len = this->replay_bmp;
                        replay->replay_window = this->replay_window;
                        DBG2(DBG_KNL, "  using replay window of %u packets",
                                 this->replay_window);
 
-                       rthdr = XFRM_RTA_NEXT(rthdr);
                        if (esn)
                        {
                                DBG2(DBG_KNL, "  using extended sequence numbers (ESN)");
@@ -1577,17 +1522,12 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
        if (mark.value)
        {
                struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id);
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        return;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
        }
@@ -1678,17 +1618,12 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
        if (mark.value)
        {
                struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        return FAILED;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
        }
@@ -1781,17 +1716,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
        if (mark.value)
        {
                struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        return FAILED;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
        }
@@ -1863,17 +1793,12 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
        if (mark.value)
        {
                struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +  RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        return FAILED;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
        }
@@ -1945,7 +1870,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
        rta = XFRM_RTA(out, struct xfrm_usersa_info);
        rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info);
        pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info);
-       while(RTA_OK(rta, rtasize))
+       while (RTA_OK(rta, rtasize))
        {
                /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */
                if (rta->rta_type != XFRMA_ENCAP || new_encap)
@@ -1964,53 +1889,42 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
                rta = RTA_NEXT(rta, rtasize);
        }
 
-       rta = (struct rtattr*)pos;
        if (tmpl == NULL && new_encap)
        {       /* add tmpl if we are enabling it */
-               rta->rta_type = XFRMA_ENCAP;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
+               if (!tmpl)
                {
                        goto failed;
                }
-
-               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
                tmpl->encap_type = UDP_ENCAP_ESPINUDP;
                tmpl->encap_sport = ntohs(new_src->get_port(new_src));
                tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
                memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
-
-               rta = XFRM_RTA_NEXT(rta);
        }
 
        if (replay_esn)
        {
-               rta->rta_type = XFRMA_REPLAY_ESN_VAL;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) +
-                                                                 this->replay_bmp);
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               struct xfrm_replay_state_esn *state;
+
+               state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL,
+                                                               sizeof(*state) + this->replay_bmp);
+               if (!state)
                {
                        goto failed;
                }
-               memcpy(RTA_DATA(rta), replay_esn,
-                          sizeof(struct xfrm_replay_state_esn) + this->replay_bmp);
-
-               rta = XFRM_RTA_NEXT(rta);
+               memcpy(state, replay_esn, sizeof(*state) + this->replay_bmp);
        }
        else if (replay)
        {
-               rta->rta_type = XFRMA_REPLAY_VAL;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               struct xfrm_replay_state *state;
+
+               state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_VAL,
+                                                               sizeof(*state));
+               if (!state)
                {
                        goto failed;
                }
-               memcpy(RTA_DATA(rta), replay, sizeof(struct xfrm_replay_state));
-
-               rta = XFRM_RTA_NEXT(rta);
+               memcpy(state, replay, sizeof(*state));
        }
        else
        {
@@ -2107,11 +2021,9 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
        policy_info->lft.soft_use_expires_seconds = 0;
        policy_info->lft.hard_use_expires_seconds = 0;
 
-       struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info);
-
        if (mapping->type == POLICY_IPSEC)
        {
-               struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
+               struct xfrm_user_tmpl *tmpl;
                struct {
                        u_int8_t proto;
                        bool use;
@@ -2121,26 +2033,29 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
                        { IPPROTO_AH, ipsec->cfg.ah.use },
                };
                ipsec_mode_t proto_mode = ipsec->cfg.mode;
-
-               rthdr->rta_type = XFRMA_TMPL;
-               rthdr->rta_len = 0; /* actual length is set below */
+               int count = 0;
 
                for (i = 0; i < countof(protos); i++)
                {
-                       if (!protos[i].use)
+                       if (protos[i].use)
                        {
-                               continue;
+                               count++;
                        }
+               }
+               tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_TMPL,
+                                                          count * sizeof(*tmpl));
+               if (!tmpl)
+               {
+                       this->mutex->unlock(this->mutex);
+                       return FAILED;
+               }
 
-                       rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-                       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) +
-                                               RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl)));
-                       if (hdr->nlmsg_len > sizeof(request))
+               for (i = 0; i < countof(protos); i++)
+               {
+                       if (!protos[i].use)
                        {
-                               this->mutex->unlock(this->mutex);
-                               return FAILED;
+                               continue;
                        }
-
                        tmpl->reqid = ipsec->cfg.reqid;
                        tmpl->id.proto = protos[i].proto;
                        tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
@@ -2160,25 +2075,18 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
                        /* use transport mode for other SAs */
                        proto_mode = MODE_TRANSPORT;
                }
-
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (ipsec->mark.value)
        {
                struct xfrm_mark *mrk;
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        this->mutex->unlock(this->mutex);
                        return FAILED;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = ipsec->mark.value;
                mrk->m = ipsec->mark.mask;
        }
@@ -2410,17 +2318,12 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
        if (mark.value)
        {
                struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
                        return FAILED;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
        }
@@ -2581,18 +2484,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        if (mark.value)
        {
                struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
 
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk));
+               if (!mrk)
                {
-                       this->mutex->unlock(this->mutex);
                        return FAILED;
                }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
                mrk->v = mark.value;
                mrk->m = mark.mask;
        }