bool error_occured;
GList **station_list;
GList **mpath_list;
+ wmesh_meshconf_info_s **meshconf;
} mesh_nl_state;
typedef struct {
return NL_SKIP;
}
+static int _on_receive_meshconf_info(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *pinfo[NL80211_MESHCONF_ATTR_MAX + 1];
+ static struct nla_policy meshconf_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
+ [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
+ [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
+ [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
+ [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
+ [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
+ [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
+ [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
+ };
+
+ mesh_nl_state *state = (mesh_nl_state *)arg;
+ wmesh_meshconf_info_s *meshconf_info = NULL;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the interface and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending mpath notifications.
+ */
+
+ if (!tb[NL80211_ATTR_MESH_CONFIG]) {
+ WMESH_LOGE("missing mesh path info!");
+ return NL_SKIP;
+ }
+ if (nla_parse_nested(pinfo, NL80211_MESHCONF_ATTR_MAX,
+ tb[NL80211_ATTR_MESH_CONFIG], meshconf_policy)) {
+ WMESH_LOGE("failed to parse nested attributes!");
+ return NL_SKIP;
+ }
+
+ meshconf_info = g_try_new0(wmesh_meshconf_info_s, 1);
+ if (NULL == meshconf_info) {
+ WMESH_LOGE("Failed to allocate mesh path info !");
+ return NL_SKIP;
+ }
+
+ if (pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]) {
+ meshconf_info->retry_timeout =
+ nla_get_u16(pinfo[NL80211_MESHCONF_RETRY_TIMEOUT]);
+ WMESH_LOGD("Retry Timeout : %u", meshconf_info->retry_timeout);
+ }
+ if (pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]) {
+ meshconf_info->hwmp_max_preq_retries =
+ nla_get_u8(pinfo[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES]);
+ WMESH_LOGD("HWMP Max PREQ Retries : %u",
+ meshconf_info->hwmp_max_preq_retries);
+ }
+ if (pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]) {
+ meshconf_info->confirm_timeout =
+ nla_get_u16(pinfo[NL80211_MESHCONF_CONFIRM_TIMEOUT]);
+ WMESH_LOGD("Confirm Timeout : %u", meshconf_info->confirm_timeout);
+ }
+ if (pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]) {
+ meshconf_info->path_refresh_time =
+ nla_get_u32(pinfo[NL80211_MESHCONF_PATH_REFRESH_TIME]);
+ WMESH_LOGD("Path Refresh Time : %u", meshconf_info->path_refresh_time);
+ }
+ if (pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]) {
+ meshconf_info->holding_timeout =
+ nla_get_u16(pinfo[NL80211_MESHCONF_HOLDING_TIMEOUT]);
+ WMESH_LOGD("Holding Timeout : %u", meshconf_info->holding_timeout);
+ }
+ if (pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]) {
+ meshconf_info->min_disc_timeout =
+ nla_get_u16(pinfo[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT]);
+ WMESH_LOGD("Min Disc Timeout : %u", meshconf_info->min_disc_timeout);
+ }
+ if (pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]) {
+ meshconf_info->max_peer_links =
+ nla_get_u16(pinfo[NL80211_MESHCONF_MAX_PEER_LINKS]);
+ WMESH_LOGD("MAX Peer Links : %u", meshconf_info->max_peer_links);
+ }
+ if (pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]) {
+ meshconf_info->hwmp_preq_min_interval =
+ nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL]);
+ WMESH_LOGD("HWMP PREQ Min Interval : %u",
+ meshconf_info->hwmp_preq_min_interval);
+ }
+ if (pinfo[NL80211_MESHCONF_TTL]) {
+ meshconf_info->ttl =
+ nla_get_u8(pinfo[NL80211_MESHCONF_TTL]);
+ WMESH_LOGD("TTL : %u", meshconf_info->ttl);
+ }
+ if (pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]) {
+ meshconf_info->hwmp_active_path_timeout =
+ nla_get_u32(pinfo[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT]);
+ WMESH_LOGD("HWMP Active Path Timeout : %u",
+ meshconf_info->hwmp_active_path_timeout);
+ }
+ if (pinfo[NL80211_MESHCONF_ELEMENT_TTL]) {
+ meshconf_info->element_ttl =
+ nla_get_u8(pinfo[NL80211_MESHCONF_ELEMENT_TTL]);
+ WMESH_LOGD("Element TTL : %u", meshconf_info->element_ttl);
+ }
+ if (pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]) {
+ meshconf_info->hwmp_rann_interval =
+ nla_get_u16(pinfo[NL80211_MESHCONF_HWMP_RANN_INTERVAL]);
+ WMESH_LOGD("HWMP RANN Interval : %u",
+ meshconf_info->hwmp_rann_interval);
+ }
+
+ WMESH_LOGD("");
+ *(state->meshconf) = meshconf_info;
+
+ return NL_SKIP;
+}
+
static int _on_receive_mesh_event(struct nl_msg *msg, void *arg)
{
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
return WMESHD_ERROR_OPERATION_FAILED;
}
+static int _send_nl_get_meshconf_info(wmesh_service *service)
+{
+ mesh_nl_state state = {
+ .nl80211_id = -1,
+ .callback_state = MESH_NL_CALLBACK_TRYING,
+ .event_source = 0,
+ .nl_socket = NULL,
+ .msg = NULL,
+ .cb = NULL,
+ .s_cb = NULL,
+ .meshconf = &service->meshconf,
+ };
+ int err = WMESHD_ERROR_NONE;
+ int device_index = 0;
+ int ret;
+ int test = 0;
+
+ ret = __initialize_nl80211(&state);
+ if (WMESHD_ERROR_NONE != ret) {
+ WMESH_LOGE("Failed to initialize nl80211");
+ return ret;
+ }
+
+ ret = __initialize_netlink_message(&state);
+ if (WMESHD_ERROR_NONE != ret) {
+ WMESH_LOGE("Failed to initialize netlink message");
+ goto DESTROY;
+ }
+
+ /* Set command into message */
+ genlmsg_put(state.msg, 0, 0, state.nl80211_id, 0,
+ 0, NL80211_CMD_GET_MESH_CONFIG, 0);
+
+ /* Add attributes into message */
+ WMESH_LOGD("Dump Mesh Config with interface [%s]",
+ service->interface_info->mesh_interface);
+ ret = __get_device_index_from_string(
+ service->interface_info->mesh_interface, &device_index);
+ if (WMESHD_ERROR_NONE != ret) {
+ WMESH_LOGE("Failed to get mesh interface device index");
+ err = ret;
+ goto DESTROY;
+ }
+ NLA_PUT_U32(state.msg, NL80211_ATTR_IFINDEX, device_index);
+
+ /* Register valid callback to dump result */
+ nl_cb_set(state.cb, NL_CB_VALID, NL_CB_CUSTOM,
+ _on_receive_meshconf_info, &state);
+
+ /* Send message into kernel */
+ ret = nl_send_auto(state.nl_socket, state.msg);
+ if (ret < 0) {
+ WMESH_LOGE("Failed to nl_send_auto() [%s](%d)",
+ nl_geterror(ret), ret);
+ err = WMESHD_ERROR_OPERATION_FAILED;
+ goto DESTROY;
+ }
+
+ /* sync response */
+ state.callback_state = MESH_NL_CALLBACK_TRYING;
+ while (state.callback_state == MESH_NL_CALLBACK_TRYING) {
+ WMESH_LOGD(" count [%02d]", ++test);
+ nl_recvmsgs(state.nl_socket, state.cb);
+ }
+ WMESH_LOGD("Finished");
+
+DESTROY:
+ __clean_netlink_message(&state);
+ __clean_nl80211(&state);
+
+ return err;
+
+nla_put_failure:
+ WMESH_LOGE("Failed to message build");
+ __clean_netlink_message(&state);
+ __clean_nl80211(&state);
+
+ return WMESHD_ERROR_OPERATION_FAILED;
+}
+
static int _send_nl_register_event_handler()
{
int err = WMESHD_ERROR_NONE;
return ret;
}
+int wmesh_netlink_get_meshconf_info(wmesh_service *service)
+{
+ int ret = WMESHD_ERROR_NONE;
+
+ if (NULL == service) {
+ WMESH_LOGE("Invalid parameter [%p]", service);
+ return WMESHD_ERROR_INVALID_PARAMETER;
+ }
+
+ WMESH_LOGD("Get current Mesh Config info");
+ ret = _send_nl_get_meshconf_info(service);
+
+ return ret;
+}
+
int wmesh_netlink_register_event_handler()
{
int ret = WMESHD_ERROR_NONE;
return TRUE;
}
+static gboolean _wmeshd_dbus_handle_get_meshconf_info(NetWmesh *object,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ int ret = WMESHD_ERROR_NONE;
+ GVariantBuilder builder;
+ GVariant* meshconf_data;
+ wmesh_meshconf_info_s *item;
+
+ wmesh_service *service = (wmesh_service *)user_data;
+
+ ret = wmesh_request_get_meshconf_info(service);
+ if (WMESHD_ERROR_NONE != ret) {
+ WMESH_LOGE("Failed to wmesh_request_get_mpath_info");
+
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Request Failed");
+ } else {
+ /* Get mesh path information and make variant data */
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
+
+ item = service->meshconf;
+
+ g_variant_builder_add(&builder, "{sv}", "RETRY_TIMEOUT",
+ g_variant_new_uint16(item->retry_timeout));
+ g_variant_builder_add(&builder, "{sv}", "HWMP_MAX_PREQ_RETRIES",
+ g_variant_new_byte(item->hwmp_max_preq_retries));
+ g_variant_builder_add(&builder, "{sv}", "CONFIRM_TIMEOUT",
+ g_variant_new_uint16(item->confirm_timeout));
+ g_variant_builder_add(&builder, "{sv}", "PATH_REFRESH_TIME",
+ g_variant_new_uint32(item->path_refresh_time));
+ g_variant_builder_add(&builder, "{sv}", "HOLDING_TIMEOUT",
+ g_variant_new_uint16(item->holding_timeout));
+ g_variant_builder_add(&builder, "{sv}", "MIN_DISC_TIMEOUT",
+ g_variant_new_uint16(item->min_disc_timeout));
+ g_variant_builder_add(&builder, "{sv}", "MAX_PEER_LINKS",
+ g_variant_new_uint16(item->max_peer_links));
+ g_variant_builder_add(&builder, "{sv}", "HWMP_PREQ_MIN_INTERVAL",
+ g_variant_new_uint16(item->hwmp_preq_min_interval));
+ g_variant_builder_add(&builder, "{sv}", "TTL",
+ g_variant_new_byte(item->ttl));
+ g_variant_builder_add(&builder, "{sv}", "HWMP_ACTIVE_PATH_TIMEOUT",
+ g_variant_new_uint32(item->hwmp_active_path_timeout));
+ g_variant_builder_add(&builder, "{sv}", "ELEMENT_TTL",
+ g_variant_new_byte(item->element_ttl));
+ g_variant_builder_add(&builder, "{sv}", "HWMP_RANN_INTERVAL",
+ g_variant_new_uint16(item->hwmp_rann_interval));
+
+
+ meshconf_data = g_variant_builder_end(&builder);
+ net_wmesh_complete_get_meshconf_info(object, invocation, meshconf_data,
+ ret);
+
+ g_object_unref(meshconf_data);
+ }
+
+ g_free(service->meshconf);
+
+ return TRUE;
+}
+
static void _wmeshd_dbus_on_activator_bus_acquired(GDBusConnection *conn,
const gchar *name, gpointer user_data)
{
G_CALLBACK(_wmeshd_dbus_handle_get_station_info), service);
g_signal_connect(meshd_dbus_object, "handle-get-mpath-info",
G_CALLBACK(_wmeshd_dbus_handle_get_mpath_info), service);
+ g_signal_connect(meshd_dbus_object, "handle-get-meshconf-info",
+ G_CALLBACK(_wmeshd_dbus_handle_get_meshconf_info), service);
ret = g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(meshd_dbus_object),
conn, WMESH_DBUS_OBJPATH, &error);