/** * 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); } }
struct _zone *tipc_zone_create(u32 addr) { struct _zone *z_ptr; u32 z_num; if (!tipc_addr_domain_valid(addr)) { err("Zone creation failed, invalid domain 0x%x\n", addr); return NULL; } z_ptr = kzalloc(sizeof(*z_ptr), GFP_ATOMIC); if (!z_ptr) { warn("Zone creation failed, insufficient memory\n"); return NULL; } z_num = tipc_zone(addr); z_ptr->addr = tipc_addr(z_num, 0, 0); tipc_net.zones[z_num] = z_ptr; return z_ptr; }
/** * tipc_enable_bearer - enable bearer with the given name */ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) { struct tipc_bearer *b_ptr; struct tipc_media *m_ptr; struct tipc_bearer_names b_names; char addr_string[16]; u32 bearer_id; u32 with_this_prio; u32 i; int res = -EINVAL; if (!tipc_own_addr) { pr_warn("Bearer <%s> rejected, not supported in standalone mode\n", name); return -ENOPROTOOPT; } if (!bearer_name_validate(name, &b_names)) { pr_warn("Bearer <%s> rejected, illegal name\n", name); return -EINVAL; } if (tipc_addr_domain_valid(disc_domain) && (disc_domain != tipc_own_addr)) { if (tipc_in_scope(disc_domain, tipc_own_addr)) { disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK; res = 0; /* accept any node in own cluster */ } else if (in_own_cluster_exact(disc_domain)) res = 0; /* accept specified node in own cluster */ } if (res) { pr_warn("Bearer <%s> rejected, illegal discovery domain\n", name); return -EINVAL; } if ((priority > TIPC_MAX_LINK_PRI) && (priority != TIPC_MEDIA_LINK_PRI)) { pr_warn("Bearer <%s> rejected, illegal priority\n", name); return -EINVAL; } write_lock_bh(&tipc_net_lock); m_ptr = tipc_media_find(b_names.media_name); if (!m_ptr) { pr_warn("Bearer <%s> rejected, media <%s> not registered\n", name, b_names.media_name); goto exit; } if (priority == TIPC_MEDIA_LINK_PRI) priority = m_ptr->priority; restart: bearer_id = MAX_BEARERS; with_this_prio = 1; for (i = MAX_BEARERS; i-- != 0; ) { b_ptr = bearer_list[i]; if (!b_ptr) { bearer_id = i; continue; } if (!strcmp(name, b_ptr->name)) { pr_warn("Bearer <%s> rejected, already enabled\n", name); goto exit; } if ((b_ptr->priority == priority) && (++with_this_prio > 2)) { if (priority-- == 0) { pr_warn("Bearer <%s> rejected, duplicate priority\n", name); goto exit; } pr_warn("Bearer <%s> priority adjustment required %u->%u\n", name, priority + 1, priority); goto restart; } } if (bearer_id >= MAX_BEARERS) { pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n", name, MAX_BEARERS); goto exit; } b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC); if (!b_ptr) { res = -ENOMEM; goto exit; } strcpy(b_ptr->name, name); b_ptr->media = m_ptr; res = m_ptr->enable_media(b_ptr); if (res) { pr_warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res); goto exit; } b_ptr->identity = bearer_id; b_ptr->tolerance = m_ptr->tolerance; b_ptr->window = m_ptr->window; b_ptr->domain = disc_domain; b_ptr->net_plane = bearer_id + 'A'; b_ptr->priority = priority; res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr); if (res) { bearer_disable(b_ptr, false); pr_warn("Bearer <%s> rejected, discovery object creation failed\n", name); goto exit; } bearer_list[bearer_id] = b_ptr; pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n", name, tipc_addr_string_fill(addr_string, disc_domain), priority); exit: write_unlock_bh(&tipc_net_lock); return res; }
int tipc_addr_node_valid(u32 addr) { return (tipc_addr_domain_valid(addr) && tipc_node(addr)); }
void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) { struct tipc_node *n_ptr; struct tipc_link *link; struct tipc_media_addr media_addr; struct sk_buff *rbuf; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); u32 signature = msg_node_sig(msg); int addr_mismatch; int link_fully_up; media_addr.broadcast = 1; b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); kfree_skb(buf); /* Ensure message from node is valid and communication is permitted */ if (net_id != tipc_net_id) return; if (media_addr.broadcast) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) { if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr))) disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; } if (!tipc_in_scope(dest, tipc_own_addr)) return; if (!tipc_in_scope(b_ptr->link_req->domain, orig)) return; /* Locate structure corresponding to requesting node */ n_ptr = tipc_node_find(orig); if (!n_ptr) { n_ptr = tipc_node_create(orig); if (!n_ptr) return; } tipc_node_lock(n_ptr); /* Prepare to validate requesting node's signature and media address */ link = n_ptr->links[b_ptr->identity]; addr_mismatch = (link != NULL) && memcmp(&link->media_addr, &media_addr, sizeof(media_addr)); /* * Ensure discovery message's signature is correct * * If signature is incorrect and there is no working link to the node, * accept the new signature but invalidate all existing links to the * node so they won't re-activate without a new discovery message. * * If signature is incorrect and the requested link to the node is * working, accept the new signature. (This is an instance of delayed * rediscovery, where a link endpoint was able to re-establish contact * with its peer endpoint on a node that rebooted before receiving a * discovery message from that node.) * * If signature is incorrect and there is a working link to the node * that is not the requested link, reject the request (must be from * a duplicate node). */ if (signature != n_ptr->signature) { if (n_ptr->working_links == 0) { struct tipc_link *curr_link; int i; for (i = 0; i < MAX_BEARERS; i++) { curr_link = n_ptr->links[i]; if (curr_link) { memset(&curr_link->media_addr, 0, sizeof(media_addr)); tipc_link_reset(curr_link); } } addr_mismatch = (link != NULL); } else if (tipc_link_is_up(link) && !addr_mismatch) { /* delayed rediscovery */ } else { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } n_ptr->signature = signature; } /* * Ensure requesting node's media address is correct * * If media address doesn't match and the link is working, reject the * request (must be from a duplicate node). * * If media address doesn't match and the link is not working, accept * the new media address and reset the link to ensure it starts up * cleanly. */ if (addr_mismatch) { if (tipc_link_is_up(link)) { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } else { memcpy(&link->media_addr, &media_addr, sizeof(media_addr)); tipc_link_reset(link); } } /* Create a link endpoint for this bearer, if necessary */ if (!link) { link = tipc_link_create(n_ptr, b_ptr, &media_addr); if (!link) { tipc_node_unlock(n_ptr); return; } } /* Accept discovery message & send response, if necessary */ link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); if (rbuf) { b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); kfree_skb(rbuf); } } tipc_node_unlock(n_ptr); }
void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) { struct link *link; struct tipc_media_addr media_addr; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); msg_get_media_addr(msg,&media_addr); msg_dbg(msg, "RECV:"); buf_discard(buf); if (net_id != tipc_net_id) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) { if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr))) disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; } if (!in_scope(dest, tipc_own_addr)) return; if (is_slave(tipc_own_addr) && is_slave(orig)) return; if (is_slave(orig) && !in_own_cluster(orig)) return; if (in_own_cluster(orig)) { /* Always accept link here */ struct sk_buff *rbuf; struct tipc_media_addr *addr; struct tipc_node *n_ptr = tipc_node_find(orig); int link_fully_up; dbg(" in own cluster\n"); if (n_ptr == NULL) { n_ptr = tipc_node_create(orig); if (!n_ptr) return; } spin_lock_bh(&n_ptr->lock); link = n_ptr->links[b_ptr->identity]; if (!link) { dbg("creating link\n"); link = tipc_link_create(b_ptr, orig, &media_addr); if (!link) { spin_unlock_bh(&n_ptr->lock); return; } } addr = &link->media_addr; if (memcmp(addr, &media_addr, sizeof(*addr))) { if (tipc_link_is_up(link) || (!link->started)) { disc_dupl_alert(b_ptr, orig, &media_addr); spin_unlock_bh(&n_ptr->lock); return; } warn("Resetting link <%s>, peer interface address changed\n", link->name); memcpy(addr, &media_addr, sizeof(*addr)); tipc_link_reset(link); } link_fully_up = (link->state == WORKING_WORKING); spin_unlock_bh(&n_ptr->lock); if ((type == DSC_RESP_MSG) || link_fully_up) return; rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); if (rbuf != NULL) { msg_dbg(buf_msg(rbuf),"SEND:"); b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr); buf_discard(rbuf); } } }
void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) { struct link *link; struct tipc_media_addr media_addr; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); msg_get_media_addr(msg, &media_addr); buf_discard(buf); if (net_id != tipc_net_id) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) { if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr))) disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; } if (!tipc_in_scope(dest, tipc_own_addr)) return; if (in_own_cluster(orig)) { /* Always accept link here */ struct sk_buff *rbuf; struct tipc_media_addr *addr; struct tipc_node *n_ptr = tipc_node_find(orig); int link_fully_up; if (n_ptr == NULL) { n_ptr = tipc_node_create(orig); if (!n_ptr) return; } spin_lock_bh(&n_ptr->lock); /* Don't talk to neighbor during cleanup after last session */ if (n_ptr->cleanup_required) { spin_unlock_bh(&n_ptr->lock); return; } link = n_ptr->links[b_ptr->identity]; if (!link) { link = tipc_link_create(b_ptr, orig, &media_addr); if (!link) { spin_unlock_bh(&n_ptr->lock); return; } } addr = &link->media_addr; if (memcmp(addr, &media_addr, sizeof(*addr))) { if (tipc_link_is_up(link) || (!link->started)) { disc_dupl_alert(b_ptr, orig, &media_addr); spin_unlock_bh(&n_ptr->lock); return; } warn("Resetting link <%s>, peer interface address changed\n", link->name); memcpy(addr, &media_addr, sizeof(*addr)); tipc_link_reset(link); } link_fully_up = link_working_working(link); spin_unlock_bh(&n_ptr->lock); if ((type == DSC_RESP_MSG) || link_fully_up) return; rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); if (rbuf != NULL) { b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr); buf_discard(rbuf); } } }
void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) { struct tipc_node *n_ptr; struct tipc_link *link; struct tipc_media_addr media_addr, *addr; struct sk_buff *rbuf; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); int link_fully_up; media_addr.broadcast = 1; b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); buf_discard(buf); /* Validate discovery message from requesting node */ if (net_id != tipc_net_id) return; if (media_addr.broadcast) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) { if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr))) disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; } if (!tipc_in_scope(dest, tipc_own_addr)) return; if (!tipc_in_scope(b_ptr->link_req->domain, orig)) return; /* Locate structure corresponding to requesting node */ n_ptr = tipc_node_find(orig); if (!n_ptr) { n_ptr = tipc_node_create(orig); if (!n_ptr) return; } tipc_node_lock(n_ptr); link = n_ptr->links[b_ptr->identity]; /* Create a link endpoint for this bearer, if necessary */ if (!link) { link = tipc_link_create(n_ptr, b_ptr, &media_addr); if (!link) { tipc_node_unlock(n_ptr); return; } } /* * Ensure requesting node's media address is correct * * If media address doesn't match and the link is working, reject the * request (must be from a duplicate node). * * If media address doesn't match and the link is not working, accept * the new media address and reset the link to ensure it starts up * cleanly. */ addr = &link->media_addr; if (memcmp(addr, &media_addr, sizeof(*addr))) { if (tipc_link_is_up(link) || (!link->started)) { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } warn("Resetting link <%s>, peer interface address changed\n", link->name); memcpy(addr, &media_addr, sizeof(*addr)); tipc_link_reset(link); } /* Accept discovery message & send response, if necessary */ link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); if (rbuf) { b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); buf_discard(rbuf); } } tipc_node_unlock(n_ptr); }
/** * tipc_enable_bearer - enable bearer with the given name */ static int tipc_enable_bearer(struct net *net, const char *name, u32 disc_domain, u32 priority, struct nlattr *attr[]) { struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_bearer *b; struct tipc_media *m; struct tipc_bearer_names b_names; struct sk_buff *skb; char addr_string[16]; u32 bearer_id; u32 with_this_prio; u32 i; int res = -EINVAL; if (!tn->own_addr) { pr_warn("Bearer <%s> rejected, not supported in standalone mode\n", name); return -ENOPROTOOPT; } if (!bearer_name_validate(name, &b_names)) { pr_warn("Bearer <%s> rejected, illegal name\n", name); return -EINVAL; } if (tipc_addr_domain_valid(disc_domain) && (disc_domain != tn->own_addr)) { if (tipc_in_scope(disc_domain, tn->own_addr)) { disc_domain = tn->own_addr & TIPC_CLUSTER_MASK; res = 0; /* accept any node in own cluster */ } else if (in_own_cluster_exact(net, disc_domain)) res = 0; /* accept specified node in own cluster */ } if (res) { pr_warn("Bearer <%s> rejected, illegal discovery domain\n", name); return -EINVAL; } if ((priority > TIPC_MAX_LINK_PRI) && (priority != TIPC_MEDIA_LINK_PRI)) { pr_warn("Bearer <%s> rejected, illegal priority\n", name); return -EINVAL; } m = tipc_media_find(b_names.media_name); if (!m) { pr_warn("Bearer <%s> rejected, media <%s> not registered\n", name, b_names.media_name); return -EINVAL; } if (priority == TIPC_MEDIA_LINK_PRI) priority = m->priority; restart: bearer_id = MAX_BEARERS; with_this_prio = 1; for (i = MAX_BEARERS; i-- != 0; ) { b = rtnl_dereference(tn->bearer_list[i]); if (!b) { bearer_id = i; continue; } if (!strcmp(name, b->name)) { pr_warn("Bearer <%s> rejected, already enabled\n", name); return -EINVAL; } if ((b->priority == priority) && (++with_this_prio > 2)) { if (priority-- == 0) { pr_warn("Bearer <%s> rejected, duplicate priority\n", name); return -EINVAL; } pr_warn("Bearer <%s> priority adjustment required %u->%u\n", name, priority + 1, priority); goto restart; } } if (bearer_id >= MAX_BEARERS) { pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n", name, MAX_BEARERS); return -EINVAL; } b = kzalloc(sizeof(*b), GFP_ATOMIC); if (!b) return -ENOMEM; strcpy(b->name, name); b->media = m; res = m->enable_media(net, b, attr); if (res) { pr_warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res); return -EINVAL; } b->identity = bearer_id; b->tolerance = m->tolerance; b->window = m->window; b->domain = disc_domain; b->net_plane = bearer_id + 'A'; b->priority = priority; res = tipc_disc_create(net, b, &b->bcast_addr, &skb); if (res) { bearer_disable(net, b); pr_warn("Bearer <%s> rejected, discovery object creation failed\n", name); return -EINVAL; } rcu_assign_pointer(tn->bearer_list[bearer_id], b); if (skb) tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr); pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n", name, tipc_addr_string_fill(addr_string, disc_domain), priority); return res; }
void tipc_disc_recv_msg(struct sk_buff *buf) { struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle; struct link *link; struct tipc_media_addr media_addr; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); msg_get_media_addr(msg,&media_addr); msg_dbg(msg, "RECV:"); buf_discard(buf); if (net_id != tipc_net_id) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) return; if (!in_scope(dest, tipc_own_addr)) return; if (is_slave(tipc_own_addr) && is_slave(orig)) return; if (is_slave(orig) && !in_own_cluster(orig)) return; if (in_own_cluster(orig)) { /* Always accept link here */ struct sk_buff *rbuf; struct tipc_media_addr *addr; struct node *n_ptr = tipc_node_find(orig); int link_up; dbg(" in own cluster\n"); if (n_ptr == NULL) { n_ptr = tipc_node_create(orig); } if (n_ptr == NULL) { warn("Memory squeeze; Failed to create node\n"); return; } spin_lock_bh(&n_ptr->lock); link = n_ptr->links[b_ptr->identity]; if (!link) { dbg("creating link\n"); link = tipc_link_create(b_ptr, orig, &media_addr); if (!link) { spin_unlock_bh(&n_ptr->lock); return; } } addr = &link->media_addr; if (memcmp(addr, &media_addr, sizeof(*addr))) { char addr_string[16]; warn("New bearer address for %s\n", addr_string_fill(addr_string, orig)); memcpy(addr, &media_addr, sizeof(*addr)); tipc_link_reset(link); } link_up = tipc_link_is_up(link); spin_unlock_bh(&n_ptr->lock); if ((type == DSC_RESP_MSG) || link_up) return; rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); if (rbuf != NULL) { msg_dbg(buf_msg(rbuf),"SEND:"); b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr); buf_discard(rbuf); } } }