From 2b7b07e025b7d620a1debf5adf4c6d251512cf38 Mon Sep 17 00:00:00 2001
From: Ben Pfaff <blp@nicira.com>
Date: Thu, 5 Mar 2009 13:13:30 -0800
Subject: [PATCH] datapath: Fix querying the local port by name.

Before, this would return an ENOENT error.
---
 datapath/datapath.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 9581e792..85f5a6a6 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -354,6 +354,16 @@ static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
 	p->dev = dev;
 	if (port_no != ODPP_LOCAL)
 		rcu_assign_pointer(dev->br_port, p);
+	else {
+		/* For consistency it would make sense to assign dev->br_port
+		 * here too, but we can't because that would cause packets
+		 * received on the local port to get caught in
+		 * dp_frame_hook().  On modern Linux kernels that's not a big
+		 * deal--we would just return an appropriate value--but on
+		 * Linux 2.4 there's no way for the frame hook to pass along
+		 * the skbuff to the rest of the network stack.  So we're
+		 * stuck with the status quo. */
+	}
 	rcu_assign_pointer(dp->ports[port_no], p);
 	list_add_rcu(&p->node, &dp->port_list);
 	dp->n_ports++;
@@ -1140,7 +1150,6 @@ query_port(struct datapath *dp, struct odp_port __user *uport)
 	if (copy_from_user(&port, uport, sizeof port))
 		return -EFAULT;
 	if (port.devname[0]) {
-		struct net_bridge_port *p;
 		struct net_device *dev;
 		int err;
 
@@ -1150,8 +1159,12 @@ query_port(struct datapath *dp, struct odp_port __user *uport)
 		if (!dev)
 			return -ENODEV;
 
-		p = dev->br_port;
-		err = p && p->dp == dp ? put_port(p, uport) : -ENOENT;
+		if (dev == dp->ports[ODPP_LOCAL]->dev) {
+			err = put_port(dp->ports[ODPP_LOCAL], uport);
+		} else {
+			struct net_bridge_port *p = dev->br_port;
+			err = p && p->dp == dp ? put_port(p, uport) : -ENOENT;
+		}
 		dev_put(dev);
 
 		return err;
-- 
2.30.2