|
@@ -1785,6 +1785,56 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr,
|
|
return buf;
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * link_recv_buf_validate - validate basic format of received message
|
|
|
|
+ *
|
|
|
|
+ * This routine ensures a TIPC message has an acceptable header, and at least
|
|
|
|
+ * as much data as the header indicates it should. The routine also ensures
|
|
|
|
+ * that the entire message header is stored in the main fragment of the message
|
|
|
|
+ * buffer, to simplify future access to message header fields.
|
|
|
|
+ *
|
|
|
|
+ * Note: Having extra info present in the message header or data areas is OK.
|
|
|
|
+ * TIPC will ignore the excess, under the assumption that it is optional info
|
|
|
|
+ * introduced by a later release of the protocol.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+static int link_recv_buf_validate(struct sk_buff *buf)
|
|
|
|
+{
|
|
|
|
+ static u32 min_data_hdr_size[8] = {
|
|
|
|
+ SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE,
|
|
|
|
+ MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ struct tipc_msg *msg;
|
|
|
|
+ u32 tipc_hdr[2];
|
|
|
|
+ u32 size;
|
|
|
|
+ u32 hdr_size;
|
|
|
|
+ u32 min_hdr_size;
|
|
|
|
+
|
|
|
|
+ if (unlikely(buf->len < MIN_H_SIZE))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr);
|
|
|
|
+ if (msg == NULL)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (unlikely(msg_version(msg) != TIPC_VERSION))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ size = msg_size(msg);
|
|
|
|
+ hdr_size = msg_hdr_sz(msg);
|
|
|
|
+ min_hdr_size = msg_isdata(msg) ?
|
|
|
|
+ min_data_hdr_size[msg_type(msg)] : INT_H_SIZE;
|
|
|
|
+
|
|
|
|
+ if (unlikely((hdr_size < min_hdr_size) ||
|
|
|
|
+ (size < hdr_size) ||
|
|
|
|
+ (buf->len < size) ||
|
|
|
|
+ (size - hdr_size > TIPC_MAX_USER_MSG_SIZE)))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ return pskb_may_pull(buf, hdr_size);
|
|
|
|
+}
|
|
|
|
+
|
|
void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
{
|
|
{
|
|
read_lock_bh(&tipc_net_lock);
|
|
read_lock_bh(&tipc_net_lock);
|
|
@@ -1794,9 +1844,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
struct link *l_ptr;
|
|
struct link *l_ptr;
|
|
struct sk_buff *crs;
|
|
struct sk_buff *crs;
|
|
struct sk_buff *buf = head;
|
|
struct sk_buff *buf = head;
|
|
- struct tipc_msg *msg = buf_msg(buf);
|
|
|
|
- u32 seq_no = msg_seqno(msg);
|
|
|
|
- u32 ackd = msg_ack(msg);
|
|
|
|
|
|
+ struct tipc_msg *msg;
|
|
|
|
+ u32 seq_no;
|
|
|
|
+ u32 ackd;
|
|
u32 released = 0;
|
|
u32 released = 0;
|
|
int type;
|
|
int type;
|
|
|
|
|
|
@@ -1804,12 +1854,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
TIPC_SKB_CB(buf)->handle = b_ptr;
|
|
TIPC_SKB_CB(buf)->handle = b_ptr;
|
|
|
|
|
|
head = head->next;
|
|
head = head->next;
|
|
- if (unlikely(msg_version(msg) != TIPC_VERSION))
|
|
|
|
|
|
+
|
|
|
|
+ /* Ensure message is well-formed */
|
|
|
|
+
|
|
|
|
+ if (unlikely(!link_recv_buf_validate(buf)))
|
|
goto cont;
|
|
goto cont;
|
|
-#if 0
|
|
|
|
- if (msg_user(msg) != LINK_PROTOCOL)
|
|
|
|
-#endif
|
|
|
|
- msg_dbg(msg,"<REC<");
|
|
|
|
|
|
|
|
/* Ensure message data is a single contiguous unit */
|
|
/* Ensure message data is a single contiguous unit */
|
|
|
|
|
|
@@ -1817,6 +1866,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
goto cont;
|
|
goto cont;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Handle arrival of a non-unicast link message */
|
|
|
|
+
|
|
|
|
+ msg = buf_msg(buf);
|
|
|
|
+
|
|
if (unlikely(msg_non_seq(msg))) {
|
|
if (unlikely(msg_non_seq(msg))) {
|
|
link_recv_non_seq(buf);
|
|
link_recv_non_seq(buf);
|
|
continue;
|
|
continue;
|
|
@@ -1826,19 +1879,26 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
(msg_destnode(msg) != tipc_own_addr)))
|
|
(msg_destnode(msg) != tipc_own_addr)))
|
|
goto cont;
|
|
goto cont;
|
|
|
|
|
|
|
|
+ /* Locate unicast link endpoint that should handle message */
|
|
|
|
+
|
|
n_ptr = tipc_node_find(msg_prevnode(msg));
|
|
n_ptr = tipc_node_find(msg_prevnode(msg));
|
|
if (unlikely(!n_ptr))
|
|
if (unlikely(!n_ptr))
|
|
goto cont;
|
|
goto cont;
|
|
-
|
|
|
|
tipc_node_lock(n_ptr);
|
|
tipc_node_lock(n_ptr);
|
|
|
|
+
|
|
l_ptr = n_ptr->links[b_ptr->identity];
|
|
l_ptr = n_ptr->links[b_ptr->identity];
|
|
if (unlikely(!l_ptr)) {
|
|
if (unlikely(!l_ptr)) {
|
|
tipc_node_unlock(n_ptr);
|
|
tipc_node_unlock(n_ptr);
|
|
goto cont;
|
|
goto cont;
|
|
}
|
|
}
|
|
- /*
|
|
|
|
- * Release acked messages
|
|
|
|
- */
|
|
|
|
|
|
+
|
|
|
|
+ /* Validate message sequence number info */
|
|
|
|
+
|
|
|
|
+ seq_no = msg_seqno(msg);
|
|
|
|
+ ackd = msg_ack(msg);
|
|
|
|
+
|
|
|
|
+ /* Release acked messages */
|
|
|
|
+
|
|
if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
|
|
if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
|
|
if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported)
|
|
if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported)
|
|
tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
|
|
tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
|
|
@@ -1857,6 +1917,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
l_ptr->first_out = crs;
|
|
l_ptr->first_out = crs;
|
|
l_ptr->out_queue_size -= released;
|
|
l_ptr->out_queue_size -= released;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Try sending any messages link endpoint has pending */
|
|
|
|
+
|
|
if (unlikely(l_ptr->next_out))
|
|
if (unlikely(l_ptr->next_out))
|
|
tipc_link_push_queue(l_ptr);
|
|
tipc_link_push_queue(l_ptr);
|
|
if (unlikely(!list_empty(&l_ptr->waiting_ports)))
|
|
if (unlikely(!list_empty(&l_ptr->waiting_ports)))
|
|
@@ -1866,6 +1929,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
|
|
tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
|
|
tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Now (finally!) process the incoming message */
|
|
|
|
+
|
|
protocol_check:
|
|
protocol_check:
|
|
if (likely(link_working_working(l_ptr))) {
|
|
if (likely(link_working_working(l_ptr))) {
|
|
if (likely(seq_no == mod(l_ptr->next_in_no))) {
|
|
if (likely(seq_no == mod(l_ptr->next_in_no))) {
|