summaryrefslogtreecommitdiff
path: root/net/mctp/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mctp/route.c')
-rw-r--r--net/mctp/route.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 89e67399249b..5ef6b3b0a3d9 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -480,6 +480,10 @@ static int mctp_alloc_local_tag(struct mctp_sock *msk,
int rc = -EAGAIN;
u8 tagbits;
+ /* for NULL destination EIDs, we may get a response from any peer */
+ if (daddr == MCTP_ADDR_NULL)
+ daddr = MCTP_ADDR_ANY;
+
/* be optimistic, alloc now */
key = mctp_key_alloc(msk, saddr, daddr, 0, GFP_KERNEL);
if (!key)
@@ -545,6 +549,8 @@ struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
{
struct mctp_route *tmp, *rt = NULL;
+ rcu_read_lock();
+
list_for_each_entry_rcu(tmp, &net->mctp.routes, list) {
/* TODO: add metrics */
if (mctp_rt_match_eid(tmp, dnet, daddr)) {
@@ -555,6 +561,28 @@ struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
}
}
+ rcu_read_unlock();
+
+ return rt;
+}
+
+static struct mctp_route *mctp_route_lookup_null(struct net *net,
+ struct net_device *dev)
+{
+ struct mctp_route *tmp, *rt = NULL;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(tmp, &net->mctp.routes, list) {
+ if (tmp->dev->dev == dev && tmp->type == RTN_LOCAL &&
+ refcount_inc_not_zero(&tmp->refs)) {
+ rt = tmp;
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+
return rt;
}
@@ -853,6 +881,11 @@ static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
rcu_read_unlock();
rt = mctp_route_lookup(net, cb->net, mh->dest);
+
+ /* NULL EID, but addressed to our physical address */
+ if (!rt && mh->dest == MCTP_ADDR_NULL && skb->pkt_type == PACKET_HOST)
+ rt = mctp_route_lookup_null(net, dev);
+
if (!rt)
goto err_drop;