7 #include <sys/socket.h>
8 #include <net/ethernet.h>
14 static struct avl_tree devices
;
16 static const struct blobmsg_policy dev_attrs
[__DEV_ATTR_MAX
] = {
17 [DEV_ATTR_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
18 [DEV_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
19 [DEV_ATTR_IFNAME
] = { "ifname", BLOBMSG_TYPE_ARRAY
},
20 [DEV_ATTR_MTU
] = { "mtu", BLOBMSG_TYPE_INT32
},
21 [DEV_ATTR_MACADDR
] = { "macaddr", BLOBMSG_TYPE_STRING
},
22 [DEV_ATTR_TXQUEUELEN
] = { "txqueuelen", BLOBMSG_TYPE_INT32
},
25 const struct config_param_list device_attr_list
= {
26 .n_params
= __DEV_ATTR_MAX
,
30 static struct device
*
31 simple_device_create(struct blob_attr
*attr
)
33 struct blob_attr
*tb
[__DEV_ATTR_MAX
];
34 struct device
*dev
= NULL
;
37 blobmsg_parse(dev_attrs
, __DEV_ATTR_MAX
, tb
, blob_data(attr
), blob_len(attr
));
38 if (!tb
[DEV_ATTR_NAME
])
41 name
= blobmsg_data(tb
[DEV_ATTR_NAME
]);
45 dev
= device_get(name
, true);
49 device_init_settings(dev
, tb
);
54 static void simple_device_free(struct device
*dev
)
60 const struct device_type simple_device_type
= {
61 .name
= "Network device",
62 .config_params
= &device_attr_list
,
64 .create
= simple_device_create
,
65 .check_state
= system_if_check
,
66 .free
= simple_device_free
,
70 device_init_settings(struct device
*dev
, struct blob_attr
**tb
)
72 struct blob_attr
*cur
;
73 struct ether_addr
*ea
;
77 if ((cur
= tb
[DEV_ATTR_MTU
])) {
78 dev
->mtu
= blobmsg_get_u32(cur
);
79 dev
->flags
|= DEV_OPT_MTU
;
82 if ((cur
= tb
[DEV_ATTR_TXQUEUELEN
])) {
83 dev
->txqueuelen
= blobmsg_get_u32(cur
);
84 dev
->flags
|= DEV_OPT_TXQUEUELEN
;
87 if ((cur
= tb
[DEV_ATTR_MACADDR
])) {
88 ea
= ether_aton(blob_data(cur
));
90 memcpy(dev
->macaddr
, ea
, sizeof(dev
->macaddr
));
91 dev
->flags
|= DEV_OPT_MACADDR
;
96 static void __init
dev_init(void)
98 avl_init(&devices
, avl_strcmp
, false, NULL
);
101 static void device_broadcast_event(struct device
*dev
, enum device_event ev
)
103 struct device_user
*dep
, *tmp
;
105 list_for_each_entry_safe(dep
, tmp
, &dev
->users
, list
) {
113 static int set_device_state(struct device
*dev
, bool state
)
123 int device_claim(struct device_user
*dep
)
125 struct device
*dev
= dep
->dev
;
132 DPRINTF("claim device %s, new refcount: %d\n", dev
->ifname
, dev
->active
+ 1);
133 if (++dev
->active
!= 1)
136 device_broadcast_event(dev
, DEV_EVENT_SETUP
);
137 ret
= dev
->set_state(dev
, true);
139 device_broadcast_event(dev
, DEV_EVENT_UP
);
146 void device_release(struct device_user
*dep
)
148 struct device
*dev
= dep
->dev
;
153 dep
->claimed
= false;
155 DPRINTF("release device %s, new refcount: %d\n", dev
->ifname
, dev
->active
);
156 assert(dev
->active
>= 0);
161 device_broadcast_event(dev
, DEV_EVENT_TEARDOWN
);
162 dev
->set_state(dev
, false);
163 device_broadcast_event(dev
, DEV_EVENT_DOWN
);
166 int check_device_state(struct device
*dev
)
168 if (!dev
->type
->check_state
)
171 return dev
->type
->check_state(dev
);
174 void device_init_virtual(struct device
*dev
, const struct device_type
*type
, const char *name
)
180 strncpy(dev
->ifname
, name
, IFNAMSIZ
);
182 fprintf(stderr
, "Initialize device '%s'\n", dev
->ifname
);
183 INIT_LIST_HEAD(&dev
->users
);
187 int device_init(struct device
*dev
, const struct device_type
*type
, const char *ifname
)
191 device_init_virtual(dev
, type
, ifname
);
194 dev
->set_state
= set_device_state
;
196 dev
->avl
.key
= dev
->ifname
;
198 ret
= avl_insert(&devices
, &dev
->avl
);
202 check_device_state(dev
);
207 struct device
*device_get(const char *name
, bool create
)
211 if (strchr(name
, '.'))
212 return get_vlan_device_chain(name
, create
);
214 dev
= avl_find_element(&devices
, name
, dev
, avl
);
221 dev
= calloc(1, sizeof(*dev
));
222 device_init(dev
, &simple_device_type
, name
);
227 void device_cleanup(struct device
*dev
)
229 struct device_user
*dep
, *tmp
;
231 fprintf(stderr
, "Clean up device '%s'\n", dev
->ifname
);
232 list_for_each_entry_safe(dep
, tmp
, &dev
->users
, list
) {
236 dep
->cb(dep
, DEV_EVENT_REMOVE
);
240 avl_delete(&devices
, &dev
->avl
);
243 void device_set_present(struct device
*dev
, bool state
)
245 if (dev
->present
== state
)
248 DPRINTF("Device '%s' %s present\n", dev
->ifname
, state
? "is now" : "is no longer" );
249 dev
->present
= state
;
250 device_broadcast_event(dev
, state
? DEV_EVENT_ADD
: DEV_EVENT_REMOVE
);
253 void device_add_user(struct device_user
*dep
, struct device
*dev
)
256 list_add_tail(&dep
->list
, &dev
->users
);
257 if (dep
->cb
&& dev
->present
) {
258 dep
->cb(dep
, DEV_EVENT_ADD
);
260 dep
->cb(dep
, DEV_EVENT_UP
);
264 void device_remove_user(struct device_user
*dep
)
266 struct device
*dev
= dep
->dev
;
271 list_del(&dep
->list
);
273 if (list_empty(&dev
->users
)) {
274 /* all references have gone away, remove this device */
282 __device_free_unused(struct device
*dev
)
284 if (!list_empty(&dev
->users
))
291 device_free_unused(struct device
*dev
)
296 return __device_free_unused(dev
);
298 avl_for_each_element_safe(&devices
, dev
, avl
, tmp
)
299 __device_free_unused(dev
);