6 #include <libubox/uapi.h>
11 static struct avl_tree devices
;
13 static int avl_strcmp(const void *k1
, const void *k2
, void *ptr
)
15 return strcmp(k1
, k2
);
18 static void API_CTOR
dev_init(void)
20 avl_init(&devices
, avl_strcmp
, false, NULL
);
23 static void free_device(struct device
*dev
)
29 static void broadcast_device_event(struct device
*dev
, enum device_event ev
)
31 struct device_user
*dep
, *tmp
;
33 list_for_each_entry_safe(dep
, tmp
, &dev
->users
, list
) {
41 static int set_device_state(struct device
*dev
, bool state
)
44 broadcast_device_event(dev
, DEV_EVENT_SETUP
);
46 broadcast_device_event(dev
, DEV_EVENT_UP
);
48 broadcast_device_event(dev
, DEV_EVENT_TEARDOWN
);
50 broadcast_device_event(dev
, DEV_EVENT_DOWN
);
55 int claim_device(struct device
*dev
)
59 DPRINTF("claim device %s, new refcount: %d\n", dev
->ifname
, dev
->active
+ 1);
60 if (++dev
->active
!= 1)
63 ret
= dev
->set_state(dev
, true);
70 void release_device(struct device
*dev
)
73 DPRINTF("release device %s, new refcount: %d\n", dev
->ifname
, dev
->active
);
74 assert(dev
->active
>= 0);
77 dev
->set_state(dev
, false);
80 int check_device_state(struct device
*dev
)
82 if (!dev
->type
->check_state
)
85 return dev
->type
->check_state(dev
);
88 void init_virtual_device(struct device
*dev
, const struct device_type
*type
, const char *name
)
93 fprintf(stderr
, "Initialize interface '%s'\n", dev
->ifname
);
94 INIT_LIST_HEAD(&dev
->users
);
98 strncpy(dev
->ifname
, name
, IFNAMSIZ
);
101 int init_device(struct device
*dev
, const struct device_type
*type
, const char *ifname
)
105 init_virtual_device(dev
, type
, ifname
);
108 dev
->set_state
= set_device_state
;
110 dev
->avl
.key
= dev
->ifname
;
112 ret
= avl_insert(&devices
, &dev
->avl
);
116 check_device_state(dev
);
121 struct device
*get_device(const char *name
, bool create
)
123 static const struct device_type simple_type
= {
125 .check_state
= system_if_check
,
131 if (strchr(name
, '.'))
132 return get_vlan_device_chain(name
, create
);
134 dev
= avl_find_element(&devices
, name
, dev
, avl
);
141 dev
= calloc(1, sizeof(*dev
));
142 init_device(dev
, &simple_type
, name
);
147 void cleanup_device(struct device
*dev
)
149 struct device_user
*dep
, *tmp
;
151 fprintf(stderr
, "Clean up interface '%s'\n", dev
->ifname
);
152 list_for_each_entry_safe(dep
, tmp
, &dev
->users
, list
) {
156 dep
->cb(dep
, DEV_EVENT_REMOVE
);
160 avl_delete(&devices
, &dev
->avl
);
163 void set_device_present(struct device
*dev
, bool state
)
165 if (dev
->present
== state
)
168 DPRINTF("Device '%s' %s present\n", dev
->ifname
, state
? "is now" : "is no longer" );
169 dev
->present
= state
;
170 broadcast_device_event(dev
, state
? DEV_EVENT_ADD
: DEV_EVENT_REMOVE
);
173 void add_device_user(struct device_user
*dep
, struct device
*dev
)
176 list_add(&dep
->list
, &dev
->users
);
177 if (dep
->cb
&& dev
->present
) {
178 dep
->cb(dep
, DEV_EVENT_ADD
);
180 dep
->cb(dep
, DEV_EVENT_UP
);
184 void remove_device_user(struct device_user
*dep
)
186 struct device
*dev
= dep
->dev
;
188 list_del(&dep
->list
);
190 if (list_empty(&dev
->users
)) {
191 /* all references have gone away, remove this interface */
192 dev
->type
->free(dev
);