1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29
30#include "config.h"
31#include "dhcpcd.h"
32#include "if-pref.h"
33#include "net.h"
34
35/* Interface comparer for working out ordering. */
36static int
37ifcmp(struct interface *si, struct interface *ti)
38{
39	int sill, till;
40
41	if (si->state && !ti->state)
42		return -1;
43	if (!si->state && ti->state)
44		return 1;
45	if (!si->state && !ti->state)
46		return 0;
47	/* If one has a lease and the other not, it takes precedence. */
48	if (si->state->new && !ti->state->new)
49		return -1;
50	if (!si->state->new && ti->state->new)
51		return 1;
52	/* If we are either, they neither have a lease, or they both have.
53	 * We need to check for IPv4LL and make it non-preferred. */
54	if (si->state->new && ti->state->new) {
55		sill = (si->state->new->cookie == htonl(MAGIC_COOKIE));
56		till = (ti->state->new->cookie == htonl(MAGIC_COOKIE));
57		if (!sill && till)
58			return -1;
59		if (sill && !till)
60			return 1;
61	}
62	/* Then carrier status. */
63	if (si->carrier > ti->carrier)
64		return -1;
65	if (si->carrier < ti->carrier)
66		return 1;
67	/* Finally, metric */
68	if (si->metric < ti->metric)
69		return -1;
70	if (si->metric > ti->metric)
71		return 1;
72	return 0;
73}
74
75/* Sort the interfaces into a preferred order - best first, worst last. */
76void
77sort_interfaces(void)
78{
79	struct interface *sorted, *ifp, *ifn, *ift;
80
81	if (!ifaces || !ifaces->next)
82		return;
83	sorted = ifaces;
84	ifaces = ifaces->next;
85	sorted->next = NULL;
86	for (ifp = ifaces; ifp && (ifn = ifp->next, 1); ifp = ifn) {
87		/* Are we the new head? */
88		if (ifcmp(ifp, sorted) == -1) {
89			ifp->next = sorted;
90			sorted = ifp;
91			continue;
92		}
93		/* Do we fit in the middle? */
94		for (ift = sorted; ift->next; ift = ift->next) {
95			if (ifcmp(ifp, ift->next) == -1) {
96				ifp->next = ift->next;
97				ift->next = ifp;
98				break;
99			}
100		}
101		/* We must be at the end */
102		if (!ift->next) {
103			ift->next = ifp;
104			ifp->next = NULL;
105		}
106	}
107	ifaces = sorted;
108}
109