tipc: let function tipc_msg_reverse() expand header when needed
authorJon Paul Maloy <jon.maloy@ericsson.com>
Wed, 22 Jul 2015 14:11:18 +0000 (10:11 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sun, 26 Jul 2015 23:31:50 +0000 (16:31 -0700)
The shortest TIPC message header, for cluster local CONNECTED messages,
is 24 bytes long. With this format, the fields "dest_node" and
"orig_node" are optimized away, since they in reality are redundant
in this particular case.

However, the absence of these fields leads to code inconsistencies
that are difficult to handle in some cases, especially when we need
to reverse or reject messages at the socket layer.

In this commit, we concentrate the handling of the absent fields
to one place, by letting the function tipc_msg_reverse() reallocate
the buffer and expand the header to 32 bytes when necessary. This
means that the socket code now can assume that the two previously
absent fields are present in the header when a message needs to be
rejected. This opens up for some further simplifications of the
socket code.

Reviewed-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/msg.c
net/tipc/msg.h
net/tipc/socket.c

index 08b4cc7d496d94c80fb2fcacc30ade0192fb0dc8..4339aab930348c557c119510b6c7cf52563bf808 100644 (file)
@@ -463,43 +463,58 @@ bool tipc_msg_make_bundle(struct sk_buff **skb,  struct tipc_msg *msg,
 
 /**
  * tipc_msg_reverse(): swap source and destination addresses and add error code
- * @buf:  buffer containing message to be reversed
- * @dnode: return value: node where to send message after reversal
- * @err:  error code to be set in message
- * Consumes buffer if failure
+ * @own_node: originating node id for reversed message
+ * @skb:  buffer containing message to be reversed; may be replaced.
+ * @err:  error code to be set in message, if any
+ * Consumes buffer at failure
  * Returns true if success, otherwise false
  */
-bool tipc_msg_reverse(u32 own_addr,  struct sk_buff *buf, u32 *dnode,
-                     int err)
+bool tipc_msg_reverse(u32 own_node,  struct sk_buff **skb, u32 *dnode, int err)
 {
-       struct tipc_msg *msg = buf_msg(buf);
+       struct sk_buff *_skb = *skb;
+       struct tipc_msg *hdr = buf_msg(_skb);
        struct tipc_msg ohdr;
-       uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE);
+       int dlen = min_t(uint, msg_data_sz(hdr), MAX_FORWARD_SIZE);
 
-       if (skb_linearize(buf))
+       if (skb_linearize(_skb))
                goto exit;
-       msg = buf_msg(buf);
-       if (msg_dest_droppable(msg))
+       hdr = buf_msg(_skb);
+       if (msg_dest_droppable(hdr))
                goto exit;
-       if (msg_errcode(msg))
+       if (msg_errcode(hdr))
                goto exit;
-       memcpy(&ohdr, msg, msg_hdr_sz(msg));
-       msg_set_errcode(msg, err);
-       msg_set_origport(msg, msg_destport(&ohdr));
-       msg_set_destport(msg, msg_origport(&ohdr));
-       msg_set_prevnode(msg, own_addr);
-       if (!msg_short(msg)) {
-               msg_set_orignode(msg, msg_destnode(&ohdr));
-               msg_set_destnode(msg, msg_orignode(&ohdr));
+
+       /* Take a copy of original header before altering message */
+       memcpy(&ohdr, hdr, msg_hdr_sz(hdr));
+
+       /* Never return SHORT header; expand by replacing buffer if necessary */
+       if (msg_short(hdr)) {
+               *skb = tipc_buf_acquire(BASIC_H_SIZE + dlen);
+               if (!*skb)
+                       goto exit;
+               memcpy((*skb)->data + BASIC_H_SIZE, msg_data(hdr), dlen);
+               kfree_skb(_skb);
+               _skb = *skb;
+               hdr = buf_msg(_skb);
+               memcpy(hdr, &ohdr, BASIC_H_SIZE);
+               msg_set_hdr_sz(hdr, BASIC_H_SIZE);
        }
-       msg_set_size(msg, msg_hdr_sz(msg) + rdsz);
-       skb_trim(buf, msg_size(msg));
-       skb_orphan(buf);
-       *dnode = msg_orignode(&ohdr);
+
+       /* Now reverse the concerned fields */
+       msg_set_errcode(hdr, err);
+       msg_set_origport(hdr, msg_destport(&ohdr));
+       msg_set_destport(hdr, msg_origport(&ohdr));
+       msg_set_destnode(hdr, msg_prevnode(&ohdr));
+       msg_set_prevnode(hdr, own_node);
+       msg_set_orignode(hdr, own_node);
+       msg_set_size(hdr, msg_hdr_sz(hdr) + dlen);
+       *dnode = msg_destnode(hdr);
+       skb_trim(_skb, msg_size(hdr));
+       skb_orphan(_skb);
        return true;
 exit:
-       kfree_skb(buf);
-       *dnode = 0;
+       kfree_skb(_skb);
+       *skb = NULL;
        return false;
 }
 
index 2f1563b47e24f78373bb9d1b57b3c8ec426f5f91..0e96f59e33157d6c1a009d561a7197810253f81a 100644 (file)
@@ -785,8 +785,7 @@ static inline bool msg_peer_is_up(struct tipc_msg *m)
 
 struct sk_buff *tipc_buf_acquire(u32 size);
 bool tipc_msg_validate(struct sk_buff *skb);
-bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode,
-                     int err);
+bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, u32 *dnode, int err);
 void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type,
                   u32 hsize, u32 destnode);
 struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
