sai_status_t mlnx_sched_hierarchy_foreach(mlnx_port_config_t    *port,
                                          mlnx_sched_obj_iter_t  iter,
                                          mlnx_sched_iter_ctx_t *ctx)
{
    mlnx_qos_queue_config_t *queue;
    mlnx_iter_ret_t          ret;
    uint32_t                 ii, lvl;

    assert(iter != NULL);

    for (lvl = 0; lvl < MAX_SCHED_LEVELS; lvl++) {
        for (ii = 0; ii < level_max_groups(lvl); ii++) {
            ret = iter(port, group_get(port, lvl, ii), ctx);
            if (ret == ITER_STOP) {
                goto out;
            }
        }
    }

    port_queues_foreach(port, queue, ii) {
        ret = iter(port, &queue->sched_obj, ctx);
        if (ret == ITER_STOP) {
            goto out;
        }
    }
Exemplo n.º 2
0
void prot_group_download_labels_reply( struct qqclient* qq, qqpacket* p )
{
	bytebuffer *buf = p->buf;
	uchar cmd = get_byte( buf );
	if( cmd == 0x1F ){	//download
		uint next_pos = get_int( buf );
		if( next_pos == 0x1000000 ){	//no group labels info ??
			return;
		}
		if( next_pos != 0x00 ){
			DBG("next_pos == 0x%x", next_pos );
		}
		get_byte( buf );	//unknown
		get_word( buf );
		uchar len;
		while( buf->pos < buf->len ){
			uchar number = get_byte( buf );
			get_byte( buf );
			len = get_byte( buf );
			//temp seems to be utf8 code
			qqgroup *g = group_get( qq, number, 1 );
			if( g == NULL )
				continue;
			memset( g->name, 0, NICKNAME_LEN );
			get_data( buf, (uchar*)g->name, len );
//			DBG("group id: %u  name: %s", g->number, g->name );
		}
		group_put_event( qq );
		buddy_put_event( qq );
	}else{
		DBG("unknown cmd=%x", cmd );
	}
}
Exemplo n.º 3
0
/*
 * Accept a set of transforms offered by the initiator and chose one we can
 * handle.
 */
int
ike_phase_1_responder_recv_SA (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct sa *sa = TAILQ_FIRST (&exchange->sa_list);
    struct ipsec_sa *isa = sa->data;
    struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
    struct payload *prop = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL]);
    struct ipsec_exch *ie = exchange->data;

    /* Mark the SA as handled.  */
    sa_p->flags |= PL_MARK;

    /* IKE requires that only one SA with only one proposal exists.  */
    if (TAILQ_NEXT (sa_p, link) || TAILQ_NEXT (prop, link))
    {
        log_print ("ike_phase_1_responder_recv_SA: "
                   "multiple SA or proposal payloads in phase 1");
        /* XXX Is there a better notification type?  */
        message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
        return -1;
    }

    /* Chose a transform from the SA.  */
    if (message_negotiate_sa (msg, ike_phase_1_validate_prop)
            || !TAILQ_FIRST (&sa->protos))
        return -1;

    /* XXX Move into message_negotiate_sa?  */
    ipsec_decode_transform (msg, sa, TAILQ_FIRST (&sa->protos),
                            TAILQ_FIRST (&sa->protos)->chosen->p);

    ie->group = group_get (isa->group_desc);

    /*
     * Check that the mandatory attributes: encryption, hash, authentication
     * method and Diffie-Hellman group description, has been supplied.
     */
    if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group)
    {
        message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
        return -1;
    }

    /* Save the body for later hash computation.  */
    ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH (sa_p->p) - ISAKMP_GEN_SZ;
    ie->sa_i_b = malloc (ie->sa_i_b_len);
    if (!ie->sa_i_b)
    {
        /* XXX How to notify peer?  */
        log_error ("ike_phase_1_responder_recv_SA: malloc (%lu) failed",
                   (unsigned long)ie->sa_i_b_len);
        return -1;
    }
    memcpy (ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ, ie->sa_i_b_len);

    return 0;
}
Exemplo n.º 4
0
int
main(void)
{
	int len, id;
	char buf[DH_MAXSZ], buf2[DH_MAXSZ];
	char sec[DH_MAXSZ], sec2[DH_MAXSZ];
	struct group *group, *group2;
	const char *name[] = { "MODP", "EC2N", "ECP" };

	group_init();

	for (id = 0; id < 0xff; id++) {
		if ((group = group_get(id)) == NULL ||
		    (group2 = group_get(id)) == NULL)
			continue;

		printf ("Testing group %d (%s%d): ", id,
		    name[group->spec->type],
		    group->spec->bits);

		len = dh_getlen(group);

		dh_create_exchange(group, buf);
		dh_create_exchange(group2, buf2);

		dh_create_shared(group, sec, buf2);
		dh_create_shared(group2, sec2, buf);

		if (memcmp (sec, sec2, len)) {
			printf("FAILED\n");
			return (1);
		} else
			printf("OKAY\n");

		group_free(group);
		group_free(group2);
	}

	return (0);
}
Exemplo n.º 5
0
/* Figure out what transform the responder chose.  */
int
ike_phase_1_initiator_recv_SA (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct sa *sa = TAILQ_FIRST (&exchange->sa_list);
    struct ipsec_exch *ie = exchange->data;
    struct ipsec_sa *isa = sa->data;
    struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
    struct payload *prop = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL]);
    struct payload *xf = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]);

    /*
     * IKE requires that only one SA with only one proposal exists and since
     * we are getting an answer on our transform offer, only one transform.
     */
    if (TAILQ_NEXT (sa_p, link) || TAILQ_NEXT (prop, link)
            || TAILQ_NEXT (xf, link))
    {
        log_print ("ike_phase_1_initiator_recv_SA: "
                   "multiple SA, proposal or transform payloads in phase 1");
        /* XXX Is there a better notification type?  */
        message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
        return -1;
    }

    /* Check that the chosen transform matches an offer.  */
    if (message_negotiate_sa (msg, ike_phase_1_validate_prop)
            || !TAILQ_FIRST (&sa->protos))
        return -1;

    ipsec_decode_transform (msg, sa, TAILQ_FIRST (&sa->protos), xf->p);

    /* XXX I don't like exchange-specific stuff in here.  */
    if (exchange->type != ISAKMP_EXCH_AGGRESSIVE)
        ie->group = group_get (isa->group_desc);

    /* Mark the SA as handled.  */
    sa_p->flags |= PL_MARK;

    return 0;
}
Exemplo n.º 6
0
int
ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
    struct iked_message *msg, off_t offset)
{
	struct ikev2_notify	*n;
	u_int8_t		*buf, md[SHA_DIGEST_LENGTH];
	size_t			 len;
	u_int32_t		 spi32;
	u_int64_t		 spi64;
	struct iked_spi		*rekey;
	u_int16_t		 type;
	u_int16_t		 group;

