summaryrefslogtreecommitdiff
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c102
1 files changed, 96 insertions, 6 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 7e6240e41e69..ea33eab4fb9d 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -57,6 +57,10 @@ static int tipc_release(struct socket *sock);
static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
static void tipc_sk_timeout(unsigned long ref);
+static int tipc_sk_publish(struct tipc_port *port, uint scope,
+ struct tipc_name_seq const *seq);
+static int tipc_sk_withdraw(struct tipc_port *port, uint scope,
+ struct tipc_name_seq const *seq);
static const struct proto_ops packet_ops;
static const struct proto_ops stream_ops;
@@ -138,6 +142,38 @@ static void reject_rx_queue(struct sock *sk)
}
}
+/* tipc_sk_peer_msg - verify if message was sent by connected port's peer
+ *
+ * Handles cases where the node's network address has changed from
+ * the default of <0.0.0> to its configured setting.
+ */
+static bool tipc_sk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)
+{
+ u32 peer_port = tipc_port_peerport(&tsk->port);
+ u32 orig_node;
+ u32 peer_node;
+
+ if (unlikely(!tsk->port.connected))
+ return false;
+
+ if (unlikely(msg_origport(msg) != peer_port))
+ return false;
+
+ orig_node = msg_orignode(msg);
+ peer_node = tipc_port_peernode(&tsk->port);
+
+ if (likely(orig_node == peer_node))
+ return true;
+
+ if (!orig_node && (peer_node == tipc_own_addr))
+ return true;
+
+ if (!peer_node && (orig_node == tipc_own_addr))
+ return true;
+
+ return false;
+}
+
/**
* tipc_sk_create - create a TIPC socket
* @net: network namespace (must be default network)
@@ -356,7 +392,7 @@ static int tipc_release(struct socket *sock)
}
}
- tipc_withdraw(port, 0, NULL);
+ tipc_sk_withdraw(port, 0, NULL);
tipc_ref_discard(port->ref);
k_cancel_timer(&port->timer);
if (port->connected) {
@@ -407,7 +443,7 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
lock_sock(sk);
if (unlikely(!uaddr_len)) {
- res = tipc_withdraw(&tsk->port, 0, NULL);
+ res = tipc_sk_withdraw(&tsk->port, 0, NULL);
goto exit;
}
@@ -435,8 +471,8 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
}
res = (addr->scope > 0) ?
- tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) :
- tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);
+ tipc_sk_publish(&tsk->port, addr->scope, &addr->addr.nameseq) :
+ tipc_sk_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);
exit:
release_sock(sk);
return res;
@@ -663,7 +699,7 @@ static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode,
int conn_cong;
/* Ignore if connection cannot be validated: */
- if (!port->connected || !tipc_port_peer_msg(port, msg))
+ if (!tipc_sk_peer_msg(tsk, msg))
goto exit;
port->probing_state = TIPC_CONN_OK;
@@ -1444,7 +1480,7 @@ static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
switch ((int)sock->state) {
case SS_CONNECTED:
/* Accept only connection-based messages sent by peer */
- if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) {
+ if (tipc_sk_peer_msg(tsk, msg)) {
if (unlikely(msg_errcode(msg))) {
sock->state = SS_DISCONNECTING;
port->connected = 0;
@@ -2027,6 +2063,60 @@ exit:
tipc_sk_put(tsk);
}
+static int tipc_sk_publish(struct tipc_port *port, uint scope,
+ struct tipc_name_seq const *seq)
+{
+ struct publication *publ;
+ u32 key;
+
+ if (port->connected)
+ return -EINVAL;
+ key = port->ref + port->pub_count + 1;
+ if (key == port->ref)
+ return -EADDRINUSE;
+
+ publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
+ scope, port->ref, key);
+ if (unlikely(!publ))
+ return -EINVAL;
+
+ list_add(&publ->pport_list, &port->publications);
+ port->pub_count++;
+ port->published = 1;
+ return 0;
+}
+
+static int tipc_sk_withdraw(struct tipc_port *port, uint scope,
+ struct tipc_name_seq const *seq)
+{
+ struct publication *publ;
+ struct publication *safe;
+ int rc = -EINVAL;
+
+ list_for_each_entry_safe(publ, safe, &port->publications, pport_list) {
+ if (seq) {
+ if (publ->scope != scope)
+ continue;
+ if (publ->type != seq->type)
+ continue;
+ if (publ->lower != seq->lower)
+ continue;
+ if (publ->upper != seq->upper)
+ break;
+ tipc_nametbl_withdraw(publ->type, publ->lower,
+ publ->ref, publ->key);
+ rc = 0;
+ break;
+ }
+ tipc_nametbl_withdraw(publ->type, publ->lower,
+ publ->ref, publ->key);
+ rc = 0;
+ }
+ if (list_empty(&port->publications))
+ port->published = 0;
+ return rc;
+}
+
static int tipc_sk_show(struct tipc_port *port, char *buf,
int len, int full_id)
{