1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
#include "udebug.h"
static struct blob_attr *
find_attr(struct blob_attr *attr, const char *name, enum blobmsg_type type)
{
struct blobmsg_policy policy = { name, type };
struct blob_attr *ret;
if (!attr)
return NULL;
blobmsg_parse_attr(&policy, 1, &ret, attr);
return ret;
}
static void
udebug_ubus_msg_cb(struct udebug_ubus *ctx, struct blob_attr *data)
{
struct blob_attr *en_attr;
bool enabled;
data = find_attr(data, "service", BLOBMSG_TYPE_TABLE);
data = find_attr(data, ctx->service, BLOBMSG_TYPE_TABLE);
if (!data)
return;
en_attr = find_attr(data, "enabled", BLOBMSG_TYPE_STRING);
enabled = en_attr && !!atoi(blobmsg_get_string(en_attr));
ctx->cb(ctx, data, enabled);
}
static int
udebug_ubus_notify_cb(struct ubus_context *ubus, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct udebug_ubus *ctx = container_of(obj, struct udebug_ubus, sub.obj);
if (!strcmp(method, "config"))
udebug_ubus_msg_cb(ctx, msg);
return 0;
}
static void
udebug_ubus_req_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
udebug_ubus_msg_cb(req->priv, msg);
}
static bool
udebug_ubus_new_obj_cb(struct ubus_context *ubus, struct ubus_subscriber *sub,
const char *path)
{
struct udebug_ubus *ctx = container_of(sub, struct udebug_ubus, sub);
if (strcmp(path, "udebug") != 0)
return false;
uloop_timeout_set(&ctx->t, 1);
return true;
}
static void udebug_ubus_get_config(struct uloop_timeout *t)
{
struct udebug_ubus *ctx = container_of(t, struct udebug_ubus, t);
uint32_t id;
if (ubus_lookup_id(ctx->ubus, "udebug", &id))
return;
ubus_invoke(ctx->ubus, id, "get_config", NULL, udebug_ubus_req_cb, ctx, 1000);
}
void udebug_ubus_ring_init(struct udebug *ud, struct udebug_ubus_ring *ring)
{
if (!ring->size)
ring->size = ring->default_size;
if (!ring->entries)
ring->entries = ring->default_entries;
udebug_buf_init(ring->buf, ring->entries, ring->size);
udebug_buf_add(ud, ring->buf, ring->meta);
}
void udebug_ubus_apply_config(struct udebug *ud, struct udebug_ubus_ring *rings, int n,
struct blob_attr *data, bool enabled)
{
enum {
CFG_ATTR_ENABLE,
CFG_ATTR_SIZE,
CFG_ATTR_ENTRIES,
__CFG_ATTR_MAX,
};
static struct blobmsg_policy policy[] = {
[CFG_ATTR_ENABLE] = { NULL, BLOBMSG_TYPE_STRING },
[CFG_ATTR_SIZE] = { NULL, BLOBMSG_TYPE_STRING },
[CFG_ATTR_ENTRIES] = { NULL, BLOBMSG_TYPE_STRING },
};
for (size_t i = 0; i < n; i++) {
struct blob_attr *tb[__CFG_ATTR_MAX], *cur;
struct udebug_buf *buf = rings[i].buf;
const char *name = rings[i].meta->name;
int name_len = strlen(name);
unsigned int size, entries;
bool cur_enabled = enabled;
char *str;
policy[CFG_ATTR_ENABLE].name = name;
#define SIZE_FMT "%s_size"
str = alloca(sizeof(SIZE_FMT) + name_len);
sprintf(str, SIZE_FMT, name);
policy[CFG_ATTR_SIZE].name = str;
#define ENTRIES_FMT "%s_entries"
str = alloca(sizeof(ENTRIES_FMT) + name_len);
sprintf(str, ENTRIES_FMT, name);
policy[CFG_ATTR_ENTRIES].name = str;
blobmsg_parse_attr(policy, __CFG_ATTR_MAX, tb, data);
if (enabled && (cur = tb[CFG_ATTR_ENABLE]) != NULL)
cur_enabled = !!atoi(blobmsg_get_string(cur));
if ((cur = tb[CFG_ATTR_SIZE]) != NULL)
size = atoi(blobmsg_get_string(cur));
else
size = rings[i].default_size;
if ((cur = tb[CFG_ATTR_ENTRIES]) != NULL)
entries = atoi(blobmsg_get_string(cur));
else
entries = rings[i].default_entries;
if (udebug_buf_valid(buf) == cur_enabled &&
size == rings[i].size &&
entries == rings[i].entries)
continue;
if (udebug_buf_valid(buf))
udebug_buf_free(buf);
rings[i].size = size;
rings[i].entries = entries;
if (!cur_enabled)
continue;
udebug_ubus_ring_init(ud, &rings[i]);
}
}
void udebug_netlink_msg(struct udebug_buf *buf, uint16_t proto, const void *data, size_t len)
{
struct {
uint16_t pkttype;
uint16_t arphdr;
uint16_t _pad[5];
uint16_t proto;
} hdr = {
.arphdr = cpu_to_be16(824),
.proto = cpu_to_be16(proto),
};
if (!udebug_buf_valid(buf))
return;
udebug_entry_init(buf);
udebug_entry_append(buf, &hdr, sizeof(hdr));
udebug_entry_append(buf, data, len);
udebug_entry_add(buf);
}
void udebug_ubus_init(struct udebug_ubus *ctx, struct ubus_context *ubus,
const char *service, udebug_config_cb cb)
{
ctx->ubus = ubus;
ctx->service = service;
ctx->cb = cb;
ctx->sub.new_obj_cb = udebug_ubus_new_obj_cb;
ctx->sub.cb = udebug_ubus_notify_cb;
ubus_register_subscriber(ubus, &ctx->sub);
ctx->t.cb = udebug_ubus_get_config;
}
void udebug_ubus_free(struct udebug_ubus *ctx)
{
if (!ctx->ubus)
return;
uloop_timeout_cancel(&ctx->t);
ubus_unregister_subscriber(ctx->ubus, &ctx->sub);
}
|