state, ctx, req);
}
+enum {
+ NETWORK_CMD_PING,
+ NETWORK_CMD_PING6,
+ NETWORK_CMD_TRACEROUTE,
+ NETWORK_CMD_TRACEROUTE6,
+ NETWORK_CMD_NSLOOKUP
+};
+
+static int
+network_cmd(struct ubus_context *ctx, struct ubus_request_data *req,
+ struct blob_attr *msg, int which)
+{
+ char *arg;
+ struct blob_attr *tb[__RPC_D_MAX];
+
+ blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ if (!tb[RPC_D_DATA])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ arg = blobmsg_get_string(tb[RPC_D_DATA]);
+
+ const char *cmds[][8] = {
+ [NETWORK_CMD_PING] = {
+ "ping", "-c", "5", "-W", "1", arg
+ },
+ [NETWORK_CMD_PING6] = {
+ "ping6", "-c", "5", "-W", "1", arg
+ },
+ [NETWORK_CMD_TRACEROUTE] = {
+ "traceroute", "-q", "1", "-w", "1", "-n", arg
+ },
+ [NETWORK_CMD_TRACEROUTE6] = {
+ "traceroute6", "-q", "1", "-w", "2", "-n", arg
+ },
+ [NETWORK_CMD_NSLOOKUP] = {
+ "nslookup", arg
+ }
+ };
+
+ return ops->exec(cmds[which], NULL, NULL, NULL, NULL, NULL, ctx, req);
+}
+
+static int
+rpc_luci2_network_ping(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_cmd(ctx, req, msg, NETWORK_CMD_PING);
+}
+
+static int
+rpc_luci2_network_ping6(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_cmd(ctx, req, msg, NETWORK_CMD_PING6);
+}
+
+static int
+rpc_luci2_network_traceroute(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_cmd(ctx, req, msg, NETWORK_CMD_TRACEROUTE);
+}
+
+static int
+rpc_luci2_network_traceroute6(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_cmd(ctx, req, msg, NETWORK_CMD_TRACEROUTE6);
+}
+
+static int
+rpc_luci2_network_nslookup(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_cmd(ctx, req, msg, NETWORK_CMD_NSLOOKUP);
+}
+
+
+static int
+network_ifupdown(struct ubus_context *ctx, struct ubus_request_data *req,
+ struct blob_attr *msg, bool up)
+{
+ const char *cmd[3] = { NULL };
+ struct blob_attr *tb[__RPC_D_MAX];
+
+ blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ if (!tb[RPC_D_DATA])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ cmd[0] = up ? "/sbin/ifup" : "/sbin/ifdown";
+ cmd[1] = blobmsg_get_string(tb[RPC_D_DATA]);
+
+ return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req);
+}
+
+static int
+rpc_luci2_network_ifup(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_ifupdown(ctx, req, msg, true);
+}
+
+static int
+rpc_luci2_network_ifdown(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ return network_ifupdown(ctx, req, msg, false);
+}
+
+static int
+rpc_luci2_network_dev_list(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ char path[PATH_MAX];
+ struct dirent *e;
+ struct stat s;
+ void *c, *t;
+ bool wireless, bridge, tuntap;
+ int type;
+ DIR *d;
+ FILE *f;
+
+ if (!(d = opendir("/sys/class/net")))
+ return rpc_errno_status();
+
+ blob_buf_init(&buf, 0);
+ c = blobmsg_open_array(&buf, "devices");
+
+ while ((e = readdir(d)) != NULL)
+ {
+ snprintf(path, sizeof(path) - 1, "/sys/class/net/%s/type", e->d_name);
+
+ if (stat(path, &s) || !S_ISREG(s.st_mode) || !(f = fopen(path, "r")))
+ continue;
+
+ type = 1;
+ memset(path, 0, sizeof(path));
+
+ if (fread(path, 1, sizeof(path) - 1, f) > 0)
+ type = atoi(path);
+
+ fclose(f);
+
+
+ snprintf(path, sizeof(path) - 1,
+ "/sys/class/net/%s/wireless", e->d_name);
+
+ wireless = (!stat(path, &s) && S_ISDIR(s.st_mode));
+
+ snprintf(path, sizeof(path) - 1,
+ "/sys/class/net/%s/phy80211", e->d_name);
+
+ wireless = (wireless || (!stat(path, &s) && S_ISLNK(s.st_mode)));
+
+ snprintf(path, sizeof(path) - 1,
+ "/sys/class/net/%s/bridge", e->d_name);
+
+ bridge = (!stat(path, &s) && S_ISDIR(s.st_mode));
+
+ snprintf(path, sizeof(path) - 1,
+ "/sys/class/net/%s/tun_flags", e->d_name);
+
+ tuntap = (!stat(path, &s) && S_ISREG(s.st_mode));
+
+ t = blobmsg_open_table(&buf, NULL);
+
+ blobmsg_add_string(&buf, "device", e->d_name);
+ blobmsg_add_u32(&buf, "type", type);
+ blobmsg_add_u8(&buf, "is_bridge", bridge);
+ blobmsg_add_u8(&buf, "is_tuntap", tuntap);
+ blobmsg_add_u8(&buf, "is_wireless", wireless);
+
+ blobmsg_close_table(&buf, t);
+ }
+
+ blobmsg_close_array(&buf, c);
+
+ closedir(d);
+
+ ubus_send_reply(ctx, req, buf.head);
+ return 0;
+}
+
struct opkg_state {
int cur_offset;
UBUS_METHOD("switch_info", rpc_luci2_network_sw_info,
rpc_switch_policy),
UBUS_METHOD("switch_status", rpc_luci2_network_sw_status,
- rpc_switch_policy)
+ rpc_switch_policy),
+ UBUS_METHOD("ping", rpc_luci2_network_ping,
+ rpc_data_policy),
+ UBUS_METHOD("ping6", rpc_luci2_network_ping6,
+ rpc_data_policy),
+ UBUS_METHOD("traceroute", rpc_luci2_network_traceroute,
+ rpc_data_policy),
+ UBUS_METHOD("traceroute6", rpc_luci2_network_traceroute6,
+ rpc_data_policy),
+ UBUS_METHOD("nslookup", rpc_luci2_network_nslookup,
+ rpc_data_policy),
+ UBUS_METHOD("ifup", rpc_luci2_network_ifup,
+ rpc_data_policy),
+ UBUS_METHOD("ifdown", rpc_luci2_network_ifdown,
+ rpc_data_policy),
+ UBUS_METHOD_NOARG("device_list", rpc_luci2_network_dev_list)
};
static struct ubus_object_type luci2_network_type =