	if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL)
		return (-1);
	type = betoh16(n->n_type);

	log_debug("%s: protoid %s spisize %d type %s",
	    __func__,
	    print_map(n->n_protoid, ikev2_saproto_map), n->n_spisize,
	    print_map(type, ikev2_n_map));

	len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*n);
	if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(*n), len)) == NULL)
		return (-1);

	print_hex(buf, 0, len);

	if (!ikev2_msg_frompeer(msg))
		return (0);

	switch (type) {
	case IKEV2_N_NAT_DETECTION_SOURCE_IP:
	case IKEV2_N_NAT_DETECTION_DESTINATION_IP:
		if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1)
			return (-1);
		if (len != sizeof(md) || memcmp(buf, md, len) != 0) {
			log_debug("%s: %s detected NAT, enabling "
			    "UDP encapsulation", __func__,
			    print_map(type, ikev2_n_map));

			/*
			 * Enable UDP encapsulation of ESP packages if
			 * the check detected NAT.
			 */
			if (msg->msg_sa != NULL)
				msg->msg_sa->sa_udpencap = 1;
		}
		print_hex(md, 0, sizeof(md));
		break;
	case IKEV2_N_INVALID_KE_PAYLOAD:
		if (len != sizeof(group)) {
			log_debug("%s: malformed notification", __func__);
			return (-1);
		}
		if (!msg->msg_sa->sa_hdr.sh_initiator) {
			log_debug("%s: not an initiator", __func__);
			sa_free(env, msg->msg_sa);
			msg->msg_sa = NULL;
			return (-1);
		}
		memcpy(&group, buf, len);
		group = betoh16(group);
		if ((msg->msg_policy->pol_peerdh = group_get(group))
		    == NULL) {
			log_debug("%s: unable to select DH group %d", __func__,
			    group);
			return (-1);
		}
		log_debug("%s: responder selected DH group %d", __func__,
		    group);
		sa_free(env, msg->msg_sa);
		msg->msg_sa = NULL;
		timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa,
		    NULL);
		timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL);
		break;
	case IKEV2_N_NO_ADDITIONAL_SAS:
		/* This makes sense for Child SAs only atm */
		if (msg->msg_sa->sa_stateflags & IKED_REQ_CHILDSA) {
			ikev2_disable_rekeying(env, msg->msg_sa);
			msg->msg_sa->sa_stateflags &= ~IKED_REQ_CHILDSA;
		}
		break;
	case IKEV2_N_REKEY_SA:
		if (len != n->n_spisize) {
			log_debug("%s: malformed notification", __func__);
			return (-1);
		}
		rekey = &msg->msg_parent->msg_rekey;
		if (rekey->spi != 0) {
			log_debug("%s: rekeying of multiple SAs not supported",
			    __func__);
			return (-1);
		}
		switch (n->n_spisize) {
		case 4:
			memcpy(&spi32, buf, len);
			rekey->spi = betoh32(spi32);
			break;
		case 8:
			memcpy(&spi64, buf, len);
			rekey->spi = betoh64(spi64);
			break;
		default:
			log_debug("%s: invalid spi size %d", __func__,
			    n->n_spisize);
			return (-1);
		}
		rekey->spi_size = n->n_spisize;
		rekey->spi_protoid = n->n_protoid;

		log_debug("%s: rekey %s spi %s", __func__,
		    print_map(n->n_protoid, ikev2_saproto_map),
		    print_spi(rekey->spi, n->n_spisize));
		break;
	}

	return (0);
}
Exemplo n.º 7
0
/* Offer a set of transforms to the responder in the MSG message.  */
int
ike_phase_1_initiator_send_SA (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct ipsec_exch *ie = exchange->data;
    u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr;
    u_int8_t **transform = 0;
    size_t transforms_len = 0, proposal_len, sa_len;
    size_t *transform_len = 0;
    struct conf_list *conf, *life_conf;
    struct conf_list_node *xf, *life;
    int i, value, update_nextp;
    struct payload *p;
    struct proto *proto;
    int group_desc = -1, new_group_desc;

    /* Get the list of transforms.  */
    conf = conf_get_list (exchange->policy, "Transforms");
    if (!conf)
        return -1;

    transform = calloc (conf->cnt, sizeof *transform);
    if (!transform)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (%d, %lu) failed",
                   conf->cnt, (unsigned long)sizeof *transform);
        goto bail_out;
    }

    transform_len = calloc (conf->cnt, sizeof *transform_len);
    if (!transform_len)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (%d, %lu) failed",
                   conf->cnt, (unsigned long)sizeof *transform_len);
        goto bail_out;
    }

    for (xf = TAILQ_FIRST (&conf->fields), i = 0; i < conf->cnt;
            i++, xf = TAILQ_NEXT (xf, link))
    {
        /* XXX The sizing needs to be dynamic.  */
        transform[i]
            = malloc (ISAKMP_TRANSFORM_SA_ATTRS_OFF + 16 * ISAKMP_ATTR_VALUE_OFF);
        if (!transform[i])
        {
            log_error ("ike_phase_1_initiator_send_SA: malloc (%d) failed",
                       ISAKMP_TRANSFORM_SA_ATTRS_OFF
                       + 16 * ISAKMP_ATTR_VALUE_OFF);
            goto bail_out;
        }

        SET_ISAKMP_TRANSFORM_NO (transform[i], i);
        SET_ISAKMP_TRANSFORM_ID (transform[i], IPSEC_TRANSFORM_KEY_IKE);
        SET_ISAKMP_TRANSFORM_RESERVED (transform[i], 0);

        attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;

        if (attribute_set_constant (xf->field, "ENCRYPTION_ALGORITHM",
                                    ike_encrypt_cst,
                                    IKE_ATTR_ENCRYPTION_ALGORITHM, &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "HASH_ALGORITHM", ike_hash_cst,
                                    IKE_ATTR_HASH_ALGORITHM, &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "AUTHENTICATION_METHOD",
                                    ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD,
                                    &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "GROUP_DESCRIPTION",
                                    ike_group_desc_cst,
                                    IKE_ATTR_GROUP_DESCRIPTION, &attr))
        {
            /*
             * If no group description exists, try looking for a user-defined
             * one.
             */
            if (attribute_set_constant (xf->field, "GROUP_TYPE", ike_group_cst,
                                        IKE_ATTR_GROUP_TYPE, &attr))
                goto bail_out;

#if 0
            if (attribute_set_bignum (xf->field, "GROUP_PRIME",
                                      IKE_ATTR_GROUP_PRIME, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
                                      IKE_ATTR_GROUP_GENERATOR_2, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
                                      IKE_ATTR_GROUP_GENERATOR_2, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_CURVE_A",
                                      IKE_ATTR_GROUP_CURVE_A, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_CURVE_B",
                                      IKE_ATTR_GROUP_CURVE_B, &attr))
                goto bail_out;
#endif
        }

        /*
         * Life durations are special, we should be able to specify
         * several, one per type.
         */
        life_conf = conf_get_list (xf->field, "Life");
        if (life_conf)
        {
            for (life = TAILQ_FIRST (&life_conf->fields); life;
                    life = TAILQ_NEXT (life, link))
            {
                attribute_set_constant (life->field, "LIFE_TYPE",
                                        ike_duration_cst, IKE_ATTR_LIFE_TYPE,
                                        &attr);

                /* XXX Deals with 16 and 32 bit lifetimes only */
                value = conf_get_num (life->field, "LIFE_DURATION", 0);
                if (value)
                {
                    if (value <= 0xffff)
                        attr = attribute_set_basic (attr, IKE_ATTR_LIFE_DURATION,
                                                    value);
                    else
                    {
                        value = htonl (value);
                        attr = attribute_set_var (attr, IKE_ATTR_LIFE_DURATION,
                                                  (u_int8_t *)&value,
                                                  sizeof value);
                    }
                }
            }
            conf_free_list (life_conf);
        }

        attribute_set_constant (xf->field, "PRF", ike_prf_cst, IKE_ATTR_PRF,
                                &attr);

        value = conf_get_num (xf->field, "KEY_LENGTH", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_KEY_LENGTH, value);

        value = conf_get_num (xf->field, "FIELD_SIZE", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_FIELD_SIZE, value);

        value = conf_get_num (xf->field, "GROUP_ORDER", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_GROUP_ORDER, value);

        /* Record the real transform size.  */
        transforms_len += transform_len[i] = attr - transform[i];

        /* XXX I don't like exchange-specific stuff in here.  */
        if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
        {
            /*
             * Make sure that if a group description is specified, it is
             * specified for all transforms equally.
             */
            attr = (u_int8_t *)conf_get_str (xf->field, "GROUP_DESCRIPTION");
            new_group_desc
                = attr ? constant_value (ike_group_desc_cst, (char *)attr) : 0;
            if (group_desc == -1)
                group_desc = new_group_desc;
            else if (group_desc != new_group_desc)
            {
                log_print ("ike_phase_1_initiator_send_SA: "
                           "differing group descriptions in a proposal");
                goto bail_out;
            }
        }

        /* We need to check that we actually support our configuration.  */
        if (attribute_map (transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                           transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                           exchange->doi->is_attribute_incompatible, msg))
        {
            log_print ("ike_phase_1_initiator_send_SA: "
                       "section [%s] has unsupported attribute(s)",
                       xf->field);
            goto bail_out;
        }
    }

    /* XXX I don't like exchange-specific stuff in here.  */
    if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
        ie->group = group_get (group_desc);

    proposal_len = ISAKMP_PROP_SPI_OFF;
    proposal = malloc (proposal_len);
    if (!proposal)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)proposal_len);
        goto bail_out;
    }

    SET_ISAKMP_PROP_NO (proposal, 1);
    SET_ISAKMP_PROP_PROTO (proposal, ISAKMP_PROTO_ISAKMP);
    SET_ISAKMP_PROP_SPI_SZ (proposal, 0);
    SET_ISAKMP_PROP_NTRANSFORMS (proposal, conf->cnt);

    /* XXX I would like to see this factored out.  */
    proto = calloc (1, sizeof *proto);
    if (!proto)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (1, %lu) failed",
                   (unsigned long)sizeof *proto);
        goto bail_out;
    }

    proto->no = 1;
    proto->proto = ISAKMP_PROTO_ISAKMP;
    proto->sa = TAILQ_FIRST (&exchange->sa_list);
    TAILQ_INSERT_TAIL (&TAILQ_FIRST (&exchange->sa_list)->protos, proto,
                       link);

    sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
    sa_buf = malloc (sa_len);
    if (!sa_buf)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)sa_len);
        goto bail_out;
    }

    SET_ISAKMP_SA_DOI (sa_buf, IPSEC_DOI_IPSEC);
    SET_IPSEC_SIT_SIT (sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);

    /*
     * Add the payloads.  As this is a SA, we need to recompute the
     * lengths of the payloads containing others.
     */
    if (message_add_payload (msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
        goto bail_out;
    SET_ISAKMP_GEN_LENGTH (sa_buf,
                           sa_len + proposal_len + transforms_len);
    sa_buf = 0;

    saved_nextp = msg->nextp;
    if (message_add_payload (msg, ISAKMP_PAYLOAD_PROPOSAL, proposal,
                             proposal_len, 0))
        goto bail_out;
    SET_ISAKMP_GEN_LENGTH (proposal, proposal_len + transforms_len);
    proposal = 0;

    update_nextp = 0;
    for (i = 0; i < conf->cnt; i++)
    {
        if (message_add_payload (msg, ISAKMP_PAYLOAD_TRANSFORM, transform[i],
                                 transform_len[i], update_nextp))
            goto bail_out;
        update_nextp = 1;
        transform[i] = 0;
    }
    msg->nextp = saved_nextp;

    /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len.  */
    ie->sa_i_b_len = sa_len + proposal_len + transforms_len - ISAKMP_GEN_SZ;
    ie->sa_i_b = malloc (ie->sa_i_b_len);
    if (!ie->sa_i_b)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)ie->sa_i_b_len);
        goto bail_out;
    }
    memcpy (ie->sa_i_b,
            TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA])->p + ISAKMP_GEN_SZ,
            sa_len - ISAKMP_GEN_SZ);
    memcpy (ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
            TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL])->p,
            proposal_len);
    transforms_len = 0;
    for (i = 0, p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]);
            i < conf->cnt; i++, p = TAILQ_NEXT (p, link))
    {
        memcpy (ie->sa_i_b + sa_len + proposal_len + transforms_len
                - ISAKMP_GEN_SZ,
                p->p, transform_len[i]);
        transforms_len += transform_len[i];
    }

    conf_free_list (conf);
    free (transform);
    free (transform_len);
    return 0;

