2
0
Эх сурвалжийг харах

ipops: exported functions to kemi framework

Daniel-Constantin Mierla 7 жил өмнө
parent
commit
c11af868d6
1 өөрчлөгдсөн 374 нэмэгдсэн , 60 устгасан
  1. 374 60
      src/modules/ipops/ipops_mod.c

+ 374 - 60
src/modules/ipops/ipops_mod.c

@@ -47,6 +47,7 @@
 #include "../../core/pvar.h"
 #include "../../core/resolve.h"
 #include "../../core/lvalue.h"
+#include "../../core/kemi.h"
 #include "api.h"
 #include "ipops_pv.h"
 #include "ip_parser.h"
@@ -528,6 +529,16 @@ static int w_is_ip(sip_msg_t* _msg, char* _s, char *_p2)
 		return -1;
 }
 
+/**
+ * 
+ */
+static int ki_is_ip(sip_msg_t *msg, str *sval)
+{
+	if (ip_parser_execute(sval->s, sval->len) != ip_type_error)
+		return 1;
+	else
+		return -1;
+}
 
 /*! \brief Return true if the given argument (string or pv) is a valid
  * IPv4 or IPv6. */
@@ -559,6 +570,23 @@ static int w_is_pure_ip(sip_msg_t* _msg, char* _s, char *_p2)
 	}
 }
 
+/**
+ * 
+ */
+static int ki_is_pure_ip(sip_msg_t *msg, str *sval)
+{
+	switch(ip_parser_execute(sval->s, sval->len)) {
+		case(ip_type_ipv4):
+			return 1;
+			break;
+		case(ip_type_ipv6):
+			return 1;
+			break;
+		default:
+			return -1;
+			break;
+	}
+}
 
 /*! \brief Return true if the given argument (string or pv) is a valid IPv4. */
 static int w_is_ipv4(sip_msg_t* _msg, char* _s, char *_p2)
@@ -583,6 +611,17 @@ static int w_is_ipv4(sip_msg_t* _msg, char* _s, char *_p2)
 }
 
 
+/**
+ * 
+ */
+static int ki_is_ip4(sip_msg_t *msg, str *sval)
+{
+	if (ip_parser_execute(sval->s, sval->len) == ip_type_ipv4)
+		return 1;
+	else
+		return -1;
+}
+
 /*! \brief Return true if the given argument (string or pv) is a valid IPv6. */
 static int w_is_ipv6(sip_msg_t* _msg, char* _s, char *_p2)
 {
@@ -605,6 +644,16 @@ static int w_is_ipv6(sip_msg_t* _msg, char* _s, char *_p2)
 		return -1;
 }
 
+/**
+ * 
+ */
+static int ki_is_ip6(sip_msg_t *msg, str *sval)
+{
+	if (ip_parser_execute(sval->s, sval->len) == ip_type_ipv6)
+		return 1;
+	else
+		return -1;
+}
 
 /*! \brief Return true if the given argument (string or pv) is a valid
  * IPv6 reference. */
@@ -630,6 +679,17 @@ static int w_is_ipv6_reference(sip_msg_t* _msg, char* _s, char *_p2)
 }
 
 
+/**
+ * 
+ */
+static int ki_is_ip6_reference(sip_msg_t *msg, str *sval)
+{
+	if (ip_parser_execute(sval->s, sval->len) == ip_type_ipv6_reference)
+		return 1;
+	else
+		return -1;
+}
+
 /*! \brief Return the IP type of the given argument (string or pv):
  *  1 = IPv4, 2 = IPv6, 3 = IPv6 refenrece, -1 = invalid IP. */
 static int w_ip_type(sip_msg_t* _msg, char* _s, char *_p2)
@@ -663,6 +723,26 @@ static int w_ip_type(sip_msg_t* _msg, char* _s, char *_p2)
 	}
 }
 
