summaryrefslogtreecommitdiffstats
path: root/if.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2015-03-07 12:08:32 +0000
committerRoy Marples <roy@marples.name>2015-03-07 12:08:32 +0000
commit3e3a5dcbbe0ebfd891f71da296d8ae7be394428c (patch)
tree921acf96c2be6910f837cfcecf49a4d668696e0a /if.c
parent648b5c64478baaab23926809e723ce5425cea42f (diff)
downloaddhcpcd-3e3a5dcbbe0ebfd891f71da296d8ae7be394428c.tar.xz
Include IPv6RA and DHCPv6 in the sorting of interfaces.
Diffstat (limited to 'if.c')
-rw-r--r--if.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/if.c b/if.c
index 7526b77a..de3693e7 100644
--- a/if.c
+++ b/if.c
@@ -588,3 +588,72 @@ if_domtu(const char *ifname, short int mtu)
return -1;
return ifr.ifr_mtu;
}
+
+/* Interface comparer for working out ordering. */
+static int
+if_cmp(const struct interface *si, const struct interface *ti)
+{
+#ifdef INET
+ int r;
+#endif
+
+ if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
+ return -1;
+ if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
+ return 1;
+ if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti))
+ return -1;
+ if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti))
+ return 1;
+ if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti))
+ return -1;
+ if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti))
+ return 1;
+
+#ifdef INET
+ /* Special attention needed hereto due take states and IPv4LL. */
+ if ((r = ipv4_ifcmp(si, ti)) != 0)
+ return r;
+#endif
+
+ /* Then carrier status. */
+ if (si->carrier > ti->carrier)
+ return -1;
+ if (si->carrier < ti->carrier)
+ return 1;
+ /* Finally, metric */
+ if (si->metric < ti->metric)
+ return -1;
+ if (si->metric > ti->metric)
+ return 1;
+ return 0;
+}
+
+/* Sort the interfaces into a preferred order - best first, worst last. */
+void
+if_sortinterfaces(struct dhcpcd_ctx *ctx)
+{
+ struct if_head sorted;
+ struct interface *ifp, *ift;
+
+ if (ctx->ifaces == NULL ||
+ (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL ||
+ TAILQ_NEXT(ifp, next) == NULL)
+ return;
+
+ TAILQ_INIT(&sorted);
+ TAILQ_REMOVE(ctx->ifaces, ifp, next);
+ TAILQ_INSERT_HEAD(&sorted, ifp, next);
+ while ((ifp = TAILQ_FIRST(ctx->ifaces))) {
+ TAILQ_REMOVE(ctx->ifaces, ifp, next);
+ TAILQ_FOREACH(ift, &sorted, next) {
+ if (if_cmp(ifp, ift) == -1) {
+ TAILQ_INSERT_BEFORE(ift, ifp, next);
+ break;
+ }
+ }
+ if (ift == NULL)
+ TAILQ_INSERT_TAIL(&sorted, ifp, next);
+ }
+ TAILQ_CONCAT(ctx->ifaces, &sorted, next);
+}