Exemple #1
0
/**
 * 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);
	}
}
Exemple #2
0
/**
 * tipc_disc_init_msg - initialize a link setup message
 * @net: the applicable net namespace
 * @type: message type (request or response)
 * @b: ptr to bearer issuing message
 */
static void tipc_disc_init_msg(struct net *net, struct sk_buff *buf, u32 type,
			       struct tipc_bearer *b)
{
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	struct tipc_msg *msg;
	u32 dest_domain = b->domain;

	msg = buf_msg(buf);
	tipc_msg_init(tn->own_addr, msg, LINK_CONFIG, type,
		      MAX_H_SIZE, dest_domain);
	msg_set_non_seq(msg, 1);
	msg_set_node_sig(msg, tn->random);
	msg_set_node_capabilities(msg, TIPC_NODE_CAPABILITIES);
	msg_set_dest_domain(msg, dest_domain);
	msg_set_bc_netid(msg, tn->net_id);
	b->media->addr2msg(msg_media_addr(msg), &b->addr);
}
Exemple #3
0
static struct sk_buff *tipc_disc_init_msg(u32 type,
					  u32 dest_domain,
					  struct tipc_bearer *b_ptr)
{
	struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
	struct tipc_msg *msg;

	if (buf) {
		msg = buf_msg(buf);
		tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
		msg_set_non_seq(msg, 1);
		msg_set_dest_domain(msg, dest_domain);
		msg_set_bc_netid(msg, tipc_net_id);
		b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
	}
	return buf;
}
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_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str)
{
	u32 usr = msg_user(msg);
	tipc_printf(buf, KERN_DEBUG);
	tipc_printf(buf, str);

	switch (usr) {
	case MSG_BUNDLER:
		tipc_printf(buf, "BNDL::");
		tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg));
		break;
	case BCAST_PROTOCOL:
		tipc_printf(buf, "BCASTP::");
		break;
	case MSG_FRAGMENTER:
		tipc_printf(buf, "FRAGM::");
		switch (msg_type(msg)) {
		case FIRST_FRAGMENT:
			tipc_printf(buf, "FIRST:");
			break;
		case FRAGMENT:
			tipc_printf(buf, "BODY:");
			break;
		case LAST_FRAGMENT:
			tipc_printf(buf, "LAST:");
			break;
		default:
			tipc_printf(buf, "UNKNOWN:%x", msg_type(msg));

		}
		tipc_printf(buf, "NO(%u/%u):", msg_long_msgno(msg),
			    msg_fragm_no(msg));
		break;
	case TIPC_LOW_IMPORTANCE:
	case TIPC_MEDIUM_IMPORTANCE:
	case TIPC_HIGH_IMPORTANCE:
	case TIPC_CRITICAL_IMPORTANCE:
		tipc_printf(buf, "DAT%u:", msg_user(msg));
		if (msg_short(msg)) {
			tipc_printf(buf, "CON:");
			break;
		}
		switch (msg_type(msg)) {
		case TIPC_CONN_MSG:
			tipc_printf(buf, "CON:");
			break;
		case TIPC_MCAST_MSG:
			tipc_printf(buf, "MCST:");
			break;
		case TIPC_NAMED_MSG:
			tipc_printf(buf, "NAM:");
			break;
		case TIPC_DIRECT_MSG:
			tipc_printf(buf, "DIR:");
			break;
		default:
			tipc_printf(buf, "UNKNOWN TYPE %u", msg_type(msg));
		}
		if (msg_reroute_cnt(msg))
			tipc_printf(buf, "REROUTED(%u):",
				    msg_reroute_cnt(msg));
		break;
	case NAME_DISTRIBUTOR:
		tipc_printf(buf, "NMD::");
		switch (msg_type(msg)) {
		case PUBLICATION:
			tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20);	
			break;
		case WITHDRAWAL:
			tipc_printf(buf, "WDRW:");
			break;
		default:
			tipc_printf(buf, "UNKNOWN:%x", msg_type(msg));
		}
		if (msg_reroute_cnt(msg))
			tipc_printf(buf, "REROUTED(%u):",
				    msg_reroute_cnt(msg));
		break;
	case CONN_MANAGER:
		tipc_printf(buf, "CONN_MNG:");
		switch (msg_type(msg)) {
		case CONN_PROBE:
			tipc_printf(buf, "PROBE:");
			break;
		case CONN_PROBE_REPLY:
			tipc_printf(buf, "PROBE_REPLY:");
			break;
		case CONN_ACK:
			tipc_printf(buf, "CONN_ACK:");
			tipc_printf(buf, "ACK(%u):", msg_msgcnt(msg));
			break;
		default:
			tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg));
		}
		if (msg_reroute_cnt(msg))
			tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg));
		break;
	case LINK_PROTOCOL:
		switch (msg_type(msg)) {
		case STATE_MSG:
			tipc_printf(buf, "STATE:");
			tipc_printf(buf, "%s:", msg_probe(msg) ? "PRB" : "");
			tipc_printf(buf, "NXS(%u):", msg_next_sent(msg));
			tipc_printf(buf, "GAP(%u):", msg_seq_gap(msg));
			tipc_printf(buf, "LSTBC(%u):", msg_last_bcast(msg));
			break;
		case RESET_MSG:
			tipc_printf(buf, "RESET:");
			if (msg_size(msg) != msg_hdr_sz(msg))
				tipc_printf(buf, "BEAR:%s:", msg_data(msg));
			break;
		case ACTIVATE_MSG:
			tipc_printf(buf, "ACTIVATE:");
			break;
		default:
			tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg));
		}
		tipc_printf(buf, "PLANE(%c):", msg_net_plane(msg));
		tipc_printf(buf, "SESS(%u):", msg_session(msg));
		break;
	case CHANGEOVER_PROTOCOL:
		tipc_printf(buf, "TUNL:");
		switch (msg_type(msg)) {
		case DUPLICATE_MSG:
			tipc_printf(buf, "DUPL:");
			break;
		case ORIGINAL_MSG:
			tipc_printf(buf, "ORIG:");
			tipc_printf(buf, "EXP(%u)", msg_msgcnt(msg));
			break;
		default:
			tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg));
		}
		break;
	case LINK_CONFIG:
		tipc_printf(buf, "CFG:");
		switch (msg_type(msg)) {
		case DSC_REQ_MSG:
			tipc_printf(buf, "DSC_REQ:");
			break;
		case DSC_RESP_MSG:
			tipc_printf(buf, "DSC_RESP:");
			break;
		default:
			tipc_printf(buf, "UNKNOWN TYPE:%x:", msg_type(msg));
			break;
		}
		break;
	default:
		tipc_printf(buf, "UNKNOWN USER:"******"NO_NAME:");
			break;
		case TIPC_ERR_NO_PORT:
			tipc_printf(buf, "NO_PORT:");
			break;
		case TIPC_ERR_NO_NODE:
			tipc_printf(buf, "NO_PROC:");
			break;
		case TIPC_ERR_OVERLOAD:
			tipc_printf(buf, "OVERLOAD:");
			break;
		case TIPC_CONN_SHUTDOWN:
			tipc_printf(buf, "SHUTDOWN:");
			break;
		default:
			tipc_printf(buf, "UNKNOWN ERROR(%x):",
				    msg_errcode(msg));
		}
	default:
		break;
	}

	tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg));
	tipc_printf(buf, "SZ(%u):", msg_size(msg));
	tipc_printf(buf, "SQNO(%u):", msg_seqno(msg));

	if (msg_non_seq(msg))
		tipc_printf(buf, "NOSEQ:");
	else
		tipc_printf(buf, "ACK(%u):", msg_ack(msg));
	tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg));
	tipc_printf(buf, "PRND(%x)", msg_prevnode(msg));

	if (msg_isdata(msg)) {
		if (msg_named(msg)) {
			tipc_printf(buf, "NTYP(%u):", msg_nametype(msg));
			tipc_printf(buf, "NINST(%u)", msg_nameinst(msg));
		}
	}

	if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) &&
	    (usr != MSG_BUNDLER)) {
		if (!msg_short(msg)) {
			tipc_printf(buf, ":ORIG(%x:%u):",
				    msg_orignode(msg), msg_origport(msg));
			tipc_printf(buf, ":DEST(%x:%u):",
				    msg_destnode(msg), msg_destport(msg));
		} else {
			tipc_printf(buf, ":OPRT(%u):", msg_origport(msg));
			tipc_printf(buf, ":DPRT(%u):", msg_destport(msg));
		}
	}
	if (msg_user(msg) == NAME_DISTRIBUTOR) {
		tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg));
		tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg));
	}

	if (msg_user(msg) ==  LINK_CONFIG) {
		struct tipc_media_addr orig;

		tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg));
		tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg));
		memcpy(orig.value, msg_media_addr(msg), sizeof(orig.value));
		orig.media_id = 0;
		orig.broadcast = 0;
		tipc_media_addr_printf(buf, &orig);
	}
	if (msg_user(msg) == BCAST_PROTOCOL) {
		tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg));
		tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg));
	}
	tipc_printf(buf, "\n");
	if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg)))
		tipc_msg_dbg(buf, msg_get_wrapped(msg), "      /");
	if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT))
		tipc_msg_dbg(buf, msg_get_wrapped(msg), "      /");
}
Exemple #6
0
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);
}