|
@@ -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)
|
|
|
{
|