/*
 * Copyright (C) 2008 iptelorg GmbH
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*!
 * \file
 * \brief Kamailio core :: kamailio compatible fixups
 * \ingroup core
 * Module: \ref core
 */

#include "mod_fix.h"
#include "mem/mem.h"
#include "trim.h"


#if 0
/* TODO: */
int fixup_regexpNL_null(void** param, int param_no); /* not used */
int fixup_regexpNL_none(void** param, int param_no); /* textops */
#endif


#define FREE_FIXUP_FP(suffix, minp, maxp)               \
	int fixup_free_##suffix(void **param, int param_no) \
	{                                                   \
		if((param_no > (maxp)) || (param_no < (minp)))  \
			return E_UNSPEC;                            \
		if(*param)                                      \
			fparam_free_restore(param);                 \
		return 0;                                       \
	}


/** macro for declaring a fixup and the corresponding free_fixup
  * for a function which fixes to fparam_t and expects 2 different types.
  *
  * The result (in *param) will be a fparam_t.
  *
  * @param suffix - function suffix (fixup_ will be pre-pended to it
  * @param minp - minimum parameter number acceptable
  * @param maxp - maximum parameter number
  * @param no1 -  number of parameters of type1
  * @param type1 - fix_param type for the 1st param
  * @param type2 - fix_param type for all the other params
  */
#define FIXUP_F2FP(suffix, minp, maxp, no1, type1, type2)                  \
	int fixup_##suffix(void **param, int param_no)                         \
	{                                                                      \
		if((param_no > (maxp)) || (param_no < (minp)))                     \
			return E_UNSPEC;                                               \
		if(param_no <= (no1)) {                                            \
			if(fix_param_types((type1), param) != 0) {                     \
				ERR("Cannot convert function parameter %d to" #type1 "\n", \
						param_no);                                         \
				return E_UNSPEC;                                           \
			}                                                              \
		} else {                                                           \
			if(fix_param_types((type2), param) != 0) {                     \
				ERR("Cannot convert function parameter %d to" #type2 "\n", \
						param_no);                                         \
				return E_UNSPEC;                                           \
			}                                                              \
		}                                                                  \
		return 0;                                                          \
	}                                                                      \
	FREE_FIXUP_FP(suffix, minp, maxp)


/** macro for declaring a fixup and the corresponding free_fixup
  * for a function which fixes directly to the requested type.
  *
  * @see FIXUP_F2FP for the parameters
  * Side effect: declares also some _fp_helper functions
  */
