restructure the proto state, add a callback for notifications by the protocol handler...
[project/netifd.git] / interface.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #include "netifd.h"
6 #include "ubus.h"
7
8 LIST_HEAD(interfaces);
9
10 static void
11 clear_interface_errors(struct interface *iface)
12 {
13         struct interface_error *error, *tmp;
14
15         list_for_each_entry_safe(error, tmp, &iface->errors, list) {
16                 list_del(&error->list);
17                 free(error);
18         }
19 }
20
21 void interface_add_error(struct interface *iface, const char *subsystem,
22                          const char *code, const char **data, int n_data)
23 {
24         struct interface_error *error;
25         int i, len = 0;
26         int *datalen;
27         char *dest;
28
29         if (n_data) {
30                 len = n_data * sizeof(char *);
31                 datalen = alloca(len);
32                 for (i = 0; i < n_data; i++) {
33                         datalen[i] = strlen(data[i]) + 1;
34                         len += datalen[i];
35                 }
36         }
37
38         error = calloc(1, sizeof(*error) + sizeof(char *) + len);
39         if (!error)
40                 return;
41
42         list_add_tail(&error->list, &iface->errors);
43         error->subsystem = subsystem;
44         error->code = code;
45
46         dest = (char *) &error->data[n_data + 1];
47         for (i = 0; i < n_data; i++) {
48                 error->data[i] = dest;
49                 memcpy(dest, data[i], datalen[i]);
50                 dest += datalen[i];
51         }
52         error->data[n_data] = NULL;
53 }
54
55 static int
56 interface_event(struct interface *iface, enum interface_event ev)
57 {
58         if (!iface->state || !iface->state->event)
59                 return 0;
60
61         return iface->state->event(iface->state, ev);
62 }
63
64 static void
65 __set_interface_up(struct interface *iface)
66 {
67         if (iface->up)
68                 return;
69
70         if (claim_device(iface->main_dev.dev) < 0)
71                 return;
72
73         if (interface_event(iface, IFEV_UP) < 0) {
74                 release_device(iface->main_dev.dev);
75                 return;
76         }
77
78         iface->up = true;
79 }
80
81 static void
82 __set_interface_down(struct interface *iface)
83 {
84         clear_interface_errors(iface);
85
86         if (!iface->up)
87                 return;
88
89         iface->up = false;
90         interface_event(iface, IFEV_DOWN);
91         release_device(iface->main_dev.dev);
92 }
93
94 static void
95 interface_cb(struct device_user *dep, enum device_event ev)
96 {
97         struct interface *iface;
98         bool new_state;
99
100         iface = container_of(dep, struct interface, main_dev);
101         switch (ev) {
102         case DEV_EVENT_ADD:
103                 new_state = true;
104                 break;
105         case DEV_EVENT_REMOVE:
106                 new_state = false;
107                 break;
108         default:
109                 return;
110         }
111
112         if (iface->active == new_state)
113                 return;
114
115         iface->active = new_state;
116
117         if (new_state) {
118                 if (iface->autostart)
119                         __set_interface_up(iface);
120         } else
121                 __set_interface_down(iface);
122 }
123
124 struct interface *
125 alloc_interface(const char *name)
126 {
127         struct interface *iface;
128
129         iface = get_interface(name);
130         if (iface)
131                 return iface;
132
133         iface = calloc(1, sizeof(*iface));
134         iface->main_dev.cb = interface_cb;
135         iface->l3_iface = &iface->main_dev;
136         strncpy(iface->name, name, sizeof(iface->name) - 1);
137         list_add(&iface->list, &interfaces);
138         INIT_LIST_HEAD(&iface->errors);
139
140         netifd_ubus_add_interface(iface);
141
142         return iface;
143 }
144
145 void
146 free_interface(struct interface *iface)
147 {
148         netifd_ubus_remove_interface(iface);
149         list_del(&iface->list);
150         if (iface->state && iface->state->free)
151                 iface->state->free(iface->state);
152         free(iface);
153 }
154
155 struct interface *
156 get_interface(const char *name)
157 {
158         struct interface *iface;
159
160         list_for_each_entry(iface, &interfaces, list) {
161                 if (!strcmp(iface->name, name))
162                         return iface;
163         }
164         return NULL;
165 }
166
167 void
168 interface_remove_link(struct interface *iface, struct device *llif)
169 {
170         struct device *dev = iface->main_dev.dev;
171
172         if (dev && dev->hotplug_ops) {
173                 dev->hotplug_ops->del(dev, llif);
174                 return;
175         }
176
177         remove_device_user(&iface->main_dev);
178 }
179
180 int
181 interface_add_link(struct interface *iface, struct device *llif)
182 {
183         struct device *dev = iface->main_dev.dev;
184
185         if (dev && dev->hotplug_ops)
186                 return dev->hotplug_ops->add(dev, llif);
187
188         if (iface->main_dev.dev)
189                 interface_remove_link(iface, NULL);
190
191         add_device_user(&iface->main_dev, llif);
192
193         return 0;
194 }
195
196 int
197 set_interface_up(struct interface *iface)
198 {
199         iface->autostart = true;
200
201         if (!iface->active) {
202                 interface_add_error(iface, "interface", "NO_DEVICE", NULL, 0);
203                 return -1;
204         }
205
206         if (iface->up)
207                 return -1;
208
209         __set_interface_up(iface);
210         return 0;
211 }
212
213 int
214 set_interface_down(struct interface *iface)
215 {
216         iface->autostart = false;
217         __set_interface_down(iface);
218
219         return 0;
220 }