+/*! \brief Return the IP type of the given argument (string or pv):
+ *  1 = IPv4, 2 = IPv6, 3 = IPv6 refenrece, -1 = invalid IP. */
+static int ki_ip_type(sip_msg_t *msg, str *sval)
+{
+	switch (ip_parser_execute(sval->s, sval->len)) {
+		case(ip_type_ipv4):
+			return 1;
+			break;
+		case(ip_type_ipv6):
+			return 2;
+			break;
+		case(ip_type_ipv6_reference):
+			return 3;
+			break;
+		default:
+			return -1;
+			break;
+	}
+}
+
 static int w_detailed_ipv4_type(sip_msg_t* _msg, char* _s,  char *_dst)
 {
 	return _detailed_ip_type(ip_type_ipv4, _msg, _s, _dst);
@@ -679,26 +759,15 @@ static int w_detailed_ip_type(sip_msg_t* _msg, char* _s,  char *_dst)
 	return _detailed_ip_type(ip_type_error, _msg, _s, _dst);
 }
 
-static int _detailed_ip_type(unsigned int _type, sip_msg_t* _msg,
-		char* _s,  char *_dst)
+static int _detailed_ip_type_helper(unsigned int _type, sip_msg_t* _msg,
+		str* sval,  pv_spec_t *dst)
 {
 	str string;
-	pv_spec_t *dst;
 	pv_value_t val;
 	char *res;
 	unsigned int assumed_type;
 
-	if (_s == NULL) {
-		LM_ERR("bad parameter\n");
-		return -2;
-	}
-
-	if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
-	{
-		LM_ERR("cannot print the format for string\n");
-		return -3;
-	}
-
+	string = *sval;
 	assumed_type = (ip_type_error == _type)?
 						ip_parser_execute(string.s, string.len) : _type;
 
@@ -728,35 +797,73 @@ static int _detailed_ip_type(unsigned int _type, sip_msg_t* _msg,
 	val.rs.s = res;
 	val.rs.len = strlen(res);
 	val.flags = PV_VAL_STR;
-	dst = (pv_spec_t *)_dst;
 	dst->setf(_msg, &dst->pvp, (int)EQ_T, &val);
 	return 1;
 }
 
-/*! \brief Return true if both IP's (string or pv) are equal.
- * This function also allows comparing an IPv6 with an IPv6 reference. */
-static int w_compare_ips(sip_msg_t* _msg, char* _s1, char* _s2)
+static int _detailed_ip_type(unsigned int _type, sip_msg_t* _msg,
+		char* _s,  char *_dst)
 {
-	str string1, string2;
-	enum enum_ip_type ip1_type, ip2_type;
+	str string;
+	pv_spec_t *dst;
 
-	if (_s1 == NULL || _s2 == NULL ) {
-		LM_ERR("bad parameters\n");
+	if (_s == NULL) {
+		LM_ERR("bad parameter\n");
 		return -2;
 	}
 
-	if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
+	if (fixup_get_svalue(_msg, (gparam_p)_s, &string))
 	{
-		LM_ERR("cannot print the format for first string\n");
+		LM_ERR("cannot print the format for string\n");
 		return -3;
 	}
+	dst = (pv_spec_t *)_dst;
 
-	if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
-	{
-		LM_ERR("cannot print the format for second string\n");
-		return -3;
+	return _detailed_ip_type_helper(_type, _msg, &string, dst);
+}
+
+static int ki_detailed_ip_type_helper(unsigned int _type, sip_msg_t* _msg,
+		str* _sval,  str *_dpv)
+{
+	pv_spec_t *dst;
+
+	dst = pv_cache_get(_dpv);
+	if (dst == NULL) {
+		LM_ERR("result pvar is not found: %.*s\n", _dpv->len, _dpv->s);
+		return -1;
+	}
+	if (dst->setf == NULL) {
+		LM_ERR("result pvar is not writeble: %.*s\n", _dpv->len, _dpv->s);
+		return -1;
 	}
+	return _detailed_ip_type_helper(_type, _msg, _sval, dst);
+}
+
+static int ki_detailed_ipv4_type(sip_msg_t* _msg, str* _sval, str *_dpv)
+{
+	return ki_detailed_ip_type_helper(ip_type_ipv4, _msg, _sval, _dpv);
+}
+
+static int ki_detailed_ipv6_type(sip_msg_t* _msg, str* _sval, str *_dpv)
+{
+	return ki_detailed_ip_type_helper(ip_type_ipv6, _msg, _sval, _dpv);
+}
+
+static int ki_detailed_ip_type(sip_msg_t* _msg, str* _sval, str *_dpv)
+{
+	/* `ip_type_error` should read `unknown type` */
+	return ki_detailed_ip_type_helper(ip_type_error, _msg, _sval, _dpv);
+}
+
+/*! \brief Return true if both IP's (string or pv) are equal.
+ * This function also allows comparing an IPv6 with an IPv6 reference. */
+static int ki_compare_ips(sip_msg_t* _msg, str* _sval1, str* _sval2)
+{
+	str string1, string2;
+	enum enum_ip_type ip1_type, ip2_type;
 
+	string1 = *_sval1;
+	string2 = *_sval2;
 	switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
 		case(ip_type_error):
 			return -1;
@@ -789,13 +896,11 @@ static int w_compare_ips(sip_msg_t* _msg, char* _s1, char* _s2)
 		return -1;
 }
 
-
-/*! \brief Return true if both pure IP's (string or pv) are equal.
- * IPv6 references not allowed. */
-static int w_compare_pure_ips(sip_msg_t* _msg, char* _s1, char* _s2)
+/*! \brief Return true if both IP's (string or pv) are equal.
+ * This function also allows comparing an IPv6 with an IPv6 reference. */
+static int w_compare_ips(sip_msg_t* _msg, char* _s1, char* _s2)
 {
 	str string1, string2;
-	enum enum_ip_type ip1_type, ip2_type;
 
 	if (_s1 == NULL || _s2 == NULL ) {
 		LM_ERR("bad parameters\n");
@@ -814,6 +919,18 @@ static int w_compare_pure_ips(sip_msg_t* _msg, char* _s1, char* _s2)
 		return -3;
 	}
 
+	return ki_compare_ips(_msg, &string1, &string2);
+}
+
+/*! \brief Return true if both pure IP's (string or pv) are equal.
+ * IPv6 references not allowed. */
+static int ki_compare_pure_ips(sip_msg_t* _msg, str* _sval1, str* _sval2)
+{
+	str string1, string2;
+	enum enum_ip_type ip1_type, ip2_type;
+
+	string1 = *_sval1;
+	string2 = *_sval2;
 	switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
 		case(ip_type_error):
 			return -1;
@@ -842,19 +959,11 @@ static int w_compare_pure_ips(sip_msg_t* _msg, char* _s1, char* _s2)
 		return -1;
 }
 
-
-/*! \brief Return true if the first IP (string or pv) is within the subnet
- * defined by the second commma-separated IP list in CIDR notation.
+/*! \brief Return true if both pure IP's (string or pv) are equal.
  * IPv6 references not allowed. */
-static int w_ip_is_in_subnet(sip_msg_t* _msg, char* _s1, char* _s2)
+static int w_compare_pure_ips(sip_msg_t* _msg, char* _s1, char* _s2)
 {
-	struct in6_addr ip_addr6;
-	struct in_addr ip_addr;
-	int ret;
-	char ip_addr_str[INET6_ADDRSTRLEN],*b,*e;
-	void *ip;
 	str string1, string2;
-	enum enum_ip_type ip1_type;
 
 	if (_s1 == NULL || _s2 == NULL ) {
 		LM_ERR("bad parameters\n");
@@ -873,6 +982,24 @@ static int w_ip_is_in_subnet(sip_msg_t* _msg, char* _s1, char* _s2)
 		return -3;
 	}
 
+	return ki_compare_pure_ips(_msg, &string1, &string2);
+}
+
+/*! \brief Return true if the first IP (string or pv) is within the subnet
+ * defined by the second commma-separated IP list in CIDR notation.
+ * IPv6 references not allowed. */
+static int ki_ip_is_in_subnet(sip_msg_t* _msg, str* _sval1, str* _sval2)
+{
+	struct in6_addr ip_addr6;
+	struct in_addr ip_addr;
+	int ret;
+	char ip_addr_str[INET6_ADDRSTRLEN],*b,*e;
+	void *ip;
+	str string1, string2;
+	enum enum_ip_type ip1_type;
+
+	string1 = *_sval1;
+	string2 = *_sval2;
 	switch(ip1_type = ip_parser_execute(string1.s, string1.len)) {
 		case(ip_type_error):
 			return -1;
@@ -910,6 +1037,33 @@ static int w_ip_is_in_subnet(sip_msg_t* _msg, char* _s1, char* _s2)
 }
 
 
+/*! \brief Return true if the first IP (string or pv) is within the subnet
+ * defined by the second commma-separated IP list in CIDR notation.
+ * IPv6 references not allowed. */
+static int w_ip_is_in_subnet(sip_msg_t* _msg, char* _s1, char* _s2)
+{
+	str string1, string2;
+
+	if (_s1 == NULL || _s2 == NULL ) {
+		LM_ERR("bad parameters\n");
+		return -2;
+	}
+
+	if (fixup_get_svalue(_msg, (gparam_p)_s1, &string1))
+	{
+		LM_ERR("cannot print the format for first string\n");
+		return -3;
+	}
+
+	if (fixup_get_svalue(_msg, (gparam_p)_s2, &string2))
+	{
+		LM_ERR("cannot print the format for second string\n");
+		return -3;
+	}
+
+	return ki_ip_is_in_subnet(_msg, &string1, &string2);
+}
+
 /*! \brief Return true if the given argument (string or pv) is a valid
  * RFC 1918 IPv4 (private address). */
 static int w_is_ip_rfc1918(sip_msg_t* _msg, char* _s, char *_p2)
@@ -933,6 +1087,16 @@ static int w_is_ip_rfc1918(sip_msg_t* _msg, char* _s, char *_p2)
 		return -1;
 }
 
+/*! \brief Return true if the given argument (string or pv) is a valid
+ * RFC 1918 IPv4 (private address). */
+static int ki_is_ip_rfc1918(sip_msg_t* _msg, str* sval)
+{
+	if (rfc1918_parser_execute(sval->s, sval->len) == 1)
+		return 1;
+	else
+		return -1;
+}
+
 static inline ip_addr_t *strtoipX(str *ips)
 {
 	/* try to figure out INET class */
@@ -946,7 +1110,7 @@ static inline ip_addr_t *strtoipX(str *ips)
 	}
 }
 
-static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
+static int ki_dns_sys_match_ip(sip_msg_t *msg, str *vhn, str *vip)
 {
 	struct addrinfo hints, *res, *p;
 	int status;
@@ -957,18 +1121,8 @@ static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 	struct sockaddr_in *ipv4;
 	struct sockaddr_in6 *ipv6;
 
-	if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
-	{
-		LM_ERR("cannot evaluate hostname parameter\n");
-		return -2;
-	}
-
-	if (fixup_get_svalue(msg, (gparam_p)ipp, &ips))
-	{
-		LM_ERR("cannot evaluate ip address parameter\n");
-		return -2;
-	}
-
+	hns = *vhn;
+	ips = *vip;
 	ipa = strtoipX(&ips);
 	if(ipa==NULL)
 	{
@@ -1012,13 +1166,10 @@ static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 	return -1;
 }
 
-static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
+static int w_dns_sys_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 {
-	ip_addr_t *ipa;
 	str hns;
 	str ips;
-	struct hostent* he;
-	char ** h;
 
 	if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
 	{
@@ -1032,6 +1183,19 @@ static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 		return -2;
 	}
 
+	return ki_dns_sys_match_ip(msg, &hns, &ips);
+}
+
+static int ki_dns_int_match_ip(sip_msg_t *msg, str *vhn, str *vip)
+{
+	ip_addr_t *ipa;
+	str hns;
+	str ips;
+	struct hostent* he;
+	char ** h;
+
+	hns = *vhn;
+	ips = *vip;
 	ipa = strtoipX(&ips);
 	if(ipa==NULL)
 	{
@@ -1060,6 +1224,26 @@ static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
 	return -1;
 }
 
+static int w_dns_int_match_ip(sip_msg_t *msg, char *hnp, char *ipp)
+{
+	str hns;
+	str ips;
+
+	if (fixup_get_svalue(msg, (gparam_p)hnp, &hns))
+	{
+		LM_ERR("cannot evaluate hostname parameter\n");
+		return -2;
+	}
+
+	if (fixup_get_svalue(msg, (gparam_p)ipp, &ips))
+	{
+		LM_ERR("cannot evaluate ip address parameter\n");
+		return -2;
+	}
+
+	return ki_dns_int_match_ip(msg, &hns, &ips);
+}
+
 /**
  *
  */
@@ -1088,6 +1272,14 @@ static int w_dns_query(sip_msg_t* msg, char* str1, char* str2)
 	return dns_update_pv(&hostname, &name);
 }
 
+/**
+ *
+ */
+static int ki_dns_query(sip_msg_t* msg, str* naptrname, str* pvid)
+{
+	return dns_update_pv(naptrname, pvid);
+}
+
 /**
  *
  */
@@ -1116,6 +1308,14 @@ static int w_srv_query(sip_msg_t* msg, char* str1, char* str2)
 	return srv_update_pv(&srvcname, &name);
 }
 
+/**
+ *
+ */
+static int ki_srv_query(sip_msg_t* msg, str* naptrname, str* pvid)
+{
+	return srv_update_pv(naptrname, pvid);
+}
+
 /**
  *
  */
@@ -1143,3 +1343,117 @@ static int w_naptr_query(sip_msg_t* msg, char* str1, char* str2)
 
 	return naptr_update_pv(&naptrname, &name);
 }
+
+/**
+ *
+ */
+static int ki_naptr_query(sip_msg_t* msg, str* naptrname, str* pvid)
+{
+	return naptr_update_pv(naptrname, pvid);
+}
+
+/**
+ *
+ */
+/* clang-format off */
+static sr_kemi_t sr_kemi_ipops_exports[] = {
+	{ str_init("ipops"), str_init("is_ip"),
+		SR_KEMIP_INT, ki_is_ip,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("is_pure_ip"),
+		SR_KEMIP_INT, ki_is_pure_ip,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("is_ip4"),
+		SR_KEMIP_INT, ki_is_ip4,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("is_ip6"),
+		SR_KEMIP_INT, ki_is_ip6,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("is_ip6_reference"),
+		SR_KEMIP_INT, ki_is_ip6_reference,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("ip_type"),
+		SR_KEMIP_INT, ki_ip_type,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("detailed_ipv4_type"),
+		SR_KEMIP_INT, ki_detailed_ipv4_type,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("detailed_ipv6_type"),
+		SR_KEMIP_INT, ki_detailed_ipv6_type,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("detailed_ip_type"),
+		SR_KEMIP_INT, ki_detailed_ip_type,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("compare_ips"),
+		SR_KEMIP_INT, ki_compare_ips,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("compare_pure_ips"),
+		SR_KEMIP_INT, ki_compare_pure_ips,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("ip_is_in_subnet"),
+		SR_KEMIP_INT, ki_ip_is_in_subnet,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("is_ip_rfc1918"),
+		SR_KEMIP_INT, ki_is_ip_rfc1918,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("dns_sys_match_ip"),
+		SR_KEMIP_INT, ki_dns_sys_match_ip,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("dns_int_match_ip"),
+		SR_KEMIP_INT, ki_dns_int_match_ip,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("dns_query"),
+		SR_KEMIP_INT, ki_dns_query,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("srv_query"),
+		SR_KEMIP_INT, ki_srv_query,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("ipops"), str_init("naptr_query"),
+		SR_KEMIP_INT, ki_naptr_query,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+
+	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
+};
+/* clang-format on */
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	sr_kemi_modules_add(sr_kemi_ipops_exports);
+	return 0;
+}