Skip to content
Snippets Groups Projects
dslmngr.c 64.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	dsl_add_usds_to_blob("last_transmitted_signal", true, signals, bb);
    
    
    	blobmsg_add_u32(bb, "upbokle", line->upbokle);
    	dsl_add_int_to_blob("line_number", line->line_number, bb);
    
    	// noise_margin
    	long margins[] = { line->noise_margin.us, line->noise_margin.ds };
    	dsl_add_usds_to_blob("noise_margin", true, margins, bb);
    
    	// attenuation
    	long attenuations[] = { line->attenuation.us, line->attenuation.ds };
    	dsl_add_usds_to_blob("attenuation", true, attenuations, bb);
    
    	// power
    	long powers[] = { line->power.us, line->power.ds };
    	dsl_add_usds_to_blob("power", true, powers, bb);
    
    	// snrm_rmc
    	long rmc[] = { line->snrm_rmc.us, line->snrm_rmc.ds };
    	dsl_add_usds_to_blob("snrm_rmc", true, rmc, bb);
    
    	// bits_rmc_ps
    
    Jani Juvan's avatar
    Jani Juvan committed
    	dsl_add_sequence_to_blob("bits_rmc_ps_ds", false, line->bits_rmc_ps_ds.count,
    				 (const long *)line->bits_rmc_ps_ds.elements, bb);
    	dsl_add_sequence_to_blob("bits_rmc_ps_us", false, line->bits_rmc_ps_us.count,
    				 (const long *)line->bits_rmc_ps_us.elements, bb);
    
    
    	// fext_to_cancel_enable
    	void *table = blobmsg_open_table(bb, "fext_to_cancel_enable");
    	blobmsg_add_u8(bb, "us", line->fext_to_cancel_enable.us);
    	blobmsg_add_u8(bb, "ds", line->fext_to_cancel_enable.ds);
    	blobmsg_close_table(bb, table);
    
    	// etr
    	unsigned long etr[] = { line->etr.us, line->etr.ds };
    	dsl_add_usds_to_blob("etr", false, etr, bb);
    
    	// att_etr
    	unsigned long att_etr[] = { line->att_etr.us, line->att_etr.ds };
    	dsl_add_usds_to_blob("att_etr", false, att_etr, bb);
    
    	// min_eftr
    	unsigned long min_eftr[] = { line->min_eftr.us, line->min_eftr.ds };
    	dsl_add_usds_to_blob("min_eftr", false, min_eftr, bb);
    }
    
    
    int fast_status_all(struct ubus_context *ctx, struct ubus_object *obj,
    
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	static struct blob_buf bb;
    	struct fast_line line;
    	int retval = UBUS_STATUS_OK;
    
    	int i, max_line;
    	void *array_line, *table_line;
    
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    
    	array_line = blobmsg_open_array(&bb, DSL_OBJECT_LINE);
    	for (i = 0, max_line = dsl_get_line_number(); i < max_line; i++) {
    		if (xdsl_ops.get_fast_line_info == NULL || (*xdsl_ops.get_fast_line_info)(i, &line) != 0) {
    			retval = UBUS_STATUS_UNKNOWN_ERROR;
    			goto __ret;
    		}
    
    		// Line table
    		table_line = blobmsg_open_table(&bb, "");
    
    		// Line parameters
    		blobmsg_add_u32(&bb, "id", (unsigned int)i + 1);
    		fast_line_status_to_blob(&line, &bb);
    
    		blobmsg_close_table(&bb, table_line);
    
    	blobmsg_close_array(&bb, array_line);
    
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    __ret:
    	blob_buf_free(&bb);
    	return retval;
    }
    
    static void fast_line_stats_interval_to_blob(const struct fast_line_stats_interval *stats, struct blob_buf *bb)
    {
    	blobmsg_add_u64(bb, "errored_secs", stats->errored_secs);
    	blobmsg_add_u64(bb, "severely_errored_secs", stats->severely_errored_secs);
    	blobmsg_add_u64(bb, "loss", stats->loss);
    	blobmsg_add_u64(bb, "lors", stats->lors);
    	blobmsg_add_u64(bb, "uas", stats->uas);
    	blobmsg_add_u64(bb, "rtx_uc", stats->rtx_uc);
    	blobmsg_add_u64(bb, "rtx_tx", stats->rtx_tx);
    	blobmsg_add_u64(bb, "success_bsw", stats->success_bsw);
    	blobmsg_add_u64(bb, "success_sra", stats->success_sra);
    	blobmsg_add_u64(bb, "success_fra", stats->success_fra);
    	blobmsg_add_u64(bb, "success_rpa", stats->success_rpa);
    	blobmsg_add_u64(bb, "success_tiga", stats->success_tiga);
    }
    
    
    int fast_stats_all(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	int retval = UBUS_STATUS_OK;
    	static struct blob_buf bb;
    	enum dsl_stats_type type;
    
    Jani Juvan's avatar
    Jani Juvan committed
    	struct if_stats if_stats = {0};
    	struct fast_line_stats stats;
    
    	struct fast_line_stats_interval line_stats_interval;
    	int i, j, max_line;
    	void *array_line, *table_line, *table_interval;
    
    Jani Juvan's avatar
    Jani Juvan committed
    	char ifname[IFNAMSIZ];
    
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    	array_line = blobmsg_open_array(&bb, DSL_OBJECT_LINE);
    	for (i = 0, max_line = dsl_get_line_number(); i < max_line; i++) {
    		if (xdsl_ops.get_fast_line_stats == NULL || (*xdsl_ops.get_fast_line_stats)(i, &stats) != 0) {
    			retval = UBUS_STATUS_UNKNOWN_ERROR;
    			goto __ret;
    		}
    
    		// Line table
    		table_line = blobmsg_open_table(&bb, "");
    
    		// Line statistics
    		blobmsg_add_u32(&bb, "id", (unsigned int)i + 1);
    
    		if (uci_get_ifname(ifname, sizeof(ifname), true) == 0)
    			if_getstats(ifname, &if_stats);
    		dsl_if_stats_to_blob(&if_stats, &bb);
    
    		dsl_stats_to_blob(&stats, &bb);
    
    		// Line interval statistics
    		for (j = 0; j < ARRAY_SIZE(dsl_stats_types); j++) {
    			table_interval = blobmsg_open_table(&bb, dsl_stats_types[j].text);
    
    			if (xdsl_ops.get_fast_line_stats_interval == NULL || (*xdsl_ops.get_fast_line_stats_interval)
    				(i, dsl_stats_types[j].value, &line_stats_interval) != 0) {
    				retval = UBUS_STATUS_UNKNOWN_ERROR;
    				goto __ret;
    			}
    			fast_line_stats_interval_to_blob(&line_stats_interval, &bb);
    
    			blobmsg_close_table(&bb, table_interval);
    		}
    
    		// Close the table for one line
    		blobmsg_close_table(&bb, table_line);
    	}
    	blobmsg_close_array(&bb, array_line);
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    __ret:
    	blob_buf_free(&bb);
    
    	return retval;
    }
    
    static struct ubus_method fast_methods[] = {
    	{ .name = "status", .handler = fast_status_all },
    	{ .name = "stats", .handler = fast_stats_all }
    };
    static struct ubus_object_type fast_type = UBUS_OBJECT_TYPE("fast", fast_methods);
    static struct ubus_object fast_object = {
    	.name = "fast",
    	.type = &fast_type,
    	.methods = fast_methods,
    	.n_methods = ARRAY_SIZE(fast_methods),
    };
    
    int fast_line_status(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	static struct blob_buf bb;
    	struct fast_line line;
    	int retval = UBUS_STATUS_OK;
    	int num = -1;
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    	// Get line status
    	sscanf(obj->name, "fast.line.%d", &num);
    	num--;  // indexes start from 1 in ubus object
    
    	if (xdsl_ops.get_fast_line_info == NULL || (*xdsl_ops.get_fast_line_info)(num, &line) != 0) {
    		retval = UBUS_STATUS_UNKNOWN_ERROR;
    		goto __ret;
    	}
    	fast_line_status_to_blob(&line, &bb);
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    __ret:
    	blob_buf_free(&bb);
    	return retval;
    }
    
    
    int fast_line_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	static struct blob_buf bb;
    	enum dsl_stats_type type = DSL_STATS_QUARTERHOUR + 1;
    
    Jani Juvan's avatar
    Jani Juvan committed
    	struct if_stats if_stats = {0};
    	struct fast_line_stats stats;
    
    	struct fast_line_stats_interval stats_interval;
    	int retval = UBUS_STATUS_OK;
    	int num = -1;
    
    Jani Juvan's avatar
    Jani Juvan committed
    	char ifname[IFNAMSIZ];
    
    
    	// Parse and validation check the interval type if any
    
    	if ((retval = validate_interval_type(msg, &type)) != UBUS_STATUS_OK) {
    		return retval;
    
    	}
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    	// Get line number
    	sscanf(obj->name, "fast.line.%d", &num);
    
    	num--;  // indexes start from 1 in ubus object
    
    
    	// Get line interval statistics
    	if (type >= DSL_STATS_TOTAL && type <= DSL_STATS_QUARTERHOUR) {
    		if (xdsl_ops.get_fast_line_stats_interval == NULL || (*xdsl_ops.get_fast_line_stats_interval)
    			(num, type, &stats_interval) != 0) {
    			retval = UBUS_STATUS_UNKNOWN_ERROR;
    			goto __ret;
    		}
    		fast_line_stats_interval_to_blob(&stats_interval, &bb);
    	} else {
    
    Jani Juvan's avatar
    Jani Juvan committed
    		// Get interface counters
    
    		if (uci_get_ifname(ifname, sizeof(ifname), false) == 0)
    			if_getstats(ifname, &if_stats);
    		dsl_if_stats_to_blob(&if_stats, &bb);
    
    		// Get line statistics
    		if (xdsl_ops.get_fast_line_stats == NULL || (*xdsl_ops.get_fast_line_stats)(num, &stats) != 0) {
    			retval = UBUS_STATUS_UNKNOWN_ERROR;
    			goto __ret;
    		}
    		dsl_stats_to_blob(&stats, &bb);
    
    		// Get all interval statistics
    
    		for (i = 0; i < ARRAY_SIZE(dsl_stats_types); i++) {
    			table = blobmsg_open_table(&bb, dsl_stats_types[i].text);
    
    
    			if (xdsl_ops.get_fast_line_stats_interval == NULL || (*xdsl_ops.get_fast_line_stats_interval)
    
    				(num, dsl_stats_types[i].value, &stats_interval) != 0) {
    
    				retval = UBUS_STATUS_UNKNOWN_ERROR;
    				goto __ret;
    			}
    			fast_line_stats_interval_to_blob(&stats_interval, &bb);
    
    			blobmsg_close_table(&bb, table);
    		}
    	}
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    __ret:
    	blob_buf_free(&bb);
    	return retval;
    }
    
    static struct ubus_method fast_line_methods[] = {
    	{ .name = "status", .handler = fast_line_status },
    	UBUS_METHOD("stats", fast_line_stats_handler, dsl_stats_policy )
    };
    
    static struct ubus_object_type fast_line_type = UBUS_OBJECT_TYPE("fast.line", fast_line_methods);
    
    static const char *atm_link_type_str(enum atm_link_type type)
    {
    	const char *str = dsl_get_string_value(atm_link_types, type);
    
    	if (!str)
    		return "unknown";
    
    	return str;
    }
    
    static const char *atm_encap_str(enum atm_encapsulation encap)
    {
    	const char *str = dsl_get_string_value(atm_encapsulations, encap);
    
    	if (!str)
    		return "unknown";
    
    	return str;
    }
    
    static const char *atm_aal_str(enum atm_aal aal)
    {
    	switch (aal) {
    	case ATM_AAL1: return "aal1";
    	case ATM_AAL2: return "aal2";
    	case ATM_AAL3: return "aal3";
    	case ATM_AAL4: return "aal4";
    	case ATM_AAL5: return "aal5";
    	default: return "unknown";
    	}
    }
    
    static const char *atm_qos_class_str(enum atm_qos_class class)
    {
    	const char *str = dsl_get_string_value(atm_qos_classes, class);
    
    	if (!str)
    		return "unknown";
    
    	return str;
    }
    
    static void atm_add_dest_addr_to_blob(const struct atm_dest_addr *dest_addr, struct blob_buf *bb)
    {
    	void *table = blobmsg_open_table(bb, "dest_addr");
    	blobmsg_add_u32(bb, "vpi", dest_addr->vpi);
    	blobmsg_add_u32(bb, "vci", dest_addr->vci);
    	blobmsg_close_table(bb, table);
    }
    
    static void atm_link_status_to_blob(const struct atm_link *link, const struct atm_link_qos *qos, struct blob_buf *bb)
    {
    	void *array, *table;
    	int i;
    
    	blobmsg_add_string(bb, "status", dsl_if_status_str(link->status));
    	blobmsg_add_string(bb, "link_type", atm_link_type_str(link->link_type));
    	blobmsg_add_u8(bb, "auto_config", link->auto_config);
    	atm_add_dest_addr_to_blob(&link->dest_addr, bb);
    	blobmsg_add_string(bb, "encapsulation", atm_encap_str(link->encapsulation));
    	blobmsg_add_u8(bb, "fcs_preserved", link->fcs_preserved);
    
    	array = blobmsg_open_array(bb, "vc_search_list");
    	for (i = 0; i < link->vc_list_count; i++) {
    		atm_add_dest_addr_to_blob(&link->vc_search_list[i], bb);
    	}
    	blobmsg_close_array(bb, array);
    
    	blobmsg_add_string(bb, "aal", atm_aal_str(link->aal));
    
    	table = blobmsg_open_table(bb, "qos");
    	blobmsg_add_string(bb, "qos_class", atm_qos_class_str(qos->qos_class));
    	blobmsg_add_u32(bb, "peak_cell_rate", qos->peak_cell_rate);
    	blobmsg_add_u32(bb, "max_burst_size", qos->max_burst_size);
    	blobmsg_add_u32(bb, "sustainable_cell_rate", qos->sustainable_cell_rate);
    	blobmsg_close_table(bb, table);
    }
    
    int atm_link_status(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	static struct blob_buf bb;
    	struct atm_link link;
    	struct atm_link_qos qos;
    	int retval = UBUS_STATUS_OK;
    	int num = -1;
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    	// Get line status
    	sscanf(obj->name, "atm.link.%d", &num);
    
    	num--;  // indexes start from 1 in ubus object
    
    
    	if (atm_funcs.get_link_info == NULL || (*atm_funcs.get_link_info)(num, &link, &qos) != 0) {
    		retval = UBUS_STATUS_UNKNOWN_ERROR;
    		goto __ret;
    	}
    	atm_link_status_to_blob(&link, &qos, &bb);
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    __ret:
    	blob_buf_free(&bb);
    	return retval;
    }
    
    static void atm_link_stats_to_blob(const struct atm_link_stats *stats, struct blob_buf *bb)
    {
    	blobmsg_add_u64(bb, "transmitted_blocks", stats->transmitted_blocks);
    	blobmsg_add_u64(bb, "received_blocks", stats->received_blocks);
    	blobmsg_add_u64(bb, "crc_errors", stats->crc_errors);
    }
    
    int atm_link_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	static struct blob_buf bb;
    	struct atm_link_stats stats;
    	int retval = UBUS_STATUS_OK;
    	int num = -1;
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    	// Get line status
    	sscanf(obj->name, "atm.link.%d", &num);
    
    	num--;  // indexes start from 1 in ubus object
    
    
    	if (atm_funcs.get_link_stats == NULL || (*atm_funcs.get_link_stats)(num, &stats) != 0) {
    		retval = UBUS_STATUS_UNKNOWN_ERROR;
    		goto __ret;
    	}
    	atm_link_stats_to_blob(&stats, &bb);
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    
    __ret:
    	blob_buf_free(&bb);
    	return retval;
    }
    
    enum {
    	ATM_CONFIGURE_LINK_TYPE,
    	ATM_CONFIGURE_VPI,
    	ATM_CONFIGURE_VCI,
    	ATM_CONFIGURE_ENCAPSULATION,
    	ATM_CONFIGURE_QOS_CLASS,
    	ATM_CONFIGURE_PEAK_CELL_RATE,
    	ATM_CONFIGURE_MAX_BURST_SIZE,
    	ATM_CONFIGURE_SUSTAINABLE_CELL_RATE,
    	__ATM_CONFIGURE_MAX
    };
    
    static const struct blobmsg_policy atm_configure_policy[] = {
    	[ATM_CONFIGURE_LINK_TYPE] = { .name = "link_type", .type = BLOBMSG_TYPE_STRING },
    	[ATM_CONFIGURE_VPI] = { .name = "vpi", .type = BLOBMSG_TYPE_INT32 },
    	[ATM_CONFIGURE_VCI] = { .name = "vci", .type = BLOBMSG_TYPE_INT32 },
    	[ATM_CONFIGURE_ENCAPSULATION] = { .name = "encapsulation", .type = BLOBMSG_TYPE_STRING },
    	[ATM_CONFIGURE_QOS_CLASS] = { .name = "qos_class", .type = BLOBMSG_TYPE_STRING },
    	[ATM_CONFIGURE_PEAK_CELL_RATE] = { .name = "peak_cell_rate", .type = BLOBMSG_TYPE_INT32 },
    	[ATM_CONFIGURE_MAX_BURST_SIZE] = { .name = "max_burst_size", .type = BLOBMSG_TYPE_INT32 },
    	[ATM_CONFIGURE_SUSTAINABLE_CELL_RATE] = { .name = "sustainable_cell_rate", .type = BLOBMSG_TYPE_INT32 }
    };
    
    /**
     * Handler of UBUS call "atm.link.x configure"
     *
     * Calling example
     *
     * ubus call atm.link.0 configure "{'link_type':'eoa','vpi':8,'vci':35,'encapsulation':'llc',\
        'qos_class':'ubr','peak_cell_rate':10240,'max_burst_size':8124,'sustainable_cell_rate':9600}"
     *
     */
    int atm_link_configure(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	struct blob_attr *tb[__ATM_CONFIGURE_MAX];
    	struct atm_link link;
    	struct atm_link_qos qos;
    	int link_num = -1;
    
    	memset(&link, 0, sizeof(link));
    	memset(&qos, 0, sizeof(qos));
    
    	// Parse and validation check the input parameters
    	if (blobmsg_parse(atm_configure_policy, __ATM_CONFIGURE_MAX, tb, blob_data(msg), blob_len(msg)) != 0)
    		return UBUS_STATUS_INVALID_ARGUMENT;
    
    	// link_type
    	if (tb[ATM_CONFIGURE_LINK_TYPE]) {
    		const char *type_str = blobmsg_data(tb[ATM_CONFIGURE_LINK_TYPE]);
    		int type_enum = dsl_get_enum_value(atm_link_types, type_str);
    
    		if (type_enum == -1) {
    			DSLMNGR_LOG(LOG_ERR,
    				"Wrong argument for link_type. It should be like \"eoa\"\n");
    			return UBUS_STATUS_INVALID_ARGUMENT;
    		}
    		link.link_type = type_enum;
    
    		DSLMNGR_LOG(LOG_DEBUG, "link.link_type = %d(%s)\n", link.link_type, type_str);
    	}
    
    	// vpi & vci
    	if (tb[ATM_CONFIGURE_VPI] && tb[ATM_CONFIGURE_VCI]) {
    		link.dest_addr.vpi = blobmsg_get_u32(tb[ATM_CONFIGURE_VPI]);
    		link.dest_addr.vci = blobmsg_get_u32(tb[ATM_CONFIGURE_VCI]);
    
    		DSLMNGR_LOG(LOG_DEBUG, "link.dest_addr = { %d, %d }\n", link.dest_addr.vpi, link.dest_addr.vci);
    	}
    
    	// encapsulation
    	if (tb[ATM_CONFIGURE_ENCAPSULATION]) {
    		const char *encap_str = blobmsg_data(tb[ATM_CONFIGURE_ENCAPSULATION]);
    		int encap_enum = dsl_get_enum_value(atm_encapsulations, encap_str);
    
    		if (encap_enum == -1) {
    			DSLMNGR_LOG(LOG_ERR,
    				"Wrong argument for encapsulation. It should be like \"llc\"\n");
    			return UBUS_STATUS_INVALID_ARGUMENT;
    		}
    		link.encapsulation = encap_enum;
    
    		DSLMNGR_LOG(LOG_DEBUG, "link.encapsulation = %d(%s)\n", link.encapsulation, encap_str);
    	}
    
    	// qos_class
    	if (tb[ATM_CONFIGURE_QOS_CLASS]) {
    		const char *class_str = blobmsg_data(tb[ATM_CONFIGURE_QOS_CLASS]);
    		int class_enum = dsl_get_enum_value(atm_qos_classes, class_str);
    
    		if (class_enum == -1) {
    			DSLMNGR_LOG(LOG_ERR,
    				"Wrong argument for qos_class. It should be like \"ubr\"\n");
    			return UBUS_STATUS_INVALID_ARGUMENT;
    		}
    		qos.qos_class = class_enum;
    
    		DSLMNGR_LOG(LOG_DEBUG, "qos.qos_class = %d(%s)\n", qos.qos_class, class_str);
    	}
    
    	// peak_cell_rate
    	if (tb[ATM_CONFIGURE_PEAK_CELL_RATE]) {
    		qos.peak_cell_rate = blobmsg_get_u32(tb[ATM_CONFIGURE_PEAK_CELL_RATE]);
    
    		DSLMNGR_LOG(LOG_DEBUG, "qos.peak_cell_rate = %u\n", qos.peak_cell_rate);
    	}
    
    	// max_burst_size
    	if (tb[ATM_CONFIGURE_MAX_BURST_SIZE]) {
    		qos.max_burst_size = blobmsg_get_u32(tb[ATM_CONFIGURE_MAX_BURST_SIZE]);
    
    		DSLMNGR_LOG(LOG_DEBUG, "qos.max_burst_size = %u\n", qos.max_burst_size);
    	}
    
    	// sustainable_cell_rate
    	if (tb[ATM_CONFIGURE_SUSTAINABLE_CELL_RATE]) {
    		qos.sustainable_cell_rate = blobmsg_get_u32(tb[ATM_CONFIGURE_SUSTAINABLE_CELL_RATE]);
    
    		DSLMNGR_LOG(LOG_DEBUG, "qos.sustainable_cell_rate = %u\n", qos.sustainable_cell_rate);
    	}
    
    	// Get link number and call libdsl API
    	sscanf(obj->name, "atm.link.%d", &link_num);
    
    	link_num--;  // indexes start from 1 in ubus object
    
    	if (atm_funcs.configure(link_num, &link, &qos) != 0) {
    		DSLMNGR_LOG(LOG_ERR, "ATM link %d confuration failed\n", link_num);
    		return UBUS_STATUS_UNKNOWN_ERROR;
    	}
    
    	return 0;
    }
    
    static struct ubus_method atm_link_methods[] = {
    	{ .name = "status", .handler = atm_link_status },
    	{ .name = "stats",  .handler = atm_link_stats_handler },
    	UBUS_METHOD("configure", atm_link_configure,  atm_configure_policy)
    };
    
    static struct ubus_object_type atm_link_type = UBUS_OBJECT_TYPE("atm.link", atm_link_methods);
    
    static void ptm_link_status_to_blob(const struct ptm_link *link, struct blob_buf *bb)
    {
    	char mac[18];
    
    	blobmsg_add_string(bb, "status", dsl_if_status_str(link->status));
    	snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
    			link->mac_addr[0], link->mac_addr[1], link->mac_addr[2],
    			link->mac_addr[3], link->mac_addr[4], link->mac_addr[5]);
    	blobmsg_add_string(bb, "mac_addr", mac);
    }
    
    int ptm_link_status(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	static struct blob_buf bb;
    	struct ptm_link link;
    	int retval = UBUS_STATUS_OK;
    	int num = -1;
    
    	// Initialize the buffer
    	memset(&bb, 0, sizeof(bb));
    	blob_buf_init(&bb, 0);
    
    	// Get line status
    	sscanf(obj->name, "ptm.link.%d", &num);
    
    	num--;  // indexes start from 1 in ubus object
    
    
    	if (ptm_funcs.get_link_info == NULL || (*ptm_funcs.get_link_info)(num, &link) != 0) {
    		retval = UBUS_STATUS_UNKNOWN_ERROR;
    		goto __ret;
    	}
    	ptm_link_status_to_blob(&link, &bb);
    
    	// Send the reply
    	ubus_send_reply(ctx, req, bb.head);
    
    __ret:
    	blob_buf_free(&bb);
    	return retval;
    }
    
    static struct ubus_method ptm_link_methods[] = {
    	{ .name = "status", .handler = ptm_link_status }
    };
    
    static struct ubus_object_type ptm_link_type = UBUS_OBJECT_TYPE("ptm.link", ptm_link_methods);
    
    /**
     * Handler of UBUS call "dsl.line.x configure"
     *
     * Calling example
     *
     * ubus call dsl.line.0 configure "{'xtse':'01,02,ab,cd,41,52,f8,6e',\
        'vdsl2_profiles':'8a,8b,8c,8d,17a,30a,35b',\
        'fast_profiles':'106a,212a','data_gathering':true,'limit_mask':255,'us0_mask':511}"
     *
     */
    int dsl_line_configure(struct ubus_context *ctx, struct ubus_object *obj,
    		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
    {
    	struct blob_attr *tb[__DSL_CONFIGURE_MAX];
    	struct dsl_config_params cfg_params;
    	int line_num = -1, i;
    
    	if (!xdsl_ops.configure) {
    		DSLMNGR_LOG(LOG_ERR, "This function is not supported on the current platform yet\n");
    		return UBUS_STATUS_NOT_SUPPORTED;
    	}
    
    	memset(&cfg_params, 0, sizeof(cfg_params));
    
    	// Parse and validation check the input parameters
    	if (blobmsg_parse(dsl_configure_policy, __DSL_CONFIGURE_MAX, tb, blob_data(msg), blob_len(msg)) != 0)
    		return UBUS_STATUS_INVALID_ARGUMENT;
    
    	// XTSE
    	if (tb[DSL_CONFIGURE_XTSE]) {
    		const char *xtse_str = blobmsg_data(tb[DSL_CONFIGURE_XTSE]);
    
    		if (!xtse_str || !*xtse_str ||
    			sscanf(xtse_str, "%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx",
    					&cfg_params.xtse[0],&cfg_params.xtse[1],&cfg_params.xtse[2],&cfg_params.xtse[3],
    					&cfg_params.xtse[4],&cfg_params.xtse[5],&cfg_params.xtse[6],&cfg_params.xtse[7]) != 8) {
    			DSLMNGR_LOG(LOG_ERR, "Wrong argument for xtse. It should be like \"01,02,ab,cd,41,52,f8,6e\"\n");
    			return UBUS_STATUS_INVALID_ARGUMENT;
    		}
    		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.xtse = {%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx}\n",
    				cfg_params.xtse[0],cfg_params.xtse[1],cfg_params.xtse[2],cfg_params.xtse[3],
    				cfg_params.xtse[4],cfg_params.xtse[5],cfg_params.xtse[6],cfg_params.xtse[7]);
    	}
    
    	// VDSL2 profiles
    	if (tb[DSL_CONFIGURE_VDSL2_PROFILES]) {
    		const char *profiles_str = blobmsg_data(tb[DSL_CONFIGURE_VDSL2_PROFILES]);
    		char *dup, *token, *saveptr;
    
    		if (!profiles_str || !*profiles_str) {
    			DSLMNGR_LOG(LOG_ERR,
    				"Wrong argument for vdsl2_profiles. It should be like \"8a,8b,8c,8d,17a,30a,35b\"\n");
    			return UBUS_STATUS_INVALID_ARGUMENT;
    		}
    
    		dup = alloca(strlen(profiles_str) + 1);
    
    		strncpy(dup, profiles_str, strlen(profiles_str) + 1);
    
    		for (token = strtok_r(dup, ",", &saveptr); token != NULL; token = strtok_r(NULL, ",", &saveptr)) {
    			int profile = dsl_get_enum_value(vdsl2_profiles, token);
    			if (profile != -1)
    				cfg_params.vdsl2_profiles |= profile;
    			else {
    				DSLMNGR_LOG(LOG_ERR,
    					"Wrong argument for vdsl2_profiles. It should be like \"8a,8b,8c,8d,17a,30a,35b\"\n");
    				return UBUS_STATUS_INVALID_ARGUMENT;
    			}
    		}
    
    		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.vdsl2_profiles = 0x%lx(%s)\n", cfg_params.vdsl2_profiles, profiles_str);
    	}
    
    	// FAST profiles
    	if (tb[DSL_CONFIGURE_FAST_PROFILES]) {
    		const char *profiles_str = blobmsg_data(tb[DSL_CONFIGURE_FAST_PROFILES]);
    		char *dup, *token, *saveptr;
    
    		if (!profiles_str || !*profiles_str) {
    			DSLMNGR_LOG(LOG_ERR,
    				"Wrong argument for fast_profiles. It should be like \"106a,212a\"\n");
    			return UBUS_STATUS_INVALID_ARGUMENT;
    		}
    
    		dup = alloca(strlen(profiles_str) + 1);
    
    		strncpy(dup, profiles_str, strlen(profiles_str) + 1);
    
    		for (token = strtok_r(dup, ",", &saveptr); token != NULL; token = strtok_r(NULL, ",", &saveptr)) {
    			int profile = dsl_get_enum_value(fast_profiles, token);
    			if (profile != -1)
    				cfg_params.fast_profiles |= profile;
    			else {
    				DSLMNGR_LOG(LOG_ERR,
    					"Wrong argument for fast_profiles. It should be like \"106a,212a\"\n");
    				return UBUS_STATUS_INVALID_ARGUMENT;
    			}
    		}
    
    		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.fast_profiles = 0x%lx(%s)\n", cfg_params.fast_profiles, profiles_str);
    	}
    
    	// enable_data_gathering
    	if (tb[DSL_CONFIGURE_ENABLE_DATA_GATHERING]) {
    		uint8_t enabled = blobmsg_get_u8(tb[DSL_CONFIGURE_ENABLE_DATA_GATHERING]);
    
    		cfg_params.enable_data_gathering = !!enabled;
    
    		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.enable_data_gathering = %d\n", cfg_params.enable_data_gathering);
    	}
    
    	// limit_mask
    	if (tb[DSL_CONFIGURE_LIMIT_MASK]) {
    		cfg_params.limit_mask = blobmsg_get_u32(tb[DSL_CONFIGURE_LIMIT_MASK]);
    
    		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.limit_mask = 0x%x\n", cfg_params.limit_mask);
    	}
    
    	// limit_mask
    	if (tb[DSL_CONFIGURE_US0_MASK]) {
    		cfg_params.us0_mask = blobmsg_get_u32(tb[DSL_CONFIGURE_US0_MASK]);
    
    		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.us0_mask = 0x%x\n", cfg_params.us0_mask);
    	}
    
    	// Get line number
    	sscanf(obj->name, "dsl.line.%d", &line_num);
    
    	line_num--;  // indexes start from 1 in ubus object
    
    	if (xdsl_ops.configure(line_num, &cfg_params) != 0) {
    		DSLMNGR_LOG(LOG_ERR, "DSL line %d confuration failed\n", line_num);
    		return UBUS_STATUS_UNKNOWN_ERROR;
    	}
    
    	return 0;
    }
    
    
    int dsl_add_ubus_objects(struct ubus_context *ctx)
    {
    	struct ubus_object *line_objects = NULL;
    	struct ubus_object *channel_objects = NULL;
    
    	struct ubus_object *fast_objects = NULL;
    	struct ubus_object *atm_objects = NULL;
    	struct ubus_object *ptm_objects = NULL;
    
    	int ret, max_line, max_channel, i;
    
    
    	// Add objects dsl
    	ret = ubus_add_object(ctx, &dsl_object);
    
    	if (ret) {
    		DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    
    				dsl_object.name, ubus_strerror(ret));
    
    		return -1;
    	}
    
    	// Add objects dsl.line.x
    	max_line = dsl_get_line_number();
    	line_objects = calloc(max_line, sizeof(struct ubus_object));
    	if (!line_objects) {
    		DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    		return -1;
    	}
    	for (i = 0; i < max_line; i++) {
    		char *obj_name;
    
    
    		if (asprintf(&obj_name, "dsl.line.%d", i + 1) <= 0) {
    
    			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    			return -1;
    		}
    
    		line_objects[i].name = obj_name;
    		line_objects[i].type = &dsl_line_type;
    		line_objects[i].methods = dsl_line_methods;
    		line_objects[i].n_methods = ARRAY_SIZE(dsl_line_methods);
    
    		ret = ubus_add_object(ctx, &line_objects[i]);
    		if (ret) {
    			DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    					obj_name, ubus_strerror(ret));
    			return -1;
    		}
    	}
    
    	// Add objects dsl.channel.x
    	max_channel = dsl_get_channel_number();
    	channel_objects = calloc(max_channel, sizeof(struct ubus_object));
    	if (!channel_objects) {
    		DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    		return -1;
    	}
    	for (i = 0; i < max_channel; i++) {
    		char *obj_name;
    
    
    		if (asprintf(&obj_name, "dsl.channel.%d", i + 1) <= 0) {
    
    			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    			return -1;
    		}
    
    		channel_objects[i].name = obj_name;
    		channel_objects[i].type = &dsl_channel_type;
    		channel_objects[i].methods = dsl_channel_methods;
    		channel_objects[i].n_methods = ARRAY_SIZE(dsl_channel_methods);
    
    		ret = ubus_add_object(ctx, &channel_objects[i]);
    		if (ret) {
    			DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    					obj_name, ubus_strerror(ret));
    			return -1;
    		}
    	}
    
    
    	// Add object fast if supported
    	if (xdsl_ops.get_fast_line_info && xdsl_ops.get_fast_line_stats &&
    	    xdsl_ops.get_fast_line_stats_interval) {
    		ret = ubus_add_object(ctx, &fast_object);
    		if (ret) {
    			DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    				    fast_object.name, ubus_strerror(ret));
    			return -1;
    		}
    	}
    
    
    	// Add objects fast.line.x if supported
    	if (xdsl_ops.get_fast_line_info && xdsl_ops.get_fast_line_stats &&
    		xdsl_ops.get_fast_line_stats_interval) {
    		fast_objects = calloc(max_line, sizeof(struct ubus_object));
    		if (!fast_objects) {
    			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    			return -1;
    		}
    		for (i = 0; i < max_line; i++) {
    			char *obj_name;
    
    
    			if (asprintf(&obj_name, "fast.line.%d", i + 1) <= 0) {
    
    				DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    				return -1;
    			}
    
    			fast_objects[i].name = obj_name;
    			fast_objects[i].type = &fast_line_type;
    			fast_objects[i].methods = fast_line_methods;
    			fast_objects[i].n_methods = ARRAY_SIZE(fast_line_methods);
    
    			ret = ubus_add_object(ctx, &fast_objects[i]);
    			if (ret) {
    				DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    						obj_name, ubus_strerror(ret));
    				return -1;
    			}
    		}
    	}
    
    	// Add objects atm.link.x if supported
    	if (atm_funcs.get_link_info && atm_funcs.get_link_stats && atm_funcs.configure) {
    		atm_objects = calloc(max_line, sizeof(struct ubus_object));
    		if (!atm_objects) {
    			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    			return -1;
    		}
    		for (i = 0; i < max_line; i++) {
    			char *obj_name;
    
    
    			if (asprintf(&obj_name, "atm.link.%d", i + 1) <= 0) {
    
    				DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    				return -1;
    			}
    
    			atm_objects[i].name = obj_name;
    			atm_objects[i].type = &atm_link_type;
    			atm_objects[i].methods = atm_link_methods;
    			atm_objects[i].n_methods = ARRAY_SIZE(atm_link_methods);
    
    			ret = ubus_add_object(ctx, &atm_objects[i]);
    			if (ret) {
    				DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    						obj_name, ubus_strerror(ret));
    				return -1;
    			}
    		}
    	}
    
    	// Add objects ptm.link.x if supported
    	if (ptm_funcs.get_link_info) {
    		ptm_objects = calloc(max_line, sizeof(struct ubus_object));
    		if (!ptm_objects) {
    			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    			return -1;
    		}
    		for (i = 0; i < max_line; i++) {
    			char *obj_name;
    
    
    			if (asprintf(&obj_name, "ptm.link.%d", i + 1) <= 0) {
    
    				DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
    				return -1;
    			}
    
    			ptm_objects[i].name = obj_name;
    			ptm_objects[i].type = &ptm_link_type;
    			ptm_objects[i].methods = ptm_link_methods;
    			ptm_objects[i].n_methods = ARRAY_SIZE(ptm_link_methods);
    
    			ret = ubus_add_object(ctx, &ptm_objects[i]);
    			if (ret) {
    				DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
    						obj_name, ubus_strerror(ret));
    				return -1;
    			}
    		}
    	}
    
    
    	// Returns on success
    	return 0;
    
    __error_ret:
    	if (line_objects)
    		free(line_objects);
    	if (channel_objects)
    		free(channel_objects);
    
    	if (fast_objects)
    		free(fast_objects);
    	if (atm_objects)
    		free(atm_objects);
    	if (ptm_objects)
    		free(ptm_objects);
    
    
    Jani Juvan's avatar
    Jani Juvan committed
    static int uci_get_ifname(char *ifname, size_t len, bool is_fast)
    {
    	struct uci_context *ctx;
    	struct uci_package *pkg;
    	struct uci_element *e;
    	const char *value;
    	bool use_ptm = is_fast;
    	int i = 0;   // always check line 0 for now
    
    	/* First, we need to check if we are running ADSL or not */
    	if (!is_fast) {
    		struct dsl_line line;
    		if (xdsl_ops.get_line_info == NULL || (*xdsl_ops.get_line_info)(i, &line) != 0)	{
    			return -1;
    		}
    		if (line.standard_used.use_xtse) {
    			if (XTSE_BIT_GET(line.standard_used.xtse, G_993_2_EUROPE) ||
    			    XTSE_BIT_GET(line.standard_used.xtse, G_993_2_JAPAN) ||
    			    XTSE_BIT_GET(line.standard_used.xtse, G_993_2_NORTH_AMERICA))
    				use_ptm= true;
    		} else {
    			if (line.standard_used.mode &
    			    (MOD_G_993_1 | MOD_G_993_1_Annex_A |
    			     MOD_G_993_2_Annex_A | MOD_G_993_2_Annex_B |
    			     MOD_G_993_2_Annex_C))
    				use_ptm= true;
    		}
    	}
    
    	ctx = uci_alloc_context();
    	if (!ctx)
    		return -1;
    
    	if (uci_load(ctx, "dsl", &pkg)) {
    		uci_free_context(ctx);
    		return -1;
    	}
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		if (!strcmp(s->type, use_ptm ? "ptm-device" : "atm-device")) {
    			value = uci_lookup_option_string(ctx, s, "device");
    			if (value) {
    				if (snprintf(ifname, len, "%s", value) >= len) {
    					// truncated
    					uci_free_context(ctx);
    					return -2;
    				}
    				// success
    				uci_free_context(ctx);
    				return 0;
    			}
    		}
    	}
    
    	// not found
    	uci_free_context(ctx);
    	return -1;
    }
    
    
    static int uci_get_oem_params(char *vendor_id, char *sw_version, char *serial_nr)