index 5b0b08d58fcc139b88628d3d0c111c066010f002..e2d5b983148536cc0df192d08ce7c63858aa5518 100644 (file)
@@ -260,7 +260,7 @@ static void tsk_rej_rx_queue(struct sock *sk)
        u32 own_node = tsk_own_node(tipc_sk(sk));
 
        while ((skb = __skb_dequeue(&sk->sk_receive_queue))) {
-               if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_ERR_NO_PORT))
+               if (tipc_msg_reverse(own_node, &skb, &dnode, TIPC_ERR_NO_PORT))
                        tipc_node_xmit_skb(sock_net(sk), skb, dnode, 0);
        }
 }
@@ -441,7 +441,7 @@ static int tipc_release(struct socket *sock)
                                tsk->connected = 0;
                                tipc_node_remove_conn(net, dnode, tsk->portid);
                        }
-                       if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode,
+                       if (tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode,
                                             TIPC_ERR_NO_PORT))
                                tipc_node_xmit_skb(net, skb, dnode, 0);
                }
@@ -784,7 +784,7 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff **skb)
                if (conn_cong)
                        tsk->sk.sk_write_space(&tsk->sk);
        } else if (msg_type(msg) == CONN_PROBE) {
-               if (tipc_msg_reverse(own_node, *skb, &dnode, TIPC_OK)) {
+               if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_OK)) {
                        msg_set_type(msg, CONN_PROBE_REPLY);
                        return;
                }
@@ -1702,7 +1702,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
                        atomic_add(truesize, dcnt);
                return 0;
        }
-       if (!err || tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, -err))
+       if (!err || tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, -err))
                tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
        return 0;
 }
@@ -1796,7 +1796,7 @@ int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
                        goto xmit;
                }
                tn = net_generic(net, tipc_net_id);
-               if (!tipc_msg_reverse(tn->own_addr, skb, &dnode, -err))
+               if (!tipc_msg_reverse(tn->own_addr, &skb, &dnode, -err))
                        continue;
 xmit:
                tipc_node_xmit_skb(net, skb, dnode, dport);
@@ -2090,7 +2090,7 @@ restart:
                                kfree_skb(skb);
                                goto restart;
                        }
-                       if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode,
+                       if (tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode,
                                             TIPC_CONN_SHUTDOWN))
                                tipc_node_xmit_skb(net, skb, dnode,
                                                   tsk->portid);