/** * tipc_disc_rcv - handle incoming discovery message (request or response) * @net: the applicable net namespace * @buf: buffer containing message * @bearer: bearer that message arrived on */ void tipc_disc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *bearer) { struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_media_addr maddr; struct sk_buff *rskb; struct tipc_msg *hdr = buf_msg(skb); u32 ddom = msg_dest_domain(hdr); u32 onode = msg_prevnode(hdr); u32 net_id = msg_bc_netid(hdr); u32 mtyp = msg_type(hdr); u32 signature = msg_node_sig(hdr); u16 caps = msg_node_capabilities(hdr); bool respond = false; bool dupl_addr = false; int err; err = bearer->media->msg2addr(bearer, &maddr, msg_media_addr(hdr)); kfree_skb(skb); if (err) return; /* Ensure message from node is valid and communication is permitted */ if (net_id != tn->net_id) return; if (maddr.broadcast) return; if (!tipc_addr_domain_valid(ddom)) return; if (!tipc_addr_node_valid(onode)) return; if (in_own_node(net, onode)) { if (memcmp(&maddr, &bearer->addr, sizeof(maddr))) disc_dupl_alert(bearer, tn->own_addr, &maddr); return; } if (!tipc_in_scope(ddom, tn->own_addr)) return; if (!tipc_in_scope(bearer->domain, onode)) return; tipc_node_check_dest(net, onode, bearer, caps, signature, &maddr, &respond, &dupl_addr); if (dupl_addr) disc_dupl_alert(bearer, onode, &maddr); /* Send response, if necessary */ if (respond && (mtyp == DSC_REQ_MSG)) { rskb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC); if (!rskb) return; tipc_disc_init_msg(net, rskb, DSC_RESP_MSG, bearer); tipc_bearer_xmit_skb(net, bearer->identity, rskb, &maddr); } }
/** * tipc_nodesub_subscribe - create "node down" subscription for specified node */ void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr, void *usr_handle, net_ev_handler handle_down) { if (in_own_node(addr)) { node_sub->node = NULL; return; } node_sub->node = tipc_node_find(addr); if (!node_sub->node) { pr_warn("Node subscription rejected, unknown node 0x%x\n", addr); return; } node_sub->handle_node_down = handle_down; node_sub->usr_handle = usr_handle; tipc_node_lock(node_sub->node); list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub); tipc_node_unlock(node_sub->node); }
struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, int request_space, int reply_headroom) { struct sk_buff *rep_tlv_buf; rtnl_lock(); /* Save request and reply details in a well-known location */ req_tlv_area = request_area; req_tlv_space = request_space; rep_headroom = reply_headroom; /* Check command authorization */ if (likely(in_own_node(orig_node))) { /* command is permitted */ } else { rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot be done remotely)"); goto exit; } /* Call appropriate processing routine */ switch (cmd) { case TIPC_CMD_NOOP: rep_tlv_buf = tipc_cfg_reply_none(); break; case TIPC_CMD_GET_NODES: rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space); break; case TIPC_CMD_GET_LINKS: rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space); break; case TIPC_CMD_SHOW_LINK_STATS: rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space); break; case TIPC_CMD_RESET_LINK_STATS: rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space); break; case TIPC_CMD_SHOW_NAME_TABLE: rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space); break; case TIPC_CMD_GET_BEARER_NAMES: rep_tlv_buf = tipc_bearer_get_names(); break; case TIPC_CMD_GET_MEDIA_NAMES: rep_tlv_buf = tipc_media_get_names(); break; case TIPC_CMD_SHOW_PORTS: rep_tlv_buf = tipc_sk_socks_show(); break; case TIPC_CMD_SHOW_STATS: rep_tlv_buf = tipc_show_stats(); break; case TIPC_CMD_SET_LINK_TOL: case TIPC_CMD_SET_LINK_PRI: case TIPC_CMD_SET_LINK_WINDOW: rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd); break; case TIPC_CMD_ENABLE_BEARER: rep_tlv_buf = cfg_enable_bearer(); break; case TIPC_CMD_DISABLE_BEARER: rep_tlv_buf = cfg_disable_bearer(); break; case TIPC_CMD_SET_NODE_ADDR: rep_tlv_buf = cfg_set_own_addr(); break; case TIPC_CMD_SET_MAX_PORTS: rep_tlv_buf = cfg_set_max_ports(); break; case TIPC_CMD_SET_NETID: rep_tlv_buf = cfg_set_netid(); break; case TIPC_CMD_GET_MAX_PORTS: rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports); break; case TIPC_CMD_GET_NETID: rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); break; case TIPC_CMD_NOT_NET_ADMIN: rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); break; case TIPC_CMD_SET_MAX_ZONES: case TIPC_CMD_GET_MAX_ZONES: case TIPC_CMD_SET_MAX_SLAVES: case TIPC_CMD_GET_MAX_SLAVES: case TIPC_CMD_SET_MAX_CLUSTERS: case TIPC_CMD_GET_MAX_CLUSTERS: case TIPC_CMD_SET_MAX_NODES: case TIPC_CMD_GET_MAX_NODES: case TIPC_CMD_SET_MAX_SUBSCR: case TIPC_CMD_GET_MAX_SUBSCR: case TIPC_CMD_SET_MAX_PUBL: case TIPC_CMD_GET_MAX_PUBL: case TIPC_CMD_SET_LOG_SIZE: case TIPC_CMD_SET_REMOTE_MNG: case TIPC_CMD_GET_REMOTE_MNG: case TIPC_CMD_DUMP_LOG: rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (obsolete command)"); break; default: rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (unknown command)"); break; } WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN)); /* Append an error message if we cannot return all requested data */ if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) { if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0') sprintf(rep_tlv_buf->data + rep_tlv_buf->len - sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED); } /* Return reply buffer */ exit: rtnl_unlock(); return rep_tlv_buf; }