+
+int phonet_route_add(struct net_device *dev, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ int err = -EEXIST;
+
+ daddr = daddr >> 2;
+ spin_lock_bh(&routes->lock);
+ if (routes->table[daddr] == NULL) {
+ routes->table[daddr] = dev;
+ dev_hold(dev);
+ err = 0;
+ }
+ spin_unlock_bh(&routes->lock);
+ return err;
+}
+
+int phonet_route_del(struct net_device *dev, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ int err = -ENOENT;
+
+ daddr = daddr >> 2;
+ spin_lock_bh(&routes->lock);
+ if (dev == routes->table[daddr]) {
+ routes->table[daddr] = NULL;
+ dev_put(dev);
+ err = 0;
+ }
+ spin_unlock_bh(&routes->lock);
+ return err;
+}
+
+struct net_device *phonet_route_get(struct net *net, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(net, phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ struct net_device *dev;
+
+ ASSERT_RTNL(); /* no need to hold the device */
+
+ daddr >>= 2;
+ spin_lock_bh(&routes->lock);
+ dev = routes->table[daddr];
+ spin_unlock_bh(&routes->lock);
+ return dev;
+}
+
+struct net_device *phonet_route_output(struct net *net, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(net, phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ struct net_device *dev;
+
+ spin_lock_bh(&routes->lock);
+ dev = routes->table[daddr >> 2];
+ if (dev)
+ dev_hold(dev);
+ spin_unlock_bh(&routes->lock);
+
+ if (!dev)
+ dev = phonet_device_get(net); /* Default route */
+ return dev;
+}