#define FIXUP_F2T(suffix, minp, maxp, no1, type1, type2)          \
	FIXUP_F2FP(fp_##suffix, minp, maxp, no1, type1, type2)        \
	int fixup_##suffix(void **param, int param_no)                \
	{                                                             \
		int ret;                                                  \
		if((ret = fixup_fp_##suffix(param, param_no)) != 0)       \
			return ret;                                           \
		*param = ((fparam_t *)*param)->fixed;                     \
		return 0;                                                 \
	}                                                             \
	int fixup_free_##suffix(void **param, int param_no)           \
	{                                                             \
		void *p;                                                  \
		int ret;                                                  \
		if(param && *param) {                                     \
			p = *param - (long)&((fparam_t *)0)->v;               \
			if((ret = fixup_free_fp_##suffix(&p, param_no)) == 0) \
				*param = p;                                       \
			return ret;                                           \
		}                                                         \
		return 0;                                                 \
	}


/** macro for declaring a fixup and the corresponding free_fixup
  * for a function expecting first no1 params as fparamt_t and the
  * rest as direct type.
  *
  * @see FIXUP_F2FP for the parameters with the exception
  * that only the first no1 parameters are converted to
  * fparamt_t and the rest directly to the corresponding type
  *
  * Side effect: declares also some _fpt_helper functions
  */
#define FIXUP_F2FP_T(suffix, minp, maxp, no1, type1, type2)             \
	FIXUP_F2FP(fpt_##suffix, minp, maxp, no1, type1, type2)             \
	int fixup_##suffix(void **param, int param_no)                      \
	{                                                                   \
		int ret;                                                        \
		if((ret = fixup_fpt_##suffix(param, param_no)) != 0)            \
			return ret;                                                 \
		if(param_no > (no1))                                            \
			*param = &((fparam_t *)*param)->v;                          \
		return 0;                                                       \
	}                                                                   \
	int fixup_free_##suffix(void **param, int param_no)                 \
	{                                                                   \
		void *p;                                                        \
		int ret;                                                        \
		if(param && *param) {                                           \
			p = (param_no > (no1)) ? *param - (long)&((fparam_t *)0)->v \
								   : *param;                            \
			if((ret = fixup_free_fpt_##suffix(&p, param_no)) == 0)      \
				*param = p;                                             \
			return ret;                                                 \
		}                                                               \
		return 0;                                                       \
	}


/** macro for declaring a fixup which fixes all the parameters to the same
  * type.
  *
  * @see FIXUP_F2T.
  */
#define FIXUP_F1T(suffix, minp, maxp, type) \
	FIXUP_F2T(suffix, minp, maxp, maxp, type, 0)


FIXUP_F1T(str_null, 1, 1, FPARAM_STR)
FIXUP_F1T(str_str, 1, 2, FPARAM_STR)
FIXUP_F1T(str_all, 1, 100, FPARAM_STR)

/*
  no free fixups possible for unit_*
  (they overwrite the pointer with the converted number => the original
   value cannot be recovered)
FIXUP_F1T(uint_null, 1, 1, FPARAM_INT)
FIXUP_F1T(uint_uint, 1, 2, FPARAM_INT)
*/


int fixup_uint_uint(void **param, int param_no)
{
	str s;
	unsigned int num;

	s.s = *param;
	s.len = strlen(s.s);
	if(likely(str2int(&s, &num) == 0)) {
		*param = (void *)(long)num;
	} else
		/* not a number */
		return E_UNSPEC;
	return 0;
}


int fixup_uint_null(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_uint_uint(param, param_no);
	return E_UNSPEC;
}


/* fixup_regexp_null() has to be written "by hand", since
   it needs to save the original pointer (the fixup users expects
   a pointer to the regex in *param and hence the original value
   needed on free cannot be recovered directly).
FIXUP_F1T(regexp_null, 1, 1, FPARAM_REGEX)
*/

struct regex_fixup
{
	regex_t regex; /* compiled regex */
	void *orig;	   /* original pointer */
};

int fixup_regexp_null(void **param, int param_no)
{
	struct regex_fixup *re;

	if(param_no != 1)
		return E_UNSPEC;
	if((re = pkg_malloc(sizeof(*re))) == 0) {
		PKG_MEM_ERROR;
		goto error;
	}
	if(regcomp(&re->regex, *param, REG_EXTENDED | REG_ICASE | REG_NEWLINE))
		goto error;
	re->orig = *param;
	*param = re;
	return 0;
error:
	if(re)
		pkg_free(re);
	return E_UNSPEC;
}

int fixup_regexp_regexp(void **param, int param_no)
{
	return fixup_regexp_null(param, 1);
}

int fixup_free_regexp_null(void **param, int param_no)
{
	struct regex_fixup *re;

	if(param_no != 1)
		return E_UNSPEC;
	if(*param) {
		re = *param;
		*param = re->orig;
		regfree(&re->regex);
		pkg_free(re);
	}
	return 0;
}

int fixup_free_regexp_regexp(void **param, int param_no)
{
	return fixup_free_regexp_null(param, 1);
}

int fixup_igp_regexp(void **param, int param_no)
{
	struct regex_fixup *re;

	if(param_no == 1) {
		return fixup_igp_null(param, param_no);
	}
	if(param_no == 2) {
		if((re = pkg_malloc(sizeof(*re))) == 0) {
			PKG_MEM_ERROR;
			goto error;
		}
		if(regcomp(&re->regex, *param, REG_EXTENDED | REG_ICASE | REG_NEWLINE))
			goto error;
		re->orig = *param;
		*param = re;
	}
	return 0;
error:
	if(re)
		pkg_free(re);
	return E_UNSPEC;
}

int fixup_free_igp_regexp(void **param, int param_no)
{
	struct regex_fixup *re;

	if(param_no == 1) {
		return fixup_free_igp_null(param, param_no);
	}
	if(param_no == 2) {
		if(*param) {
			re = *param;
			*param = re->orig;
			regfree(&re->regex);
			pkg_free(re);
		}
	}
	return 0;
}


/* fixup_pvar_*() has to be written "by hand", since
   it needs to save the original pointer (the fixup users expects
   a pointer to the pv_spec_t in *param and hence the original value
   needed on free cannot be recovered directly).
FIXUP_F1T(pvar_null, 1, 1, FPARAM_PVS)
FIXUP_F1T(pvar_pvar, 1, 2, FPARAM_PVS)
*/

typedef struct pvs_fixup
{
	pv_spec_t pvs; /* parsed pv spec */
	void *orig;	   /* original pointer */
} pvs_fixup_t;

int fixup_pvar_all(void **param, int param_no)
{
	pvs_fixup_t *pvs_f;
	str name;

	pvs_f = 0;
	name.s = *param;
	name.len = strlen(name.s);
	trim(&name);
	if(name.len == 0 || name.s[0] != '$')
		/* not a pvs id */
		goto error;
	if((pvs_f = pkg_malloc(sizeof(*pvs_f))) == 0) {
		PKG_MEM_ERROR;
		goto error;
	}
	if(pv_parse_spec2(&name, &pvs_f->pvs, 1) == 0)
		/* not a valid pvs identifier */
		goto error;
	pvs_f->orig = *param;
	*param = pvs_f;
	return 0;
error:
	if(pvs_f)
		pkg_free(pvs_f);
	return E_UNSPEC;
}


int fixup_free_pvar_all(void **param, int param_no)
{
	pvs_fixup_t *pvs_f;

	if(*param) {
		pvs_f = *param;
		*param = pvs_f->orig;
		/* free only the contents (don't attempt to free &pvs_f->pvs)*/
		pv_spec_destroy(&pvs_f->pvs);
		/* free the whole pvs_fixup_t */
		pkg_free(pvs_f);
	}
	return 0;
}


int fixup_pvar_pvar(void **param, int param_no)
{
	if(param_no > 2)
		return E_UNSPEC;
	return fixup_pvar_all(param, param_no);
}


int fixup_free_pvar_pvar(void **param, int param_no)
{
	if(param_no > 2)
		return E_UNSPEC;
	return fixup_free_pvar_all(param, param_no);
}


int fixup_pvar_pvar_pvar(void **param, int param_no)
{
	if(param_no > 3)
		return E_UNSPEC;
	return fixup_pvar_all(param, param_no);
}

int fixup_free_pvar_pvar_pvar(void **param, int param_no)
{
	if(param_no > 3)
		return E_UNSPEC;
	return fixup_free_pvar_all(param, param_no);
}


int fixup_pvar_null(void **param, int param_no)
{
	if(param_no != 1)
		return E_UNSPEC;
	return fixup_pvar_all(param, param_no);
}


int fixup_free_pvar_null(void **param, int param_no)
{
	if(param_no != 1)
		return E_UNSPEC;
	return fixup_free_pvar_all(param, param_no);
}

int fixup_pvar_none(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_pvar_all(param, param_no);
	return 0;
}


int fixup_free_pvar_none(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_pvar_all(param, param_no);
	return 0;
}


/* must be written "by hand", see above (fixup_pvar_pvar).
FIXUP_F2T(pvar_str, 1, 2, 1, FPARAM_PVS, FPARAM_STR)
FIXUP_F2T(pvar_str_str, 1, 3, 1, FPARAM_PVS, FPARAM_STR)
*/

int fixup_pvar_str(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_pvar_all(param, param_no);
	else if(param_no == 2)
		return fixup_str_str(param, param_no);
	return E_UNSPEC;
}


int fixup_free_pvar_str(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_pvar_all(param, param_no);
	else if(param_no == 2)
		return fixup_free_str_str(param, param_no);
	return E_UNSPEC;
}


int fixup_pvar_str_str(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_pvar_all(param, param_no);
	else if(param_no == 2 || param_no == 3)
		return fixup_str_all(param, param_no);
	return E_UNSPEC;
}


int fixup_free_pvar_str_str(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_pvar_all(param, param_no);
	else if(param_no == 2 || param_no == 3)
		return fixup_free_str_all(param, param_no);
	return E_UNSPEC;
}


int fixup_pvar_uint(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_pvar_all(param, param_no);
	else if(param_no == 2)
		return fixup_uint_uint(param, param_no);
	return E_UNSPEC;
}


int fixup_free_pvar_uint(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_pvar_all(param, param_no);
	return E_UNSPEC;
}


FIXUP_F2FP(igp_null, 1, 1, 1, FPARAM_INT | FPARAM_PVS, 0)
FIXUP_F2FP(igp_igp, 1, 2, 2, FPARAM_INT | FPARAM_PVS, 0)

/* must be declared by hand, because of the pvar special handling
   (see above)
FIXUP_F2FP(igp_pvar, 1, 2, 1,  FPARAM_INT|FPARAM_PVS, FPARAM_PVS)
FIXUP_F2FP_T(igp_pvar_pvar, 1, 3, 1, FPARAM_INT|FPARAM_PVS, FPARAM_PVS)
*/

int fixup_igp_pvar(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_igp_null(param, param_no);
	else if(param_no == 2)
		return fixup_pvar_all(param, param_no);
	return E_UNSPEC;
}


int fixup_free_igp_pvar(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_igp_null(param, param_no);
	else if(param_no == 2)
		return fixup_free_pvar_all(param, param_no);
	return E_UNSPEC;
}


int fixup_igp_pvar_pvar(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_igp_null(param, param_no);
	else if(param_no == 2 || param_no == 3)
		return fixup_pvar_all(param, param_no);
	return E_UNSPEC;
}


int fixup_free_igp_pvar_pvar(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_igp_null(param, param_no);
	else if(param_no == 2 || param_no == 3)
		return fixup_free_pvar_all(param, param_no);
	return E_UNSPEC;
}


int fixup_igp_spve(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_igp_null(param, param_no);
	else if(param_no == 2)
		return fixup_spve_all(param, param_no);
	return E_UNSPEC;
}


int fixup_free_igp_spve(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_igp_null(param, param_no);
	else if(param_no == 2)
		return fixup_free_spve_all(param, param_no);
	return E_UNSPEC;
}


/** macro for declaring a spve fixup and the corresponding free_fixup
  * for a function expecting first no1 params as fparam converted spve
  * and the * rest as direct type.
  *
  * @see FIXUP_F2FP for the parameters with the exception
  * that the first no1 parameters are converted to fparam_t from spve
  * and the rest directly to the corresponding type
  *
  * Side effect: declares also some _spvet_helper functions
  */
#define FIXUP_F_SPVE_T(suffix, minp, maxp, no1, type2)                 \
	FIXUP_F1T(spvet_##suffix, minp, maxp, type2)                       \
	int fixup_##suffix(void **param, int param_no)                     \
	{                                                                  \
		int ret;                                                       \
		fparam_t *fp;                                                  \
		if(param_no <= (no1)) {                                        \
			if((ret = fix_param_types(FPARAM_PVE, param)) < 0) {       \
				ERR("Cannot convert function parameter %d to spve \n", \
						param_no);                                     \
				return E_UNSPEC;                                       \
			} else {                                                   \
				fp = (fparam_t *)*param;                               \
				if((ret == 0)                                          \
						&& (fp->v.pve->spec == 0                       \
								|| fp->v.pve->spec->getf == 0)) {      \
					fparam_free_restore(param);                        \
					return fix_param_types(FPARAM_STR, param);         \
				} else if(ret == 1)                                    \
					return fix_param_types(FPARAM_STR, param);         \
				return ret;                                            \
			}                                                          \
		} else                                                         \
			return fixup_spvet_##suffix(param, param_no);              \
		return 0;                                                      \
	}                                                                  \
	int fixup_free_##suffix(void **param, int param_no)                \
	{                                                                  \
		if(param && *param) {                                          \
			if(param_no <= (no1))                                      \
				fparam_free_restore(param);                            \
			else                                                       \
				return fixup_free_spvet_##suffix(param, param_no);     \
		}                                                              \
		return 0;                                                      \
	}


/* format: name, minp, maxp, no_of_spve_params, type_for_rest_params */
FIXUP_F_SPVE_T(spve_spve, 1, 2, 2, 0)
FIXUP_F_SPVE_T(spve_uint, 1, 2, 1, FPARAM_INT)
FIXUP_F_SPVE_T(spve_str, 1, 2, 1, FPARAM_STR)
FIXUP_F_SPVE_T(spve_null, 1, 1, 1, 0)

/** get the corresp. fixup_free* function.
 * @param f -fixup function pointer.
 * @return  - pointer to free_fixup function if known, 0 otherwise.
 */
free_fixup_function mod_fix_get_fixup_free(fixup_function f)
{
	if(f == fixup_str_null)
		return fixup_free_str_null;
	if(f == fixup_str_str)
		return fixup_free_str_str;
	/* no free fixup for fixup_uint_* (they overwrite the pointer
	   value with a number and the original value cannot be recovered) */
	if(f == fixup_uint_null)
		return 0;
	if(f == fixup_uint_uint)
		return 0;
	if(f == fixup_regexp_null)
		return fixup_free_regexp_null;
	if(f == fixup_pvar_null)
		return fixup_free_pvar_null;
	if(f == fixup_pvar_pvar)
		return fixup_free_pvar_pvar;
	if(f == fixup_pvar_str)
		return fixup_free_pvar_str;
	if(f == fixup_pvar_str_str)
		return fixup_free_pvar_str_str;
	if(f == fixup_igp_igp)
		return fixup_free_igp_igp;
	if(f == fixup_igp_null)
		return fixup_free_igp_null;
	if(f == fixup_igp_pvar)
		return fixup_free_igp_pvar;
	if(f == fixup_igp_pvar_pvar)
		return fixup_free_igp_pvar_pvar;
	if(f == fixup_spve_spve)
		return fixup_free_spve_spve;
	if(f == fixup_spve_null)
		return fixup_free_spve_null;
	/* no free fixup, because of the uint part (the uint cannot be freed,
	   see above fixup_uint_null) */
	if(f == fixup_spve_uint)
		return 0;
	if(f == fixup_spve_str)
		return fixup_free_spve_str;
	return 0;
}

/**
 *
 */
int fixup_spve_all(void **param, int param_no)
{
	return fixup_spve_null(param, 1);
}

/**
 *
 */
int fixup_free_spve_all(void **param, int param_no)
{
	return fixup_free_spve_null(param, 1);
}

/**
 *
 */
int fixup_igp_all(void **param, int param_no)
{
	return fixup_igp_null(param, 1);
}

/**
 *
 */
int fixup_free_igp_all(void **param, int param_no)
{
	return fixup_free_igp_null(param, 1);
}

/**
 *
 */
int fixup_spve_igp(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_spve_null(param, 1);
	if(param_no == 2)
		return fixup_igp_null(param, 1);
	return E_UNSPEC;
}

/**
 *
 */
int fixup_free_spve_igp(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_spve_null(param, 1);
	if(param_no == 2)
		return fixup_free_igp_null(param, 1);
	return E_UNSPEC;
}

/**
 *
 */
int fixup_spve_spve_igp(void **param, int param_no)
{
	if(param_no == 1 || param_no == 2)
		return fixup_spve_null(param, 1);
	if(param_no == 3)
		return fixup_igp_null(param, 1);
	return E_UNSPEC;
}

/**
 *
 */
int fixup_free_spve_spve_igp(void **param, int param_no)
{
	if(param_no == 1 || param_no == 2)
		return fixup_free_spve_null(param, 1);
	if(param_no == 3)
		return fixup_free_igp_null(param, 1);
	return E_UNSPEC;
}

/**
 *
 */
int fixup_spve_pvar(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_spve_null(param, 1);
	if(param_no == 2)
		return fixup_pvar_null(param, 1);
	return E_UNSPEC;
}

/**
 *
 */
int fixup_free_spve_pvar(void **param, int param_no)
{
	if(param_no == 1)
		return fixup_free_spve_null(param, 1);
	if(param_no == 2)
		return fixup_free_pvar_null(param, 1);
	return E_UNSPEC;
}

/**
 *
 */
int fixup_none_spve(void **param, int param_no)
{
	if(param_no == 2)
		return fixup_spve_null(param, 1);
	return 0;
}

/**
 *
 */
int fixup_free_none_spve(void **param, int param_no)
{
	if(param_no == 2)
		return fixup_free_spve_null(param, 1);
	return 0;
}


/**
 *
 */
int fixup_vstr_all(void **param, int param_no)
{
	str s;
	pv_elem_t *xm;

	s.s = (char *)(*param);
	s.len = strlen(s.s);
	if(pv_parse_format(&s, &xm) < 0) {
		LM_ERR("invalid parameter format [%s]\n", (char *)(*param));
		return E_UNSPEC;
	}
	*param = (void *)xm;
	return 0;
}

/**
 *
 */
int fixup_free_vstr_all(void **param, int param_no)
{
	pv_elem_free_all((pv_elem_t *)(*param));
	return 0;
}

/**
 *
 */
int fixup_get_vstr_buf(sip_msg_t *msg, pv_elem_t *p, char *buf, int blen)
{
	if(pv_printf(msg, p, buf, &blen) < 0) {
		LM_ERR("unable to get the value\n");
		return -1;
	}
	return -1;
}

/**
 *
 */
int fixup_ssi(void **param, int param_no)
{
	switch(param_no) {
		case 1:
		case 2:
			return fixup_spve_null(param, 1);
		case 3:
			return fixup_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_free_ssi(void **param, int param_no)
{
	switch(param_no) {
		case 1:
		case 2:
			return fixup_free_spve_null(param, 1);
		case 3:
			return fixup_free_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_sii(void **param, int param_no)
{
	switch(param_no) {
		case 1:
			return fixup_spve_null(param, 1);
		case 2:
		case 3:
			return fixup_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_free_sii(void **param, int param_no)
{
	switch(param_no) {
		case 1:
			return fixup_free_spve_null(param, 1);
		case 2:
		case 3:
			return fixup_free_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_sssi(void **param, int param_no)
{
	switch(param_no) {
		case 1:
		case 2:
		case 3:
			return fixup_spve_null(param, 1);
		case 4:
			return fixup_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_free_sssi(void **param, int param_no)
{
	switch(param_no) {
		case 1:
		case 2:
		case 3:
			return fixup_free_spve_null(param, 1);
		case 4:
			return fixup_free_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_ssii(void **param, int param_no)
{
	switch(param_no) {
		case 1:
		case 2:
			return fixup_spve_null(param, 1);
		case 3:
		case 4:
			return fixup_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}

/**
 *
 */
int fixup_free_ssii(void **param, int param_no)
{
	switch(param_no) {
		case 1:
		case 2:
			return fixup_free_spve_null(param, 1);
		case 3:
		case 4:
			return fixup_free_igp_null(param, 1);
		default:
			return E_UNSPEC;
	}
}
