Network interfaces at 0.0.0.0?

David Wragg (dpw@doc.ic.ac.uk)
17 Dec 1998 01:22:08 +0000


2.0 happily allows networks interfaces to be configured with IP
address 0.0.0.0, meaning no particular IP address. This is useful for
things such as hosts which get their IP configuration via BOOTP.

But this support has disappeared in 2.1. Was there a good reason for
this? The IP-autoconfiguration via BOOTP is still there, but the
implementation has to jump through hoops, and those tricks can't be
done from userspace. I can't find any other equivalent functionality
(well, except by using raw sockets, ick).

In trying to understand what the problem with 0.0.0.0 was, I hacked
support into 2.1.131, see patch below. Although I'm not totally happy
with it (I need to think more about the change in fib_frontend.c), it
works fine. Could networking experts let me know if something is
fundamentally wrong with it. I'd really like to see 0.0.0.0 support
back in 2.2.

Dave Wragg

(Most of this patch is just BOOTP code that gets simplified away)

diff -rua linux-2.1.131/net/ipv4/devinet.c linux-2.1.131.bootp/net/ipv4/devinet.c
--- linux-2.1.131/net/ipv4/devinet.c Mon Sep 7 14:27:58 1998
+++ linux-2.1.131.bootp/net/ipv4/devinet.c Wed Dec 16 16:13:11 1998
@@ -208,9 +208,16 @@
{
struct in_ifaddr *ifa1, **ifap, **last_primary;

- if (ifa->ifa_local == 0) {
- inet_free_ifa(ifa);
- return 0;
+ /* Allow 0.0.0.0, but it must be the only address, to avoid
+ multiple matches. */
+ if (in_dev->ifa_list) {
+ if (ifa->ifa_local == 0) {
+ inet_free_ifa(ifa);
+ return 0;
+ }
+
+ if (in_dev->ifa_list->ifa_local == 0)
+ inet_del_ifa(in_dev, &in_dev->ifa_list, 1);
}

ifa->ifa_flags &= ~IFA_F_SECONDARY;
@@ -1001,18 +1008,12 @@

__initfunc(int inet_add_bootp_addr(struct device *dev))
{
- struct in_device *in_dev = dev->ip_ptr;
struct in_ifaddr *ifa;

- if (!in_dev && !(in_dev = inetdev_init(dev)))
- return -ENOBUFS;
if (!(ifa = inet_alloc_ifa()))
return -ENOBUFS;
- ifa->ifa_dev = in_dev;
- in_dev->ifa_list = ifa;
- rtmsg_ifa(RTM_NEWADDR, ifa);
- notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
- return 0;
+
+ return inet_set_ifa(dev, ifa);
}

__initfunc(void inet_del_bootp_addr(struct device *dev))
diff -rua linux-2.1.131/net/ipv4/fib_frontend.c linux-2.1.131.bootp/net/ipv4/fib_frontend.c
--- linux-2.1.131/net/ipv4/fib_frontend.c Mon Sep 7 14:27:58 1998
+++ linux-2.1.131.bootp/net/ipv4/fib_frontend.c Wed Dec 16 16:13:59 1998
@@ -443,7 +443,7 @@
if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);

- if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
+ if (!(ifa->ifa_flags&IFA_F_SECONDARY) &&
(prefix != addr || ifa->ifa_prefixlen < 32)) {
fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
diff -rua linux-2.1.131/net/ipv4/ipconfig.c linux-2.1.131.bootp/net/ipv4/ipconfig.c
--- linux-2.1.131/net/ipv4/ipconfig.c Sun Nov 8 18:40:51 1998
+++ linux-2.1.131.bootp/net/ipv4/ipconfig.c Wed Dec 16 14:13:19 1998
@@ -411,96 +411,6 @@
static struct bootp_pkt *ic_recv_bootp __initdata = NULL; /* Packet being received */

/*
- * Dirty tricks for BOOTP packet routing. We replace the standard lookup function
- * for the local fib by our version which does fake lookups and returns our private
- * fib entries. Ugly, but it seems to be the simplest way to do the job.
- */
-
-static void *ic_old_local_lookup __initdata = NULL; /* Old local routing table lookup function */
-static struct fib_info *ic_bootp_tx_fib __initdata = NULL; /* Our fake fib entries */
-static struct fib_info *ic_bootp_rx_fib __initdata = NULL;
-
-__initfunc(static int ic_bootp_route_lookup(struct fib_table *tb, const struct rt_key *key,
- struct fib_result *res))
-{
- static u32 ic_brl_zero = 0;
-
- DBG(("BOOTP: Route lookup: %d:%08x -> %d:%08x: ", key->iif, key->src, key->oif, key->dst));
- res->scope = RT_SCOPE_UNIVERSE;
- res->prefix = &ic_brl_zero;
- res->prefixlen = 0;
- res->nh_sel = 0;
- if (key->src == 0 && key->dst == 0xffffffff && key->iif == loopback_dev.ifindex) { /* Packet output */
- DBG(("Output\n"));
- res->type = RTN_UNICAST;
- res->fi = ic_bootp_tx_fib;
- } else if (key->iif && key->iif != loopback_dev.ifindex && key->oif == 0) { /* Packet input */
- DBG(("Input\n"));
- res->type = RTN_LOCAL;
- res->fi = ic_bootp_rx_fib;
- } else if (!key->iif && !key->oif && !key->src) { /* Address check by inet_addr_type() */
- DBG(("Check\n"));
- res->type = RTN_UNICAST;
- res->fi = ic_bootp_tx_fib;
- } else {
- DBG(("Drop\n"));
- return -EINVAL;
- }
- return 0;
-}
-
-__initfunc(static int ic_set_bootp_route(struct ic_device *d))
-{
- struct fib_info *f = ic_bootp_tx_fib;
- struct fib_nh *n = &f->fib_nh[0];
-
- n->nh_dev = d->dev;
- n->nh_oif = n->nh_dev->ifindex;
- rt_cache_flush(0);
- return 0;
-}
-
-__initfunc(static int ic_bootp_route_init(void))
-{
- int size = sizeof(struct fib_info) + sizeof(struct fib_nh);
- struct fib_info *rf, *tf;
- struct fib_nh *nh;
-
- if (!(rf = ic_bootp_rx_fib = kmalloc(size, GFP_KERNEL)) ||
- !(tf = ic_bootp_tx_fib = kmalloc(size, GFP_KERNEL)))
- return -1;
-
- memset(rf, 0, size);
- rf->fib_nhs = 1;
- nh = &rf->fib_nh[0];
- nh->nh_scope = RT_SCOPE_UNIVERSE;
-
- memset(tf, 0, size);
- rf->fib_nhs = 1;
- nh = &rf->fib_nh[0];
- nh->nh_dev = ic_first_dev->dev;
- nh->nh_scope = RT_SCOPE_UNIVERSE;
- nh->nh_oif = nh->nh_dev->ifindex;
-
- /* Dirty trick: replace standard routing table lookup by our function */
- ic_old_local_lookup = local_table->tb_lookup;
- local_table->tb_lookup = ic_bootp_route_lookup;
-
- return 0;
-}
-
-__initfunc(static void ic_bootp_route_cleanup(void))
-{
- if (ic_old_local_lookup)
- local_table->tb_lookup = ic_old_local_lookup;
- if (ic_bootp_rx_fib)
- kfree_s(ic_bootp_rx_fib, sizeof(struct fib_info) + sizeof(struct fib_nh));
- if (ic_bootp_tx_fib)
- kfree_s(ic_bootp_tx_fib, sizeof(struct fib_info) + sizeof(struct fib_nh));
-}
-
-
-/*
* Allocation and freeing of BOOTP packet buffers.
*/
__initfunc(static int ic_bootp_alloc(void))
@@ -677,10 +587,9 @@
/* Add fake zero addresses to all interfaces */
if (ic_bootp_addrs_add() < 0)
return -1;
-
- /* Initialize BOOTP routing */
- if (ic_bootp_route_init() < 0)
- return -1;
+
+ /* Setting the addresses automatically creates appropriate
+ routes. */

/* Initialize common portion of BOOTP request */
memset(ic_xmit_bootp, 0, sizeof(struct bootp_pkt));
@@ -699,7 +608,6 @@
ic_bootp_xmit_sock->sk->broadcast = 1;
ic_bootp_xmit_sock->sk->reuse = 1;
ic_bootp_recv_sock->sk->reuse = 1;
- ic_set_bootp_route(ic_first_dev);
if (ic_udp_bind(ic_bootp_recv_sock, INADDR_ANY, 68) ||
ic_udp_bind(ic_bootp_xmit_sock, INADDR_ANY, 68) ||
ic_udp_connect(ic_bootp_xmit_sock, INADDR_BROADCAST, 67))
@@ -718,7 +626,6 @@
ic_udp_close(ic_bootp_recv_sock);
ic_bootp_addrs_del();
ic_bootp_free();
- ic_bootp_route_cleanup();
}


@@ -735,7 +642,6 @@
memset(b->hw_addr, 0, sizeof(b->hw_addr));
memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
b->secs = htons(jiffies / HZ);
- ic_set_bootp_route(d);
return ic_udp_send(ic_bootp_xmit_sock, b, sizeof(struct bootp_pkt));
}

diff -rua linux-2.1.131/net/ipv4/route.c linux-2.1.131.bootp/net/ipv4/route.c
--- linux-2.1.131/net/ipv4/route.c Sun Nov 8 18:40:06 1998
+++ linux-2.1.131.bootp/net/ipv4/route.c Wed Dec 16 14:12:40 1998
@@ -950,6 +950,10 @@
if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
goto martian_destination;

+ /* Accept anything arriving at 0.0.0.0 */
+ if (in_dev->ifa_list && in_dev->ifa_list->ifa_local == 0)
+ goto local_input;
+
/*
* Now we are ready to route packet.
*/

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/