3 #include <libubox/uloop.h>
4 #include <netinet/in.h>
7 #include <libubox/utils.h>
13 static struct ubus_context
*ubus
= NULL
;
14 static struct ubus_subscriber netifd
;
15 static struct blob_buf b
;
16 static struct blob_attr
*dump
= NULL
;
17 static uint32_t objid
= 0;
18 static struct ubus_request req_dump
= { .list
= LIST_HEAD_INIT(req_dump
.list
) };
20 static int handle_dhcpv4_leases(struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
21 struct ubus_request_data
*req
, _unused
const char *method
,
22 _unused
struct blob_attr
*msg
)
24 struct interface
*iface
;
25 time_t now
= odhcpd_time();
29 a
= blobmsg_open_table(&b
, "device");
31 avl_for_each_element(&interfaces
, iface
, avl
) {
32 if (iface
->dhcpv4
!= MODE_SERVER
)
35 void *i
= blobmsg_open_table(&b
, iface
->ifname
);
36 void *j
= blobmsg_open_array(&b
, "leases");
38 struct dhcp_assignment
*c
;
39 list_for_each_entry(c
, &iface
->dhcpv4_assignments
, head
) {
40 if (!INFINITE_VALID(c
->valid_until
) && c
->valid_until
< now
)
43 void *m
, *l
= blobmsg_open_table(&b
, NULL
);
44 char *buf
= blobmsg_alloc_string_buffer(&b
, "mac", 13);
46 odhcpd_hexlify(buf
, c
->hwaddr
, sizeof(c
->hwaddr
));
47 blobmsg_add_string_buffer(&b
);
49 blobmsg_add_string(&b
, "hostname", (c
->hostname
) ? c
->hostname
: "");
50 blobmsg_add_u8(&b
, "accept-reconf-nonce", c
->accept_fr_nonce
);
55 buf
= blobmsg_alloc_string_buffer(&b
, "reqopts", strlen(c
->reqopts
) * 4 + 1);
56 for(; c
->reqopts
[opt
]; opt
++)
57 chars
+= snprintf(buf
+ chars
, 6, "%u,", (uint8_t)c
->reqopts
[opt
]);
58 buf
[chars
- 1] = '\0';
59 blobmsg_add_string_buffer(&b
);
62 m
= blobmsg_open_array(&b
, "flags");
63 if (c
->flags
& OAF_BOUND
)
64 blobmsg_add_string(&b
, NULL
, "bound");
66 if (c
->flags
& OAF_STATIC
)
67 blobmsg_add_string(&b
, NULL
, "static");
69 if (c
->flags
& OAF_BROKEN_HOSTNAME
)
70 blobmsg_add_string(&b
, NULL
, "broken-hostname");
71 blobmsg_close_array(&b
, m
);
73 buf
= blobmsg_alloc_string_buffer(&b
, "address", INET_ADDRSTRLEN
);
74 struct in_addr addr
= {.s_addr
= c
->addr
};
75 inet_ntop(AF_INET
, &addr
, buf
, INET_ADDRSTRLEN
);
76 blobmsg_add_string_buffer(&b
);
78 blobmsg_add_u32(&b
, "valid", INFINITE_VALID(c
->valid_until
) ?
79 (uint32_t)-1 : (uint32_t)(c
->valid_until
- now
));
81 blobmsg_close_table(&b
, l
);
84 blobmsg_close_array(&b
, j
);
85 blobmsg_close_table(&b
, i
);
88 blobmsg_close_table(&b
, a
);
89 ubus_send_reply(ctx
, req
, b
.head
);
94 static void dhcpv6_blobmsg_ia_addr(struct in6_addr
*addr
, int prefix
, uint32_t pref
,
95 uint32_t valid
, _unused
void *arg
)
97 void *a
= blobmsg_open_table(&b
, NULL
);
98 char *buf
= blobmsg_alloc_string_buffer(&b
, "address", INET6_ADDRSTRLEN
);
100 inet_ntop(AF_INET6
, addr
, buf
, INET6_ADDRSTRLEN
);
101 blobmsg_add_string_buffer(&b
);
102 blobmsg_add_u32(&b
, "preferred-lifetime",
103 pref
== UINT32_MAX
? (uint32_t)-1 : pref
);
104 blobmsg_add_u32(&b
, "valid-lifetime",
105 valid
== UINT32_MAX
? (uint32_t)-1 : valid
);
108 blobmsg_add_u32(&b
, "prefix-length", prefix
);
110 blobmsg_close_table(&b
, a
);
113 static int handle_dhcpv6_leases(_unused
struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
114 _unused
struct ubus_request_data
*req
, _unused
const char *method
,
115 _unused
struct blob_attr
*msg
)
117 struct interface
*iface
;
118 time_t now
= odhcpd_time();
121 blob_buf_init(&b
, 0);
122 a
= blobmsg_open_table(&b
, "device");
124 avl_for_each_element(&interfaces
, iface
, avl
) {
125 if (iface
->dhcpv6
!= MODE_SERVER
)
128 void *i
= blobmsg_open_table(&b
, iface
->ifname
);
129 void *j
= blobmsg_open_array(&b
, "leases");
131 struct dhcp_assignment
*a
, *border
= list_last_entry(
132 &iface
->ia_assignments
, struct dhcp_assignment
, head
);
134 list_for_each_entry(a
, &iface
->ia_assignments
, head
) {
135 if (a
== border
|| (!INFINITE_VALID(a
->valid_until
) &&
136 a
->valid_until
< now
))
139 void *m
, *l
= blobmsg_open_table(&b
, NULL
);
140 char *buf
= blobmsg_alloc_string_buffer(&b
, "duid", 264);
142 odhcpd_hexlify(buf
, a
->clid_data
, a
->clid_len
);
143 blobmsg_add_string_buffer(&b
);
145 blobmsg_add_u32(&b
, "iaid", ntohl(a
->iaid
));
146 blobmsg_add_string(&b
, "hostname", (a
->hostname
) ? a
->hostname
: "");
147 blobmsg_add_u8(&b
, "accept-reconf", a
->accept_reconf
);
148 if (a
->flags
& OAF_DHCPV6_NA
)
149 blobmsg_add_u64(&b
, "assigned", a
->assigned_host_id
);
151 blobmsg_add_u16(&b
, "assigned", a
->assigned_subnet_id
);
153 m
= blobmsg_open_array(&b
, "flags");
154 if (a
->flags
& OAF_BOUND
)
155 blobmsg_add_string(&b
, NULL
, "bound");
157 if (a
->flags
& OAF_STATIC
)
158 blobmsg_add_string(&b
, NULL
, "static");
159 blobmsg_close_array(&b
, m
);
161 m
= blobmsg_open_array(&b
, a
->flags
& OAF_DHCPV6_NA
? "ipv6-addr": "ipv6-prefix");
162 dhcpv6_ia_enum_addrs(iface
, a
, now
, dhcpv6_blobmsg_ia_addr
, NULL
);
163 blobmsg_close_table(&b
, m
);
165 blobmsg_add_u32(&b
, "valid", INFINITE_VALID(a
->valid_until
) ?
166 (uint32_t)-1 : (uint32_t)(a
->valid_until
- now
));
168 blobmsg_close_table(&b
, l
);
171 blobmsg_close_array(&b
, j
);
172 blobmsg_close_table(&b
, i
);
175 blobmsg_close_table(&b
, a
);
176 ubus_send_reply(ctx
, req
, b
.head
);
180 static int handle_add_lease(_unused
struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
181 _unused
struct ubus_request_data
*req
, _unused
const char *method
,
182 struct blob_attr
*msg
)
184 if (!set_lease_from_blobmsg(msg
))
185 return UBUS_STATUS_OK
;
187 return UBUS_STATUS_INVALID_ARGUMENT
;
190 static struct ubus_method main_object_methods
[] = {
191 {.name
= "ipv4leases", .handler
= handle_dhcpv4_leases
},
192 {.name
= "ipv6leases", .handler
= handle_dhcpv6_leases
},
193 UBUS_METHOD("add_lease", handle_add_lease
, lease_attrs
),
196 static struct ubus_object_type main_object_type
=
197 UBUS_OBJECT_TYPE("dhcp", main_object_methods
);
199 static struct ubus_object main_object
= {
201 .type
= &main_object_type
,
202 .methods
= main_object_methods
,
203 .n_methods
= ARRAY_SIZE(main_object_methods
),
212 static const struct blobmsg_policy dump_attrs
[DUMP_ATTR_MAX
] = {
213 [DUMP_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_ARRAY
},
218 IFACE_ATTR_INTERFACE
,
227 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
228 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
229 [IFACE_ATTR_IFNAME
] = { .name
= "l3_device", .type
= BLOBMSG_TYPE_STRING
},
230 [IFACE_ATTR_UP
] = { .name
= "up", .type
= BLOBMSG_TYPE_BOOL
},
231 [IFACE_ATTR_DATA
] = { .name
= "data", .type
= BLOBMSG_TYPE_TABLE
},
232 [IFACE_ATTR_PREFIX
] = { .name
= "ipv6-prefix", .type
= BLOBMSG_TYPE_ARRAY
},
233 [IFACE_ATTR_ADDRESS
] = { .name
= "ipv6-address", .type
= BLOBMSG_TYPE_ARRAY
},
236 static void handle_dump(_unused
struct ubus_request
*req
, _unused
int type
, struct blob_attr
*msg
)
238 struct blob_attr
*tb
[DUMP_ATTR_MAX
];
239 blobmsg_parse(dump_attrs
, DUMP_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
241 if (!tb
[DUMP_ATTR_INTERFACE
])
245 dump
= blob_memdup(tb
[DUMP_ATTR_INTERFACE
]);
250 static void update_netifd(bool subscribe
)
253 ubus_subscribe(ubus
, &netifd
, objid
);
255 ubus_abort_request(ubus
, &req_dump
);
256 blob_buf_init(&b
, 0);
258 if (!ubus_invoke_async(ubus
, objid
, "dump", b
.head
, &req_dump
)) {
259 req_dump
.data_cb
= handle_dump
;
260 ubus_complete_request_async(ubus
, &req_dump
);
265 static int handle_update(_unused
struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
266 _unused
struct ubus_request_data
*req
, _unused
const char *method
,
267 struct blob_attr
*msg
)
269 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
273 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
274 const char *interface
= (tb
[IFACE_ATTR_INTERFACE
]) ?
275 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]) : "";
277 avl_for_each_element(&interfaces
, c
, avl
) {
278 if (!strcmp(interface
, c
->name
) && c
->ignore
) {
285 update_netifd(false);
291 void ubus_apply_network(void)
299 blobmsg_for_each_attr(a
, dump
, rem
) {
300 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
301 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(a
), blobmsg_data_len(a
));
303 if (!tb
[IFACE_ATTR_INTERFACE
] || !tb
[IFACE_ATTR_DATA
])
306 const char *interface
= (tb
[IFACE_ATTR_INTERFACE
]) ?
307 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]) : "";
309 bool matched
= false;
310 struct interface
*c
, *tmp
;
311 avl_for_each_element_safe(&interfaces
, c
, avl
, tmp
) {
312 char *f
= memmem(c
->upstream
, c
->upstream_len
,
313 interface
, strlen(interface
) + 1);
314 bool cmatched
= !strcmp(interface
, c
->name
);
317 if (!cmatched
&& (!c
->upstream_len
|| !f
|| (f
!= c
->upstream
&& f
[-1] != 0)))
321 config_parse_interface(blobmsg_data(tb
[IFACE_ATTR_DATA
]),
322 blobmsg_data_len(tb
[IFACE_ATTR_DATA
]), c
->name
, false);
326 config_parse_interface(blobmsg_data(tb
[IFACE_ATTR_DATA
]),
327 blobmsg_data_len(tb
[IFACE_ATTR_DATA
]), interface
, false);
338 static const struct blobmsg_policy obj_attrs
[OBJ_ATTR_MAX
] = {
339 [OBJ_ATTR_ID
] = { .name
= "id", .type
= BLOBMSG_TYPE_INT32
},
340 [OBJ_ATTR_PATH
] = { .name
= "path", .type
= BLOBMSG_TYPE_STRING
},
343 void ubus_bcast_dhcp_event(const char *type
, const uint8_t *mac
,
344 const size_t mlen
, const struct in_addr
*addr
, const char *name
,
345 const char *interface
)
347 if (!ubus
|| !main_object
.has_subscribers
)
350 blob_buf_init(&b
, 0);
352 blobmsg_add_string(&b
, "mac", odhcpd_print_mac(mac
, mlen
));
354 blobmsg_add_string(&b
, "ip", inet_ntoa(*addr
));
356 blobmsg_add_string(&b
, "name", name
);
358 blobmsg_add_string(&b
, "interface", interface
);
360 ubus_notify(ubus
, &main_object
, type
, b
.head
, -1);
363 static void handle_event(_unused
struct ubus_context
*ctx
, _unused
struct ubus_event_handler
*ev
,
364 _unused
const char *type
, struct blob_attr
*msg
)
366 struct blob_attr
*tb
[OBJ_ATTR_MAX
];
367 blobmsg_parse(obj_attrs
, OBJ_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
369 if (!tb
[OBJ_ATTR_ID
] || !tb
[OBJ_ATTR_PATH
])
372 if (strcmp(blobmsg_get_string(tb
[OBJ_ATTR_PATH
]), "network.interface"))
375 objid
= blobmsg_get_u32(tb
[OBJ_ATTR_ID
]);
379 static struct ubus_event_handler event_handler
= { .cb
= handle_event
};
382 const char* ubus_get_ifname(const char *name
)
390 blobmsg_for_each_attr(c
, dump
, rem
) {
391 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
392 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
394 if (!tb
[IFACE_ATTR_INTERFACE
] || strcmp(name
,
395 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
])))
398 if (tb
[IFACE_ATTR_IFNAME
])
399 return blobmsg_get_string(tb
[IFACE_ATTR_IFNAME
]);
406 bool ubus_has_prefix(const char *name
, const char *ifname
)
408 struct blob_attr
*c
, *cur
;
414 blobmsg_for_each_attr(c
, dump
, rem
) {
415 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
416 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
418 if (!tb
[IFACE_ATTR_INTERFACE
] || !tb
[IFACE_ATTR_IFNAME
])
421 if (strcmp(name
, blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
])) ||
422 strcmp(ifname
, blobmsg_get_string(tb
[IFACE_ATTR_IFNAME
])))
425 if ((cur
= tb
[IFACE_ATTR_PREFIX
])) {
426 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
|| !blobmsg_check_attr(cur
, false))
431 blobmsg_for_each_attr(d
, cur
, drem
) {
443 if (!(ubus
= ubus_connect(NULL
))) {
444 syslog(LOG_ERR
, "Unable to connect to ubus: %m");
448 netifd
.cb
= handle_update
;
449 ubus_register_subscriber(ubus
, &netifd
);
451 ubus_add_uloop(ubus
);
452 ubus_add_object(ubus
, &main_object
);
453 ubus_register_event_handler(ubus
, &event_handler
, "ubus.object.add");
454 if (!ubus_lookup_id(ubus
, "network.interface", &objid
))