diff options
| author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-08-09 09:43:35 +0000 | 
|---|---|---|
| committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-08-09 09:43:35 +0000 | 
| commit | 9e7fb8577802de2abf191d783be5b6b953c22271 (patch) | |
| tree | e6818532d3a85a8a840652f6dfc0d58d42c89a69 /src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c | |
| parent | 20e652eab94f898365fdde046ed11a2dda2f165e (diff) | |
| download | vyos-strongswan-9e7fb8577802de2abf191d783be5b6b953c22271.tar.gz vyos-strongswan-9e7fb8577802de2abf191d783be5b6b953c22271.zip | |
New upstream release.
Diffstat (limited to 'src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c')
| -rw-r--r-- | src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 323 | 
1 files changed, 278 insertions, 45 deletions
| diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 1b8c1b879..019ec93f8 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -280,6 +280,9 @@ struct policy_entry_t {  	/** parameters of installed policy */  	struct xfrm_selector sel; +	/** optional mark */ +	u_int32_t mark; +  	/** associated route installed for this policy */  	route_entry_t *route; @@ -292,7 +295,8 @@ struct policy_entry_t {   */  static u_int policy_hash(policy_entry_t *key)  { -	chunk_t chunk = chunk_create((void*)&key->sel, sizeof(struct xfrm_selector)); +	chunk_t chunk = chunk_create((void*)&key->sel, +						 	sizeof(struct xfrm_selector) + sizeof(u_int32_t));  	return chunk_hash(chunk);  } @@ -301,7 +305,8 @@ static u_int policy_hash(policy_entry_t *key)   */  static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)  { -	return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) && +	return memeq(&key->sel, &other_key->sel,  +				 sizeof(struct xfrm_selector) + sizeof(u_int32_t)) &&  		   key->direction == other_key->direction;  } @@ -917,11 +922,11 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,  METHOD(kernel_ipsec_t, add_sa, status_t,  	private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, -	u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, +	u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, mark_t mark,  	lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, -	u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, -	u_int16_t cpi, bool encap, bool inbound, traffic_selector_t* src_ts, -	traffic_selector_t* dst_ts) +	u_int16_t int_alg, chunk_t int_key,	ipsec_mode_t mode, u_int16_t ipcomp, +	u_int16_t cpi, bool encap, bool inbound, +	traffic_selector_t* src_ts, traffic_selector_t* dst_ts)  {  	netlink_buf_t request;  	char *alg_name; @@ -934,8 +939,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  	if (ipcomp != IPCOMP_NONE && cpi != 0)  	{  		lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}}; -		add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, &lft, -			   ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty, +		add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark, +			   &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,  			   mode, ipcomp, 0, FALSE, inbound, NULL, NULL);  		ipcomp = IPCOMP_NONE;  		/* use transport mode ESP SA, IPComp uses tunnel mode */ @@ -944,9 +949,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  	memset(&request, 0, sizeof(request)); -	DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", -		 ntohl(spi), reqid); - +	if (mark.value) +	{ +		DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}  " +					  "(mark %u/0x%8x)", ntohl(spi), reqid, mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", +					   ntohl(spi), reqid); +	}  	hdr = (struct nlmsghdr*)request;  	hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;  	hdr->nlmsg_type = inbound ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; @@ -1151,6 +1163,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  	if (encap)  	{ +		struct xfrm_encap_tmpl *tmpl; +  		rthdr->rta_type = XFRMA_ENCAP;  		rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); @@ -1160,7 +1174,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  			return FAILED;  		} -		struct xfrm_encap_tmpl* tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); +		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)); @@ -1177,9 +1191,36 @@ METHOD(kernel_ipsec_t, add_sa, status_t,  		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 += rthdr->rta_len; +		if (hdr->nlmsg_len > sizeof(request)) +		{ +			return FAILED; +		} + +		mrk = (struct xfrm_mark*)RTA_DATA(rthdr); +		mrk->v = mark.value; +		mrk->m = mark.mask; +		rthdr = XFRM_RTA_NEXT(rthdr); +	} +  	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)  	{ -		DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); +		if (mark.value) +		{ +			DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x  " +						  "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask); +		} +		else +		{ +			DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x", ntohl(spi)); +		}  		return FAILED;  	}  	return SUCCESS; @@ -1275,7 +1316,7 @@ static status_t get_replay_state(private_kernel_netlink_ipsec_t *this,  METHOD(kernel_ipsec_t, query_sa, status_t,  	private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, -	u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes) +	u_int32_t spi, protocol_id_t protocol, mark_t mark, u_int64_t *bytes)  {  	netlink_buf_t request;  	struct nlmsghdr *out = NULL, *hdr; @@ -1285,8 +1326,15 @@ METHOD(kernel_ipsec_t, query_sa, status_t,  	memset(&request, 0, sizeof(request)); -	DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); - +	if (mark.value) +	{ +		DBG2(DBG_KNL, "querying SAD entry with SPI %.8x  (mark %u/0x%8x)", +					   ntohl(spi), mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); +	}  	hdr = (struct nlmsghdr*)request;  	hdr->nlmsg_flags = NLM_F_REQUEST;  	hdr->nlmsg_type = XFRM_MSG_GETSA; @@ -1298,6 +1346,24 @@ METHOD(kernel_ipsec_t, query_sa, status_t,  	sa_id->proto = proto_ike2kernel(protocol);  	sa_id->family = dst->get_family(dst); +	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 += rthdr->rta_len; +		if (hdr->nlmsg_len > sizeof(request)) +		{ +			return FAILED; +		} + +		mrk = (struct xfrm_mark*)RTA_DATA(rthdr); +		mrk->v = mark.value; +		mrk->m = mark.mask; +	} +  	if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)  	{  		hdr = out; @@ -1313,8 +1379,20 @@ METHOD(kernel_ipsec_t, query_sa, status_t,  				case NLMSG_ERROR:  				{  					struct nlmsgerr *err = NLMSG_DATA(hdr); -					DBG1(DBG_KNL, "querying SAD entry with SPI %.8x failed: %s (%d)", -						 ntohl(spi), strerror(-err->error), -err->error); +					 +					if (mark.value) +					{ +						DBG1(DBG_KNL, "querying SAD entry with SPI %.8x  " +									  "(mark %u/0x%8x) failed: %s (%d)", +									   ntohl(spi), mark.value, mark.mask, +									   strerror(-err->error), -err->error); +					} +					else +					{ +						DBG1(DBG_KNL, "querying SAD entry with SPI %.8x " +									  "failed: %s (%d)", ntohl(spi), +									   strerror(-err->error), -err->error); +					}  					break;  				}  				default: @@ -1341,7 +1419,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t,  METHOD(kernel_ipsec_t, del_sa, status_t,  	private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, -	u_int32_t spi, protocol_id_t protocol, u_int16_t cpi) +	u_int32_t spi, protocol_id_t protocol, u_int16_t cpi, mark_t mark)  {  	netlink_buf_t request;  	struct nlmsghdr *hdr; @@ -1350,13 +1428,20 @@ METHOD(kernel_ipsec_t, del_sa, status_t,  	/* if IPComp was used, we first delete the additional IPComp SA */  	if (cpi)  	{ -		del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0); +		del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark);  	}  	memset(&request, 0, sizeof(request)); -	DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi)); - +	if (mark.value) +	{ +		DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x  (mark %u/0x%8x)", +					   ntohl(spi), mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi)); +	}  	hdr = (struct nlmsghdr*)request;  	hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;  	hdr->nlmsg_type = XFRM_MSG_DELSA; @@ -1368,19 +1453,53 @@ METHOD(kernel_ipsec_t, del_sa, status_t,  	sa_id->proto = proto_ike2kernel(protocol);  	sa_id->family = dst->get_family(dst); +	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 += rthdr->rta_len; +		if (hdr->nlmsg_len > sizeof(request)) +		{ +			return FAILED; +		} + +		mrk = (struct xfrm_mark*)RTA_DATA(rthdr); +		mrk->v = mark.value; +		mrk->m = mark.mask; +	} +  	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)  	{ -		DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi)); +		if (mark.value) +		{ +			DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x  " +						  "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask); +		} +		else +		{ +			DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", ntohl(spi)); +		}  		return FAILED;  	} -	DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); +	if (mark.value) +	{ +		DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x  (mark %u/0x%8x)", +					   ntohl(spi), mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); +	}  	return SUCCESS;  }  METHOD(kernel_ipsec_t, update_sa, status_t,  	private_kernel_netlink_ipsec_t *this, u_int32_t spi, protocol_id_t protocol,  	u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, -	bool old_encap, bool new_encap) +	bool old_encap, bool new_encap, mark_t mark)  {  	netlink_buf_t request;  	u_char *pos; @@ -1398,7 +1517,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,  	if (cpi)  	{  		update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, -				  src, dst, new_src, new_dst, FALSE, FALSE); +				  src, dst, new_src, new_dst, FALSE, FALSE, mark);  	}  	memset(&request, 0, sizeof(request)); @@ -1459,7 +1578,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,  	}  	/* delete the old SA (without affecting the IPComp SA) */ -	if (del_sa(this, src, dst, spi, protocol, 0) != SUCCESS) +	if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)  	{  		DBG1(DBG_KNL, "unable to delete old SAD entry with SPI %.8x", ntohl(spi));  		free(out); @@ -1558,8 +1677,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  	private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,  	traffic_selector_t *src_ts, traffic_selector_t *dst_ts,  	policy_dir_t direction, u_int32_t spi, protocol_id_t protocol, -	u_int32_t reqid, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, -	bool routed) +	u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp, +	u_int16_t cpi,	bool routed)  {  	policy_entry_t *current, *policy;  	bool found = FALSE; @@ -1571,6 +1690,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  	policy = malloc_thing(policy_entry_t);  	memset(policy, 0, sizeof(policy_entry_t));  	policy->sel = ts2selector(src_ts, dst_ts); +	policy->mark = mark.value & mark.mask;  	policy->direction = direction;  	/* find the policy, which matches EXACTLY */ @@ -1580,9 +1700,19 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  	{  		/* use existing policy */  		current->refcount++; -		DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing " -					  "refcount", src_ts, dst_ts, -					   policy_dir_names, direction); +		if (mark.value) +		{ +			DBG2(DBG_KNL, "policy %R === %R %N  (mark %u/0x%8x) " +						  "already exists, increasing refcount", +						   src_ts, dst_ts, policy_dir_names, direction, +					  	   mark.value, mark.mask); +		} +		else +		{ +			DBG2(DBG_KNL, "policy %R === %R %N " +						  "already exists, increasing refcount", +						   src_ts, dst_ts, policy_dir_names, direction); +		}  		free(policy);  		policy = current;  		found = TRUE; @@ -1593,8 +1723,17 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  		policy->refcount = 1;  	} -	DBG2(DBG_KNL, "adding policy %R === %R %N", src_ts, dst_ts, -				   policy_dir_names, direction); +	if (mark.value) +	{ +		DBG2(DBG_KNL, "adding policy %R === %R %N  (mark %u/0x%8x)", +					   src_ts, dst_ts, policy_dir_names, direction, +					   mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "adding policy %R === %R %N", +					   src_ts, dst_ts, policy_dir_names, direction); +	}  	memset(&request, 0, sizeof(request));  	hdr = (struct nlmsghdr*)request; @@ -1673,6 +1812,25 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  	tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;  	tmpl->mode = mode2kernel(mode);  	tmpl->family = src->get_family(src); +	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 += rthdr->rta_len; +		if (hdr->nlmsg_len > sizeof(request)) +		{ +			return FAILED; +		} + +		mrk = (struct xfrm_mark*)RTA_DATA(rthdr); +		mrk->v = mark.value; +		mrk->m = mark.mask; +	}  	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)  	{ @@ -1741,7 +1899,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,  METHOD(kernel_ipsec_t, query_policy, status_t,  	private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts, -	traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t *use_time) +	traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, +	u_int32_t *use_time)  {  	netlink_buf_t request;  	struct nlmsghdr *out = NULL, *hdr; @@ -1751,9 +1910,17 @@ METHOD(kernel_ipsec_t, query_policy, status_t,  	memset(&request, 0, sizeof(request)); -	DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, -				   policy_dir_names, direction); - +	if (mark.value) +	{ +		DBG2(DBG_KNL, "querying policy %R === %R %N  (mark %u/0x%8x)", +					   src_ts, dst_ts, policy_dir_names, direction, +					   mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, +					   policy_dir_names, direction); +	}  	hdr = (struct nlmsghdr*)request;  	hdr->nlmsg_flags = NLM_F_REQUEST;  	hdr->nlmsg_type = XFRM_MSG_GETPOLICY; @@ -1763,6 +1930,25 @@ METHOD(kernel_ipsec_t, query_policy, status_t,  	policy_id->sel = ts2selector(src_ts, dst_ts);  	policy_id->dir = direction; +	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 += rthdr->rta_len; +		if (hdr->nlmsg_len > sizeof(request)) +		{ +			return FAILED; +		} + +		mrk = (struct xfrm_mark*)RTA_DATA(rthdr); +		mrk->v = mark.value; +		mrk->m = mark.mask; +	} +  	if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)  	{  		hdr = out; @@ -1816,7 +2002,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,  METHOD(kernel_ipsec_t, del_policy, status_t,  	private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts, -	traffic_selector_t *dst_ts, policy_dir_t direction, bool unrouted) +	traffic_selector_t *dst_ts, policy_dir_t direction,	mark_t mark, +	bool unrouted)  {  	policy_entry_t *current, policy, *to_delete = NULL;  	route_entry_t *route; @@ -1824,12 +2011,22 @@ METHOD(kernel_ipsec_t, del_policy, status_t,  	struct nlmsghdr *hdr;  	struct xfrm_userpolicy_id *policy_id; -	DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts, -				   policy_dir_names, direction); +	if (mark.value) +	{ +		DBG2(DBG_KNL, "deleting policy %R === %R %N  (mark %u/0x%8x)", +					   src_ts, dst_ts, policy_dir_names, direction, +					   mark.value, mark.mask); +	} +	else +	{ +		DBG2(DBG_KNL, "deleting policy %R === %R %N", +					   src_ts, dst_ts, policy_dir_names, direction); +	}  	/* create a policy */  	memset(&policy, 0, sizeof(policy_entry_t));  	policy.sel = ts2selector(src_ts, dst_ts); +	policy.mark = mark.value & mark.mask;  	policy.direction = direction;  	/* find the policy */ @@ -1851,8 +2048,17 @@ METHOD(kernel_ipsec_t, del_policy, status_t,  	this->mutex->unlock(this->mutex);  	if (!to_delete)  	{ -		DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts, -					   dst_ts, policy_dir_names, direction); +		if (mark.value) +		{ +			DBG1(DBG_KNL, "deleting policy %R === %R %N  (mark %u/0x%8x) " +						  "failed, not found", src_ts, dst_ts, policy_dir_names, +						   direction, mark.value, mark.mask); +		} +		else +		{ +			DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", +						   src_ts, dst_ts, policy_dir_names, direction); +		}  		return NOT_FOUND;  	} @@ -1867,13 +2073,40 @@ METHOD(kernel_ipsec_t, del_policy, status_t,  	policy_id->sel = to_delete->sel;  	policy_id->dir = direction; +	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 += rthdr->rta_len; +		if (hdr->nlmsg_len > sizeof(request)) +		{ +			return FAILED; +		} + +		mrk = (struct xfrm_mark*)RTA_DATA(rthdr); +		mrk->v = mark.value; +		mrk->m = mark.mask; +	} +  	route = to_delete->route;  	free(to_delete);  	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)  	{ -		DBG1(DBG_KNL, "unable to delete policy %R === %R %N", src_ts, dst_ts, -					   policy_dir_names, direction); +		if (mark.value) +		{ +			DBG1(DBG_KNL, "unable to delete policy %R === %R %N  " +                          "(mark %u/0x%8x)", src_ts, dst_ts, policy_dir_names, +						   direction, mark.value, mark.mask); +		} +		else +		{ +			DBG1(DBG_KNL, "unable to delete policy %R === %R %N", +						   src_ts, dst_ts, policy_dir_names, direction); +		}  		return FAILED;  	} | 