bail_out:
    if (sa_buf)
        free (sa_buf);
    if (proposal)
        free (proposal);
    if (transform)
    {
        for (i = 0; i < conf->cnt; i++)
            if (transform[i])
                free (transform[i]);
        free (transform);
    }
    if (transform_len)
        free (transform_len);
    conf_free_list (conf);
    return -1;
}
Exemplo n.º 8
0
Arquivo: conf.c Projeto: Oryon/pimbd
int conf_group_set(struct ipc_user *u, char *data, size_t len, __unused struct blob_buf *reply)
{
	conf conf = container_of(u, conf_s, ipc_users[CONF_IPC_GROUP_SET]);
	ifgroups igs = conf->igs;
	pim pim = conf->pim;
	struct blob_attr *tb[CONF_G_MAX];
	struct in6_addr grp, src;
	group g = NULL;
	source s = NULL;
	gsource gs = NULL;
	iface i = NULL;
	ifgroup ig = NULL;
	ifgsource ifgs = NULL;
	int join = 0, listen = 0, local = 0;
	char *str;
	int ret = 0;

	if(blobmsg_parse(conf_g_attrs, CONF_G_MAX, tb, data, len) ||
			!tb[CONF_G_GROUP] || !addr_pton(&grp, blobmsg_get_string(tb[CONF_G_GROUP])) ||
			!addr_is_multicast(&grp) ||
			(tb[CONF_G_SRC] && !addr_pton(&src, blobmsg_get_string(tb[CONF_G_SRC]))) ||
			(tb[CONF_G_LISTENER] && !tb[CONF_G_DEV]))
		return -EINVAL;

	if(tb[CONF_G_PIM]) {
		if(!(str = blobmsg_get_string(tb[CONF_G_PIM])))
			return -EINVAL;
		else if (!strcmp(str, "join"))
			join = PIM_JOIN;
		else if(!strcmp(str, "prune"))
			join = PIM_PRUNE;
		else if(!strcmp(str, "none"))
			join = PIM_NONE;
		else
			return -EINVAL;
	}

	if(tb[CONF_G_LISTENER]) {
		if(!(str = blobmsg_get_string(tb[CONF_G_LISTENER])))
			return -EINVAL;
		else if (!strcmp(str, "include"))
			listen = PIM_JOIN;
		else if(!strcmp(str, "exclude"))
			listen = PIM_PRUNE;
		else if(!strcmp(str, "none"))
			listen = PIM_NONE;
		else
			return -EINVAL;
	}

	if(tb[CONF_G_LOCAL]) {
		if(!(str = blobmsg_get_string(tb[CONF_G_LOCAL])))
			return -EINVAL;
		else if (!strcmp(str, "include"))
			local = PIM_JOIN;
		else if(!strcmp(str, "exclude"))
			local = PIM_PRUNE;
		else if(!strcmp(str, "none"))
			local = PIM_NONE;
		else
			return -EINVAL;
	}

	if((tb[CONF_G_LOCAL] && !tb[CONF_G_DEV]) ||
			(tb[CONF_G_LISTENER] && !tb[CONF_G_DEV]))
		return -EINVAL;

	if((tb[CONF_G_GROUP] && (!(g = group_get(igs, &grp, 1)) || !group_ref(g))) ||
			(tb[CONF_G_SRC] && ((!(s = source_get(igs, &src, 1)) || !group_ref(s)) ||
					(!(gs = gsource_get(g, s, 1)) || !gsource_ref(gs)))) ||
			(tb[CONF_G_DEV] && ((!(i = iface_get_byname(igs, blobmsg_get_string(tb[CONF_G_DEV]), 1)) || !iface_ref(i)) ||
							(!(ig = ifgroup_get(i, g, 1)) || !ifgroup_ref(ig)))) ||
							(ig && gs && (!(ifgs = ifgsource_get(ig, gs, 1)) || !ifgsource_ref(ifgs)))) {
		ret = -ENOMEM;
		goto out;
	}

	if(tb[CONF_G_PIM]) {
		if(gs) {
			L_INFO("Set configuration of gsource "GSOURCE_L" - pim_join_desired : %s", GSOURCE_LA(gs), PIM_STATE_STR(join));
			if(!gs->conf_join_desired)
				gsource_ref(gs);
			gs->conf_join_desired = join;
			pim_gsource_conf_changed(pim, gs);
			if(!gs->conf_join_desired)
				gsource_unref(gs);
		} else {
			L_INFO("Set configuration of group "GROUP_L" - pim_join_desired : %s", GROUP_LA(g), PIM_STATE_STR(join));
			if(!g->conf_join_desired)
				group_ref(g);
			g->conf_join_desired = join;
			pim_group_conf_changed(pim, g);
			if(!g->conf_join_desired)
				group_unref(g);
		}
	}

	if(tb[CONF_G_LOCAL]) {
		L_INFO("Set configuration of ifgroup "IFGROUP_L" - local_exclude : %d", IFGROUP_LA(ig), (local == PIM_PRUNE));
		if(!ig->conf_local_exclude)
			ifgroup_ref(ig);
		ig->conf_local_exclude = !!(local == PIM_PRUNE);
		pim_ifgroup_conf_changed(pim, ig);
		if(!ig->conf_local_exclude)
			ifgroup_unref(ig);
	}

	if (tb[CONF_G_LISTENER]) {
		if(ifgs) {
			listener_update_G_S(ifgs, LISTENER_CONF, listen == PIM_JOIN, listen == PIM_PRUNE);
		} else {
			listener_update_G(ig, LISTENER_CONF, listen == PIM_PRUNE);
		}
	}

out:
	if(ifgs)
		ifgsource_unref(ifgs);
	if(gs)
		gsource_unref(gs);
	if(ig)
		ifgroup_unref(ig);
	if(g)
		group_unref(g);
	if(s)
		source_unref(s);
	if(i)
		iface_unref(i);
	return ret;
}