3 #include <libubox/uloop.h>
11 static struct ubus_context
*ubus
= NULL
;
12 static struct ubus_subscriber netifd
;
13 static struct blob_buf b
;
14 static struct blob_attr
*dump
= NULL
;
15 static uint32_t objid
= 0;
16 static struct ubus_request req_dump
= { .list
= LIST_HEAD_INIT(req_dump
.list
) };
19 static int handle_dhcpv4_leases(struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
20 struct ubus_request_data
*req
, _unused
const char *method
,
21 _unused
struct blob_attr
*msg
)
24 void *a
= blobmsg_open_table(&b
, "device");
25 time_t now
= odhcpd_time();
27 struct interface
*iface
;
28 list_for_each_entry(iface
, &interfaces
, head
) {
29 if (iface
->dhcpv4
!= RELAYD_SERVER
)
32 void *i
= blobmsg_open_table(&b
, iface
->ifname
);
33 void *j
= blobmsg_open_array(&b
, "leases");
35 struct dhcpv4_assignment
*lease
;
36 list_for_each_entry(lease
, &iface
->dhcpv4_assignments
, head
) {
37 if (lease
->valid_until
< now
)
40 void *l
= blobmsg_open_table(&b
, NULL
);
42 char *buf
= blobmsg_alloc_string_buffer(&b
, "mac", 13);
43 odhcpd_hexlify(buf
, lease
->hwaddr
, sizeof(lease
->hwaddr
));
44 blobmsg_add_string_buffer(&b
);
46 blobmsg_add_string(&b
, "hostname", lease
->hostname
);
48 buf
= blobmsg_alloc_string_buffer(&b
, "ip", INET_ADDRSTRLEN
);
49 struct in_addr addr
= {htonl(lease
->addr
)};
50 inet_ntop(AF_INET
, &addr
, buf
, INET_ADDRSTRLEN
);
51 blobmsg_add_string_buffer(&b
);
53 blobmsg_add_u32(&b
, "valid", now
- lease
->valid_until
);
55 blobmsg_close_table(&b
, l
);
58 blobmsg_close_array(&b
, j
);
59 blobmsg_close_table(&b
, i
);
62 blobmsg_close_table(&b
, a
);
63 ubus_send_reply(ctx
, req
, b
.head
);
68 static int handle_dhcpv6_leases(_unused
struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
69 _unused
struct ubus_request_data
*req
, _unused
const char *method
,
70 _unused
struct blob_attr
*msg
)
73 void *a
= blobmsg_open_table(&b
, "device");
74 time_t now
= odhcpd_time();
76 struct interface
*iface
;
77 list_for_each_entry(iface
, &interfaces
, head
) {
78 if (iface
->dhcpv6
!= RELAYD_SERVER
)
81 void *i
= blobmsg_open_table(&b
, iface
->ifname
);
82 void *j
= blobmsg_open_array(&b
, "leases");
84 struct dhcpv6_assignment
*lease
;
85 list_for_each_entry(lease
, &iface
->ia_assignments
, head
) {
86 if (lease
->valid_until
< now
)
89 void *l
= blobmsg_open_table(&b
, NULL
);
91 char *buf
= blobmsg_alloc_string_buffer(&b
, "duid", 264);
92 odhcpd_hexlify(buf
, lease
->clid_data
, lease
->clid_len
);
93 blobmsg_add_string_buffer(&b
);
95 blobmsg_add_u32(&b
, "iaid", ntohl(lease
->iaid
));
96 blobmsg_add_string(&b
, "hostname", (lease
->hostname
) ? lease
->hostname
: "");
97 blobmsg_add_u32(&b
, "assigned", lease
->assigned
);
98 blobmsg_add_u32(&b
, "length", lease
->length
);
100 void *m
= blobmsg_open_array(&b
, "ipv6");
101 struct in6_addr addr
;
102 for (size_t i
= 0; i
< iface
->ia_addr_len
; ++i
) {
103 if (iface
->ia_addr
[i
].prefix
> 64)
106 addr
= iface
->ia_addr
[i
].addr
;
107 if (lease
->length
== 128)
108 addr
.s6_addr32
[3] = htonl(lease
->assigned
);
110 addr
.s6_addr32
[1] |= htonl(lease
->assigned
);
112 char *c
= blobmsg_alloc_string_buffer(&b
, NULL
, INET6_ADDRSTRLEN
);
113 inet_ntop(AF_INET6
, &addr
, c
, INET6_ADDRSTRLEN
);
114 blobmsg_add_string_buffer(&b
);
116 blobmsg_close_table(&b
, m
);
118 blobmsg_add_u32(&b
, "valid", now
- lease
->valid_until
);
120 blobmsg_close_table(&b
, l
);
123 blobmsg_close_array(&b
, j
);
124 blobmsg_close_table(&b
, i
);
127 blobmsg_close_table(&b
, a
);
128 ubus_send_reply(ctx
, req
, b
.head
);
133 static struct ubus_method main_object_methods
[] = {
134 {.name
= "ipv4leases", .handler
= handle_dhcpv4_leases
},
135 {.name
= "ipv6leases", .handler
= handle_dhcpv6_leases
},
138 static struct ubus_object_type main_object_type
=
139 UBUS_OBJECT_TYPE("dhcp", main_object_methods
);
141 static struct ubus_object main_object
= {
143 .type
= &main_object_type
,
144 .methods
= main_object_methods
,
145 .n_methods
= ARRAY_SIZE(main_object_methods
),
154 static const struct blobmsg_policy dump_attrs
[DUMP_ATTR_MAX
] = {
155 [DUMP_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_ARRAY
},
160 IFACE_ATTR_INTERFACE
,
170 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
171 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
172 [IFACE_ATTR_IFNAME
] = { .name
= "l3_device", .type
= BLOBMSG_TYPE_STRING
},
173 [IFACE_ATTR_UP
] = { .name
= "up", .type
= BLOBMSG_TYPE_BOOL
},
174 [IFACE_ATTR_DATA
] = { .name
= "data", .type
= BLOBMSG_TYPE_TABLE
},
175 [IFACE_ATTR_PREFIX
] = { .name
= "ipv6-prefix", .type
= BLOBMSG_TYPE_ARRAY
},
176 [IFACE_ATTR_ADDRESS
] = { .name
= "ipv6-address", .type
= BLOBMSG_TYPE_ARRAY
},
177 [IFACE_ATTR_ADDRESS4
] = { .name
= "ipv4-address", .type
= BLOBMSG_TYPE_ARRAY
},
186 static const struct blobmsg_policy addr_attrs
[ADDR_ATTR_MAX
] = {
187 [ADDR_ATTR_ADDRESS
] = { .name
= "address", .type
= BLOBMSG_TYPE_ARRAY
},
188 [ADDR_ATTR_MASK
] = { .name
= "mask", .type
= BLOBMSG_TYPE_INT32
},
191 static void handle_dump(_unused
struct ubus_request
*req
, _unused
int type
, struct blob_attr
*msg
)
193 struct blob_attr
*tb
[DUMP_ATTR_MAX
];
194 blobmsg_parse(dump_attrs
, DUMP_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
196 if (!tb
[DUMP_ATTR_INTERFACE
])
200 dump
= blob_memdup(tb
[DUMP_ATTR_INTERFACE
]);
205 static void update_netifd(bool subscribe
)
208 ubus_subscribe(ubus
, &netifd
, objid
);
210 ubus_abort_request(ubus
, &req_dump
);
211 if (!ubus_invoke_async(ubus
, objid
, "dump", NULL
, &req_dump
)) {
212 req_dump
.data_cb
= handle_dump
;
213 ubus_complete_request_async(ubus
, &req_dump
);
218 static int handle_update(_unused
struct ubus_context
*ctx
, _unused
struct ubus_object
*obj
,
219 _unused
struct ubus_request_data
*req
, _unused
const char *method
,
220 struct blob_attr
*msg
)
222 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
223 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
225 const char *interface
= (tb
[IFACE_ATTR_INTERFACE
]) ?
226 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]) : "";
227 const char *ifname
= (tb
[IFACE_ATTR_IFNAME
]) ?
228 blobmsg_get_string(tb
[IFACE_ATTR_IFNAME
]) : "";
230 struct interface
*c
, *iface
= NULL
;
231 list_for_each_entry(c
, &interfaces
, head
)
232 if (!strcmp(interface
, c
->name
) || !strcmp(ifname
, c
->ifname
))
235 if (iface
&& iface
->ignore
)
238 update_netifd(false);
243 void ubus_apply_network(void)
251 blobmsg_for_each_attr(a
, dump
, rem
) {
252 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
253 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(a
), blobmsg_data_len(a
));
255 if (!tb
[IFACE_ATTR_INTERFACE
] || !tb
[IFACE_ATTR_DATA
])
258 const char *interface
= (tb
[IFACE_ATTR_INTERFACE
]) ?
259 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]) : "";
260 const char *ifname
= (tb
[IFACE_ATTR_IFNAME
]) ?
261 blobmsg_get_string(tb
[IFACE_ATTR_IFNAME
]) : "";
263 bool matched
= false;
264 struct interface
*c
, *n
;
265 list_for_each_entry_safe(c
, n
, &interfaces
, head
) {
266 char *f
= memmem(c
->upstream
, c
->upstream_len
,
267 interface
, strlen(interface
) + 1);
268 bool cmatched
= !strcmp(interface
, c
->name
) || !strcmp(ifname
, c
->ifname
);
271 if (!cmatched
&& (!c
->upstream_len
|| !f
|| (f
!= c
->upstream
&& f
[-1] != 0)))
275 config_parse_interface(blobmsg_data(tb
[IFACE_ATTR_DATA
]),
276 blobmsg_data_len(tb
[IFACE_ATTR_DATA
]), c
->name
, false);
280 config_parse_interface(blobmsg_data(tb
[IFACE_ATTR_DATA
]),
281 blobmsg_data_len(tb
[IFACE_ATTR_DATA
]), interface
, false);
292 static const struct blobmsg_policy obj_attrs
[OBJ_ATTR_MAX
] = {
293 [OBJ_ATTR_ID
] = { .name
= "id", .type
= BLOBMSG_TYPE_INT32
},
294 [OBJ_ATTR_PATH
] = { .name
= "path", .type
= BLOBMSG_TYPE_STRING
},
298 static void handle_event(_unused
struct ubus_context
*ctx
, _unused
struct ubus_event_handler
*ev
,
299 _unused
const char *type
, struct blob_attr
*msg
)
301 struct blob_attr
*tb
[OBJ_ATTR_MAX
];
302 blobmsg_parse(obj_attrs
, OBJ_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
304 if (!tb
[OBJ_ATTR_ID
] || !tb
[OBJ_ATTR_PATH
])
307 if (strcmp(blobmsg_get_string(tb
[OBJ_ATTR_PATH
]), "network.interface"))
310 objid
= blobmsg_get_u32(tb
[OBJ_ATTR_ID
]);
314 static struct ubus_event_handler event_handler
= { .cb
= handle_event
};
317 const char* ubus_get_ifname(const char *name
)
325 blobmsg_for_each_attr(c
, dump
, rem
) {
326 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
327 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
329 if (!tb
[IFACE_ATTR_INTERFACE
] || strcmp(name
,
330 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
])))
333 if (tb
[IFACE_ATTR_IFNAME
])
334 return blobmsg_get_string(tb
[IFACE_ATTR_IFNAME
]);
341 bool ubus_has_prefix(const char *name
, const char *ifname
)
343 struct blob_attr
*c
, *cur
;
349 blobmsg_for_each_attr(c
, dump
, rem
) {
350 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
351 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
353 if (!tb
[IFACE_ATTR_INTERFACE
] || !tb
[IFACE_ATTR_IFNAME
])
356 if (strcmp(name
, blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
])) ||
357 strcmp(ifname
, blobmsg_get_string(tb
[IFACE_ATTR_IFNAME
])))
360 if ((cur
= tb
[IFACE_ATTR_PREFIX
])) {
361 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
|| !blobmsg_check_attr(cur
, NULL
))
366 blobmsg_for_each_attr(d
, cur
, drem
) {
375 struct in_addr
ubus_get_address4(const char *name
)
377 struct blob_attr
*c
, *cur
;
383 blobmsg_for_each_attr(c
, dump
, rem
) {
384 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
385 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
387 if (!tb
[IFACE_ATTR_INTERFACE
] || strcmp(name
,
388 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
])))
391 if ((cur
= tb
[IFACE_ATTR_ADDRESS4
])) {
392 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
|| !blobmsg_check_attr(cur
, NULL
))
397 blobmsg_for_each_attr(d
, cur
, drem
) {
398 struct blob_attr
*addr
[ADDR_ATTR_MAX
];
399 blobmsg_parse(addr_attrs
, ADDR_ATTR_MAX
, addr
, blobmsg_data(d
), blobmsg_data_len(d
));
400 struct in_addr addr4
;
401 if (inet_pton(AF_INET
, blobmsg_get_string(addr
[ADDR_ATTR_ADDRESS
]), &addr4
) == 1)
410 struct in_addr
ubus_get_mask4(const char *name
)
412 struct blob_attr
*c
, *cur
;
418 blobmsg_for_each_attr(c
, dump
, rem
) {
419 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
420 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
422 if (!tb
[IFACE_ATTR_INTERFACE
] || strcmp(name
,
423 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
])))
426 if ((cur
= tb
[IFACE_ATTR_ADDRESS4
])) {
427 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
|| !blobmsg_check_attr(cur
, NULL
))
432 blobmsg_for_each_attr(d
, cur
, drem
) {
433 struct blob_attr
*addr
[ADDR_ATTR_MAX
];
434 blobmsg_parse(addr_attrs
, ADDR_ATTR_MAX
, addr
, blobmsg_data(d
), blobmsg_data_len(d
));
435 struct in_addr addr4
;
436 if (inet_pton(AF_INET
, blobmsg_get_string(addr
[ADDR_ATTR_MASK
]), &addr4
) == 1)
447 if (!(ubus
= ubus_connect(NULL
))) {
448 syslog(LOG_ERR
, "Unable to connect to ubus: %s", strerror(errno
));
452 netifd
.cb
= handle_update
;
453 ubus_register_subscriber(ubus
, &netifd
);
455 ubus_add_uloop(ubus
);
456 ubus_add_object(ubus
, &main_object
);
457 ubus_register_event_handler(ubus
, &event_handler
, "ubus.object.add");
458 if (!ubus_lookup_id(ubus
, "network.interface", &objid
))