2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
20 #include "interface.h"
22 static struct avl_tree aliases
;
27 struct device_user dep
;
28 struct device_user new_dep
;
33 static const struct device_type alias_device_type
;
35 static void alias_set_device(struct alias_device
*alias
, struct device
*dev
)
37 if (dev
== alias
->dep
.dev
) {
39 device_remove_user(&alias
->new_dep
);
40 alias
->update
= false;
42 device_set_present(&alias
->dev
, true);
47 device_set_present(&alias
->dev
, false);
48 device_remove_user(&alias
->new_dep
);
49 if (alias
->dev
.active
) {
51 device_add_user(&alias
->new_dep
, dev
);
57 alias
->update
= false;
58 device_remove_user(&alias
->dep
);
59 alias
->dev
.hidden
= !dev
;
61 device_set_ifindex(&alias
->dev
, dev
->ifindex
);
62 strcpy(alias
->dev
.ifname
, dev
->ifname
);
63 device_broadcast_event(&alias
->dev
, DEV_EVENT_UPDATE_IFNAME
);
64 device_add_user(&alias
->dep
, dev
);
66 alias
->dev
.ifname
[0] = 0;
67 device_broadcast_event(&alias
->dev
, DEV_EVENT_UPDATE_IFNAME
);
72 alias_device_set_state(struct device
*dev
, bool state
)
74 struct alias_device
*alias
;
76 alias
= container_of(dev
, struct alias_device
, dev
);
81 return device_claim(&alias
->dep
);
83 device_release(&alias
->dep
);
85 alias_set_device(alias
, alias
->new_dep
.dev
);
90 static void alias_device_cb(struct device_user
*dep
, enum device_event ev
)
92 struct alias_device
*alias
;
93 bool new_state
= false;
95 alias
= container_of(dep
, struct alias_device
, dep
);
99 case DEV_EVENT_REMOVE
:
100 device_set_present(&alias
->dev
, new_state
);
102 case DEV_EVENT_LINK_UP
:
104 case DEV_EVENT_LINK_DOWN
:
105 device_set_link(&alias
->dev
, new_state
);
107 case DEV_EVENT_UPDATE_IFINDEX
:
108 device_set_ifindex(&alias
->dev
, dep
->dev
->ifindex
);
111 device_broadcast_event(&alias
->dev
, ev
);
116 static struct device
*
117 alias_device_create(const char *name
, struct blob_attr
*attr
)
119 struct alias_device
*alias
;
121 alias
= calloc(1, sizeof(*alias
) + strlen(name
) + 1);
125 strcpy(alias
->name
, name
);
126 alias
->dev
.set_state
= alias_device_set_state
;
127 alias
->dev
.hidden
= true;
128 device_init_virtual(&alias
->dev
, &alias_device_type
, NULL
);
129 alias
->avl
.key
= alias
->name
;
130 avl_insert(&aliases
, &alias
->avl
);
131 alias
->dep
.alias
= true;
132 alias
->dep
.cb
= alias_device_cb
;
133 device_check_state(&alias
->dev
);
138 static void alias_device_free(struct device
*dev
)
140 struct alias_device
*alias
;
142 alias
= container_of(dev
, struct alias_device
, dev
);
143 device_remove_user(&alias
->new_dep
);
144 device_remove_user(&alias
->dep
);
145 avl_delete(&aliases
, &alias
->avl
);
149 static int alias_check_state(struct device
*dev
)
151 struct alias_device
*alias
;
152 struct interface
*iface
;
153 struct device
*ndev
= NULL
;
155 alias
= container_of(dev
, struct alias_device
, dev
);
157 iface
= vlist_find(&interfaces
, alias
->name
, iface
, node
);
158 if (iface
&& iface
->state
== IFS_UP
)
159 ndev
= iface
->l3_dev
.dev
;
161 alias_set_device(alias
, ndev
);
166 static const struct device_type alias_device_type
= {
167 .name
= "Network alias",
168 .create
= alias_device_create
,
169 .free
= alias_device_free
,
170 .check_state
= alias_check_state
,
174 alias_notify_device(const char *name
, struct device
*dev
)
176 struct alias_device
*alias
;
180 alias
= avl_find_element(&aliases
, name
, alias
, avl
);
182 alias_set_device(alias
, dev
);
188 device_alias_get(const char *name
)
190 struct alias_device
*alias
;
192 alias
= avl_find_element(&aliases
, name
, alias
, avl
);
196 return alias_device_create(name
, NULL
);
199 static void __init
alias_init(void)
201 avl_init(&aliases
, avl_strcmp
, false, NULL
);