2 * Copyright (C) 2011-2012 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.
16 #include "libubus-internal.h"
19 ubus_process_unsubscribe(struct ubus_context
*ctx
, struct ubus_msghdr
*hdr
,
20 struct ubus_object
*obj
, struct blob_attr
**attrbuf
, int fd
)
22 struct ubus_subscriber
*s
;
24 if (!obj
|| !attrbuf
[UBUS_ATTR_TARGET
])
27 if (obj
->methods
!= &watch_method
)
30 s
= container_of(obj
, struct ubus_subscriber
, obj
);
32 s
->remove_cb(ctx
, s
, blob_get_u32(attrbuf
[UBUS_ATTR_TARGET
]));
39 ubus_process_notify(struct ubus_context
*ctx
, struct ubus_msghdr
*hdr
,
40 struct ubus_object
*obj
, struct blob_attr
**attrbuf
, int fd
)
42 if (!obj
|| !attrbuf
[UBUS_ATTR_ACTIVE
])
45 obj
->has_subscribers
= blob_get_u8(attrbuf
[UBUS_ATTR_ACTIVE
]);
46 if (obj
->subscribe_cb
)
47 obj
->subscribe_cb(ctx
, obj
);
53 ubus_process_invoke(struct ubus_context
*ctx
, struct ubus_msghdr
*hdr
,
54 struct ubus_object
*obj
, struct blob_attr
**attrbuf
, int fd
)
56 struct ubus_request_data req
= {
63 bool no_reply
= false;
66 ret
= UBUS_STATUS_NOT_FOUND
;
70 if (!attrbuf
[UBUS_ATTR_METHOD
]) {
71 ret
= UBUS_STATUS_INVALID_ARGUMENT
;
75 if (attrbuf
[UBUS_ATTR_NO_REPLY
])
76 no_reply
= blob_get_int8(attrbuf
[UBUS_ATTR_NO_REPLY
]);
81 if (attrbuf
[UBUS_ATTR_USER
] && attrbuf
[UBUS_ATTR_GROUP
]) {
82 req
.acl
.user
= blobmsg_get_string(attrbuf
[UBUS_ATTR_USER
]);
83 req
.acl
.group
= blobmsg_get_string(attrbuf
[UBUS_ATTR_GROUP
]);
84 req
.acl
.object
= obj
->name
;
86 for (method
= 0; method
< obj
->n_methods
; method
++)
87 if (!obj
->methods
[method
].name
||
88 !strcmp(obj
->methods
[method
].name
,
89 blob_data(attrbuf
[UBUS_ATTR_METHOD
])))
93 ret
= UBUS_STATUS_METHOD_NOT_FOUND
;
97 if (!attrbuf
[UBUS_ATTR_DATA
]) {
98 ret
= UBUS_STATUS_INVALID_ARGUMENT
;
102 ret
= obj
->methods
[method
].handler(ctx
, obj
, &req
,
103 blob_data(attrbuf
[UBUS_ATTR_METHOD
]),
104 attrbuf
[UBUS_ATTR_DATA
]);
107 if (req
.deferred
|| no_reply
)
111 ubus_complete_deferred_request(ctx
, &req
, ret
);
115 void __hidden
ubus_process_obj_msg(struct ubus_context
*ctx
, struct ubus_msghdr_buf
*buf
, int fd
)
117 void (*cb
)(struct ubus_context
*, struct ubus_msghdr
*,
118 struct ubus_object
*, struct blob_attr
**, int fd
);
119 struct ubus_msghdr
*hdr
= &buf
->hdr
;
120 struct blob_attr
**attrbuf
;
121 struct ubus_object
*obj
;
123 void *prev_data
= NULL
;
124 attrbuf
= ubus_parse_msg(buf
->data
, blob_raw_len(buf
->data
));
125 if (!attrbuf
[UBUS_ATTR_OBJID
])
128 objid
= blob_get_u32(attrbuf
[UBUS_ATTR_OBJID
]);
129 obj
= avl_find_element(&ctx
->objects
, &objid
, obj
, avl
);
132 case UBUS_MSG_INVOKE
:
133 cb
= ubus_process_invoke
;
135 case UBUS_MSG_UNSUBSCRIBE
:
136 cb
= ubus_process_unsubscribe
;
138 case UBUS_MSG_NOTIFY
:
139 cb
= ubus_process_notify
;
145 if (buf
== &ctx
->msgbuf
) {
146 prev_data
= buf
->data
;
150 cb(ctx
, hdr
, obj
, attrbuf
, fd
);
156 buf
->data
= prev_data
;
160 static void ubus_add_object_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
162 struct ubus_object
*obj
= req
->priv
;
163 struct blob_attr
**attrbuf
= ubus_parse_msg(msg
, blob_raw_len(msg
));
165 if (!attrbuf
[UBUS_ATTR_OBJID
])
168 obj
->id
= blob_get_u32(attrbuf
[UBUS_ATTR_OBJID
]);
170 if (attrbuf
[UBUS_ATTR_OBJTYPE
])
171 obj
->type
->id
= blob_get_u32(attrbuf
[UBUS_ATTR_OBJTYPE
]);
173 obj
->avl
.key
= &obj
->id
;
174 avl_insert(&req
->ctx
->objects
, &obj
->avl
);
177 static void ubus_push_method_data(const struct ubus_method
*m
)
182 mtbl
= blobmsg_open_table(&b
, m
->name
);
184 for (i
= 0; i
< m
->n_policy
; i
++) {
185 if (m
->mask
&& !(m
->mask
& (1 << i
)))
188 blobmsg_add_u32(&b
, m
->policy
[i
].name
, m
->policy
[i
].type
);
191 blobmsg_close_table(&b
, mtbl
);
194 static bool ubus_push_object_type(const struct ubus_object_type
*type
)
199 s
= blob_nest_start(&b
, UBUS_ATTR_SIGNATURE
);
201 for (i
= 0; i
< type
->n_methods
; i
++)
202 ubus_push_method_data(&type
->methods
[i
]);
204 blob_nest_end(&b
, s
);
209 int ubus_add_object(struct ubus_context
*ctx
, struct ubus_object
*obj
)
211 struct ubus_request req
;
214 blob_buf_init(&b
, 0);
216 if (obj
->name
&& obj
->type
) {
217 blob_put_string(&b
, UBUS_ATTR_OBJPATH
, obj
->name
);
220 blob_put_int32(&b
, UBUS_ATTR_OBJTYPE
, obj
->type
->id
);
221 else if (!ubus_push_object_type(obj
->type
))
222 return UBUS_STATUS_INVALID_ARGUMENT
;
225 if (ubus_start_request(ctx
, &req
, b
.head
, UBUS_MSG_ADD_OBJECT
, 0) < 0)
226 return UBUS_STATUS_INVALID_ARGUMENT
;
228 req
.raw_data_cb
= ubus_add_object_cb
;
230 ret
= ubus_complete_request(ctx
, &req
, 0);
235 return UBUS_STATUS_NO_DATA
;
240 static void ubus_remove_object_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
242 struct ubus_object
*obj
= req
->priv
;
243 struct blob_attr
**attrbuf
= ubus_parse_msg(msg
, blob_raw_len(msg
));
245 if (!attrbuf
[UBUS_ATTR_OBJID
])
248 avl_delete(&req
->ctx
->objects
, &obj
->avl
);
252 if (attrbuf
[UBUS_ATTR_OBJTYPE
] && obj
->type
)
256 int ubus_remove_object(struct ubus_context
*ctx
, struct ubus_object
*obj
)
258 struct ubus_request req
;
261 blob_buf_init(&b
, 0);
262 blob_put_int32(&b
, UBUS_ATTR_OBJID
, obj
->id
);
264 if (ubus_start_request(ctx
, &req
, b
.head
, UBUS_MSG_REMOVE_OBJECT
, 0) < 0)
265 return UBUS_STATUS_INVALID_ARGUMENT
;
267 req
.raw_data_cb
= ubus_remove_object_cb
;
269 ret
= ubus_complete_request(ctx
, &req
, 0);
274 return UBUS_STATUS_NO_DATA
;