static void group_target(tree_t t, group_nets_ctx_t *ctx) { switch (tree_kind(t)) { case T_REF: group_ref(t, ctx, 0, -1); break; case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { type_t type = tree_type(t); if (!type_known_width(type)) ungroup_name(t, ctx); else if (!group_name(t, ctx, 0, type_width(type))) ungroup_name(t, ctx); } break; case T_LITERAL: case T_OPEN: // Constant folding can cause this to appear break; case T_AGGREGATE: { const int nassocs = tree_assocs(t); for (int i = 0; i < nassocs; i++) group_target(tree_value(tree_assoc(t, i)), ctx); } break; default: fmt_loc(stdout, tree_loc(t)); fatal_trace("Cannot handle tree kind %s in group_target", tree_kind_str(tree_kind(t))); } }
static bool group_name(tree_t target, group_nets_ctx_t *ctx, int start, int n) { switch (tree_kind(target)) { case T_REF: group_ref(target, ctx, start, n); return true; case T_ARRAY_REF: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; int offset = 0; const int nparams = tree_params(target); for (int i = 0; i < nparams; i++) { tree_t index = tree_value(tree_param(target, i)); const int stride = type_width(type_elem(type)); if (tree_kind(index) != T_LITERAL) { if (i > 0) return false; const int twidth = type_width(type); for (int j = 0; j < twidth; j += stride) group_name(value, ctx, start + j, n); return true; } else { if (i > 0) { range_t type_r = range_of(type, i); int64_t low, high; range_bounds(type_r, &low, &high); offset *= high - low + 1; } offset += stride * rebase_index(type, i, assume_int(index)); } } return group_name(value, ctx, start + offset, n); } case T_ARRAY_SLICE: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; // Only in procedure range_t slice = tree_range(target, 0 ); if (tree_kind(slice.left) != T_LITERAL || tree_kind(slice.right) != T_LITERAL) return false; int64_t low, high; range_bounds(slice, &low, &high); const int64_t low0 = rebase_index(type, 0, assume_int(slice.left)); const int stride = type_width(type_elem(type)); return group_name(value, ctx, start + low0 * stride, n); } case T_RECORD_REF: { tree_t value = tree_value(target); type_t rec = tree_type(value); const int offset = record_field_to_net(rec, tree_ident(target)); return group_name(value, ctx, start + offset, n); } case T_AGGREGATE: case T_LITERAL: // This can appear due to assignments to open ports with a // default value return true; default: fatal_at(tree_loc(target), "tree kind %s not yet supported for offset " "calculation", tree_kind_str(tree_kind(target))); } }
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; }