2 * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <arpa/inet.h>
18 static struct ubus_msg_buf
*retmsg
;
19 static int *retmsg_data
;
20 static struct avl_tree clients
;
22 static struct blob_attr
*attrbuf
[UBUS_ATTR_MAX
];
24 typedef int (*ubus_cmd_cb
)(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
);
26 static const struct blob_attr_info ubus_policy
[UBUS_ATTR_MAX
] = {
27 [UBUS_ATTR_SIGNATURE
] = { .type
= BLOB_ATTR_NESTED
},
28 [UBUS_ATTR_OBJTYPE
] = { .type
= BLOB_ATTR_INT32
},
29 [UBUS_ATTR_OBJPATH
] = { .type
= BLOB_ATTR_STRING
},
30 [UBUS_ATTR_OBJID
] = { .type
= BLOB_ATTR_INT32
},
31 [UBUS_ATTR_STATUS
] = { .type
= BLOB_ATTR_INT32
},
34 static struct blob_attr
**ubus_parse_msg(struct blob_attr
*msg
)
36 blob_parse(msg
, attrbuf
, ubus_policy
, UBUS_ATTR_MAX
);
40 static void ubus_msg_init(struct ubus_msg_buf
*ub
, uint8_t type
, uint16_t seq
, uint32_t peer
)
48 static struct ubus_msg_buf
*ubus_msg_from_blob(bool shared
)
50 return ubus_msg_new(b
.head
, blob_raw_len(b
.head
), shared
);
53 static struct ubus_msg_buf
*ubus_reply_from_blob(struct ubus_msg_buf
*ub
, bool shared
)
55 struct ubus_msg_buf
*new;
57 new = ubus_msg_from_blob(shared
);
61 ubus_msg_init(new, UBUS_MSG_DATA
, ub
->hdr
.seq
, ub
->hdr
.peer
);
65 static bool ubusd_send_hello(struct ubus_client
*cl
)
67 struct ubus_msg_buf
*ub
;
70 ub
= ubus_msg_from_blob(true);
74 ubus_msg_init(ub
, UBUS_MSG_HELLO
, 0, cl
->id
.id
);
75 ubus_msg_send(cl
, ub
, true);
79 static int ubusd_send_pong(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
81 ub
->hdr
.type
= UBUS_MSG_DATA
;
82 ubus_msg_send(cl
, ub
, false);
86 static int ubusd_handle_remove_object(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
88 struct ubus_object
*obj
;
90 if (!attr
[UBUS_ATTR_OBJID
])
91 return UBUS_STATUS_INVALID_ARGUMENT
;
93 obj
= ubusd_find_object(blob_get_u32(attr
[UBUS_ATTR_OBJID
]));
95 return UBUS_STATUS_NOT_FOUND
;
97 if (obj
->client
!= cl
)
98 return UBUS_STATUS_PERMISSION_DENIED
;
100 blob_buf_init(&b
, 0);
101 blob_put_int32(&b
, UBUS_ATTR_OBJID
, obj
->id
.id
);
103 /* check if we're removing the object type as well */
104 if (obj
->type
&& obj
->type
->refcount
== 1)
105 blob_put_int32(&b
, UBUS_ATTR_OBJTYPE
, obj
->type
->id
.id
);
107 ubusd_free_object(obj
);
109 ub
= ubus_reply_from_blob(ub
, true);
111 return UBUS_STATUS_NO_DATA
;
113 ubus_msg_send(cl
, ub
, true);
117 static int ubusd_handle_add_object(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
119 struct ubus_object
*obj
;
121 obj
= ubusd_create_object(cl
, attr
);
123 return UBUS_STATUS_INVALID_ARGUMENT
;
125 blob_buf_init(&b
, 0);
126 blob_put_int32(&b
, UBUS_ATTR_OBJID
, obj
->id
.id
);
127 if (attr
[UBUS_ATTR_SIGNATURE
])
128 blob_put_int32(&b
, UBUS_ATTR_OBJTYPE
, obj
->type
->id
.id
);
130 ub
= ubus_reply_from_blob(ub
, true);
132 return UBUS_STATUS_NO_DATA
;
134 ubus_msg_send(cl
, ub
, true);
138 static void ubusd_send_obj(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct ubus_object
*obj
)
140 struct ubus_method
*m
;
143 blob_buf_init(&b
, 0);
146 blob_put_string(&b
, UBUS_ATTR_OBJPATH
, obj
->path
.key
);
147 blob_put_int32(&b
, UBUS_ATTR_OBJID
, obj
->id
.id
);
148 blob_put_int32(&b
, UBUS_ATTR_OBJTYPE
, obj
->type
->id
.id
);
150 s
= blob_nest_start(&b
, UBUS_ATTR_SIGNATURE
);
151 list_for_each_entry(m
, &obj
->type
->methods
, list
)
152 blob_put(&b
, blob_id(m
->data
), blob_data(m
->data
), blob_len(m
->data
));
153 blob_nest_end(&b
, s
);
155 ub
= ubus_reply_from_blob(ub
, true);
159 ubus_msg_send(cl
, ub
, true);
162 static int ubusd_handle_lookup(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
164 struct ubus_object
*obj
;
169 if (!attr
[UBUS_ATTR_OBJPATH
]) {
170 avl_for_each_element(&path
, obj
, path
)
171 ubusd_send_obj(cl
, ub
, obj
);
175 objpath
= blob_data(attr
[UBUS_ATTR_OBJPATH
]);
176 len
= strlen(objpath
);
177 if (objpath
[len
- 1] != '*') {
178 obj
= avl_find_element(&path
, objpath
, obj
, path
);
180 return UBUS_STATUS_NOT_FOUND
;
182 ubusd_send_obj(cl
, ub
, obj
);
188 obj
= avl_find_ge_element(&path
, objpath
, obj
, path
);
190 return UBUS_STATUS_NOT_FOUND
;
192 while (!strncmp(objpath
, obj
->path
.key
, len
)) {
194 ubusd_send_obj(cl
, ub
, obj
);
195 if (obj
== avl_last_element(&path
, obj
, path
))
197 obj
= avl_next_element(obj
, path
);
201 return UBUS_STATUS_NOT_FOUND
;
206 static int ubusd_handle_invoke(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
208 struct ubus_msg_buf
*ub_new
;
209 struct ubus_object
*obj
= NULL
;
213 if (!attr
[UBUS_ATTR_METHOD
] || !attr
[UBUS_ATTR_OBJID
])
214 return UBUS_STATUS_INVALID_ARGUMENT
;
216 id
= ubus_find_id(&objects
, blob_get_u32(attr
[UBUS_ATTR_OBJID
]));
218 return UBUS_STATUS_NOT_FOUND
;
220 obj
= container_of(id
, struct ubus_object
, id
);
222 method
= blob_data(attr
[UBUS_ATTR_METHOD
]);
225 return obj
->recv_msg(cl
, method
, attr
[UBUS_ATTR_DATA
]);
227 blob_buf_init(&b
, 0);
228 blob_put_int32(&b
, UBUS_ATTR_OBJID
, obj
->id
.id
);
229 blob_put_string(&b
, UBUS_ATTR_METHOD
, method
);
230 if (attr
[UBUS_ATTR_DATA
])
231 blob_put(&b
, UBUS_ATTR_DATA
, blob_data(attr
[UBUS_ATTR_DATA
]),
232 blob_len(attr
[UBUS_ATTR_DATA
]));
234 ub_new
= ubus_reply_from_blob(ub
, true);
239 return UBUS_STATUS_NO_DATA
;
241 ub
->hdr
.type
= UBUS_MSG_INVOKE
;
242 ub
->hdr
.peer
= cl
->id
.id
;
243 ubus_msg_send(obj
->client
, ub
, true);
248 static struct ubus_client
*ubusd_get_client_by_id(uint32_t id
)
250 struct ubus_id
*clid
;
252 clid
= ubus_find_id(&clients
, id
);
256 return container_of(clid
, struct ubus_client
, id
);
259 static int ubusd_handle_response(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
261 struct ubus_object
*obj
;
263 if (!attr
[UBUS_ATTR_OBJID
] ||
264 (ub
->hdr
.type
== UBUS_MSG_STATUS
&& !attr
[UBUS_ATTR_STATUS
]) ||
265 (ub
->hdr
.type
== UBUS_MSG_DATA
&& !attr
[UBUS_ATTR_DATA
]))
268 obj
= ubusd_find_object(blob_get_u32(attr
[UBUS_ATTR_OBJID
]));
272 if (cl
!= obj
->client
)
275 cl
= ubusd_get_client_by_id(ub
->hdr
.peer
);
279 ub
->hdr
.peer
= blob_get_u32(attr
[UBUS_ATTR_OBJID
]);
280 ubus_msg_send(cl
, ub
, true);
288 static int ubusd_handle_add_watch(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
290 struct ubus_object
*obj
, *target
;
292 if (!attr
[UBUS_ATTR_OBJID
] || !attr
[UBUS_ATTR_TARGET
] ||
293 !attr
[UBUS_ATTR_METHOD
]) {
294 return UBUS_STATUS_INVALID_ARGUMENT
;
297 obj
= ubusd_find_object(blob_get_u32(attr
[UBUS_ATTR_OBJID
]));
299 return UBUS_STATUS_NOT_FOUND
;
301 if (cl
!= obj
->client
)
302 return UBUS_STATUS_INVALID_ARGUMENT
;
304 target
= ubusd_find_object(blob_get_u32(attr
[UBUS_ATTR_TARGET
]));
306 return UBUS_STATUS_NOT_FOUND
;
308 if (cl
== target
->client
)
309 return UBUS_STATUS_INVALID_ARGUMENT
;
311 ubus_subscribe(obj
, target
, blob_data(attr
[UBUS_ATTR_METHOD
]));
315 static int ubusd_handle_remove_watch(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, struct blob_attr
**attr
)
317 struct ubus_object
*obj
;
318 struct ubus_subscription
*s
;
321 if (!attr
[UBUS_ATTR_OBJID
] || !attr
[UBUS_ATTR_TARGET
])
322 return UBUS_STATUS_INVALID_ARGUMENT
;
324 obj
= ubusd_find_object(blob_get_u32(attr
[UBUS_ATTR_OBJID
]));
326 return UBUS_STATUS_NOT_FOUND
;
328 if (cl
!= obj
->client
)
329 return UBUS_STATUS_INVALID_ARGUMENT
;
331 id
= blob_get_u32(attr
[UBUS_ATTR_TARGET
]);
332 list_for_each_entry(s
, &obj
->target_list
, target_list
) {
333 if (s
->target
->id
.id
!= id
)
340 return UBUS_STATUS_NOT_FOUND
;
343 static const ubus_cmd_cb handlers
[__UBUS_MSG_LAST
] = {
344 [UBUS_MSG_PING
] = ubusd_send_pong
,
345 [UBUS_MSG_ADD_OBJECT
] = ubusd_handle_add_object
,
346 [UBUS_MSG_REMOVE_OBJECT
] = ubusd_handle_remove_object
,
347 [UBUS_MSG_LOOKUP
] = ubusd_handle_lookup
,
348 [UBUS_MSG_INVOKE
] = ubusd_handle_invoke
,
349 [UBUS_MSG_STATUS
] = ubusd_handle_response
,
350 [UBUS_MSG_DATA
] = ubusd_handle_response
,
351 [UBUS_MSG_SUBSCRIBE
] = ubusd_handle_add_watch
,
352 [UBUS_MSG_UNSUBSCRIBE
] = ubusd_handle_remove_watch
,
355 void ubusd_proto_receive_message(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
)
357 ubus_cmd_cb cb
= NULL
;
360 retmsg
->hdr
.seq
= ub
->hdr
.seq
;
361 retmsg
->hdr
.peer
= ub
->hdr
.peer
;
363 if (ub
->hdr
.type
< __UBUS_MSG_LAST
)
364 cb
= handlers
[ub
->hdr
.type
];
367 ret
= cb(cl
, ub
, ubus_parse_msg(ub
->data
));
369 ret
= UBUS_STATUS_INVALID_COMMAND
;
376 *retmsg_data
= htonl(ret
);
377 ubus_msg_send(cl
, retmsg
, false);
380 struct ubus_client
*ubusd_proto_new_client(int fd
, uloop_fd_handler cb
)
382 struct ubus_client
*cl
;
384 cl
= calloc(1, sizeof(*cl
));
388 INIT_LIST_HEAD(&cl
->objects
);
392 if (!ubus_alloc_id(&clients
, &cl
->id
, 0))
395 if (!ubusd_send_hello(cl
))
401 ubus_free_id(&clients
, &cl
->id
);
407 void ubusd_proto_free_client(struct ubus_client
*cl
)
409 struct ubus_object
*obj
;
411 while (!list_empty(&cl
->objects
)) {
412 obj
= list_first_entry(&cl
->objects
, struct ubus_object
, list
);
413 ubusd_free_object(obj
);
416 ubus_free_id(&clients
, &cl
->id
);
419 void ubus_notify_subscription(struct ubus_object
*obj
)
421 bool active
= !list_empty(&obj
->subscribers
);
422 struct ubus_msg_buf
*ub
;
424 blob_buf_init(&b
, 0);
425 blob_put_int32(&b
, UBUS_ATTR_OBJID
, obj
->id
.id
);
426 blob_put_int8(&b
, UBUS_ATTR_ACTIVE
, active
);
428 ub
= ubus_msg_from_blob(false);
429 ubus_msg_init(ub
, UBUS_MSG_NOTIFY
, ++obj
->invoke_seq
, 0);
430 ubus_msg_send(obj
->client
, ub
, true);
433 void ubus_notify_unsubscribe(struct ubus_subscription
*s
)
435 struct ubus_msg_buf
*ub
;
437 blob_buf_init(&b
, 0);
438 blob_put_int32(&b
, UBUS_ATTR_OBJID
, s
->subscriber
->id
.id
);
439 blob_put_int32(&b
, UBUS_ATTR_TARGET
, s
->target
->id
.id
);
441 ub
= ubus_msg_from_blob(false);
442 ubus_msg_init(ub
, UBUS_MSG_UNSUBSCRIBE
, ++s
->subscriber
->invoke_seq
, 0);
443 ubus_msg_send(s
->subscriber
->client
, ub
, true);
448 static void __init
ubusd_proto_init(void)
450 ubus_init_id_tree(&clients
);
452 blob_buf_init(&b
, 0);
453 blob_put_int32(&b
, UBUS_ATTR_STATUS
, 0);
455 retmsg
= ubus_msg_from_blob(false);
459 retmsg
->hdr
.type
= UBUS_MSG_STATUS
;
460 retmsg_data
= blob_data(blob_data(retmsg
->data
));