Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 :
5 : #include "sd-netlink.h"
6 :
7 : #include "alloc-util.h"
8 : #include "netlink-internal.h"
9 : #include "netlink-slot.h"
10 : #include "string-util.h"
11 :
12 30 : int netlink_slot_allocate(
13 : sd_netlink *nl,
14 : bool floating,
15 : NetlinkSlotType type,
16 : size_t extra,
17 : void *userdata,
18 : const char *description,
19 : sd_netlink_slot **ret) {
20 :
21 30 : _cleanup_free_ sd_netlink_slot *slot = NULL;
22 :
23 30 : assert(nl);
24 30 : assert(ret);
25 :
26 30 : slot = malloc0(offsetof(sd_netlink_slot, reply_callback) + extra);
27 30 : if (!slot)
28 0 : return -ENOMEM;
29 :
30 30 : slot->n_ref = 1;
31 30 : slot->netlink = nl;
32 30 : slot->userdata = userdata;
33 30 : slot->type = type;
34 30 : slot->floating = floating;
35 :
36 30 : if (description) {
37 20 : slot->description = strdup(description);
38 20 : if (!slot->description)
39 0 : return -ENOMEM;
40 : }
41 :
42 30 : if (!floating)
43 5 : sd_netlink_ref(nl);
44 :
45 30 : LIST_PREPEND(slots, nl->slots, slot);
46 :
47 30 : *ret = TAKE_PTR(slot);
48 :
49 30 : return 0;
50 : }
51 :
52 56 : void netlink_slot_disconnect(sd_netlink_slot *slot, bool unref) {
53 : sd_netlink *nl;
54 :
55 56 : assert(slot);
56 :
57 56 : nl = slot->netlink;
58 56 : if (!nl)
59 26 : return;
60 :
61 30 : switch (slot->type) {
62 :
63 17 : case NETLINK_REPLY_CALLBACK:
64 17 : (void) hashmap_remove(nl->reply_callbacks, &slot->reply_callback.serial);
65 :
66 17 : if (slot->reply_callback.timeout != 0)
67 8 : prioq_remove(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
68 :
69 17 : break;
70 13 : case NETLINK_MATCH_CALLBACK:
71 13 : LIST_REMOVE(match_callbacks, nl->match_callbacks, &slot->match_callback);
72 :
73 13 : switch (slot->match_callback.type) {
74 5 : case RTM_NEWLINK:
75 : case RTM_DELLINK:
76 5 : (void) socket_broadcast_group_unref(nl, RTNLGRP_LINK);
77 :
78 5 : break;
79 2 : case RTM_NEWADDR:
80 : case RTM_DELADDR:
81 2 : (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_IFADDR);
82 2 : (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_IFADDR);
83 :
84 2 : break;
85 2 : case RTM_NEWROUTE:
86 : case RTM_DELROUTE:
87 2 : (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV4_ROUTE);
88 2 : (void) socket_broadcast_group_unref(nl, RTNLGRP_IPV6_ROUTE);
89 :
90 2 : break;
91 : }
92 :
93 13 : break;
94 0 : default:
95 0 : assert_not_reached("Wut? Unknown slot type?");
96 : }
97 :
98 30 : slot->type = _NETLINK_SLOT_INVALID;
99 30 : slot->netlink = NULL;
100 30 : LIST_REMOVE(slots, nl->slots, slot);
101 :
102 30 : if (!slot->floating)
103 4 : sd_netlink_unref(nl);
104 26 : else if (unref)
105 26 : sd_netlink_slot_unref(slot);
106 : }
107 :
108 30 : static sd_netlink_slot* netlink_slot_free(sd_netlink_slot *slot) {
109 30 : assert(slot);
110 :
111 30 : netlink_slot_disconnect(slot, false);
112 :
113 30 : if (slot->destroy_callback)
114 11 : slot->destroy_callback(slot->userdata);
115 :
116 30 : free(slot->description);
117 30 : return mfree(slot);
118 : }
119 :
120 32 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_netlink_slot, sd_netlink_slot, netlink_slot_free);
121 :
122 2 : sd_netlink *sd_netlink_slot_get_netlink(sd_netlink_slot *slot) {
123 2 : assert_return(slot, NULL);
124 :
125 2 : return slot->netlink;
126 : }
127 :
128 3 : void *sd_netlink_slot_get_userdata(sd_netlink_slot *slot) {
129 3 : assert_return(slot, NULL);
130 :
131 3 : return slot->userdata;
132 : }
133 :
134 1 : void *sd_netlink_slot_set_userdata(sd_netlink_slot *slot, void *userdata) {
135 : void *ret;
136 :
137 1 : assert_return(slot, NULL);
138 :
139 1 : ret = slot->userdata;
140 1 : slot->userdata = userdata;
141 :
142 1 : return ret;
143 : }
144 :
145 3 : int sd_netlink_slot_get_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t *callback) {
146 3 : assert_return(slot, -EINVAL);
147 :
148 3 : if (callback)
149 2 : *callback = slot->destroy_callback;
150 :
151 3 : return !!slot->destroy_callback;
152 : }
153 :
154 1 : int sd_netlink_slot_set_destroy_callback(sd_netlink_slot *slot, sd_netlink_destroy_t callback) {
155 1 : assert_return(slot, -EINVAL);
156 :
157 1 : slot->destroy_callback = callback;
158 1 : return 0;
159 : }
160 :
161 3 : int sd_netlink_slot_get_floating(sd_netlink_slot *slot) {
162 3 : assert_return(slot, -EINVAL);
163 :
164 3 : return slot->floating;
165 : }
166 :
167 1 : int sd_netlink_slot_set_floating(sd_netlink_slot *slot, int b) {
168 1 : assert_return(slot, -EINVAL);
169 :
170 1 : if (slot->floating == !!b)
171 0 : return 0;
172 :
173 1 : if (!slot->netlink) /* Already disconnected */
174 0 : return -ESTALE;
175 :
176 1 : slot->floating = b;
177 :
178 1 : if (b) {
179 1 : sd_netlink_slot_ref(slot);
180 1 : sd_netlink_unref(slot->netlink);
181 : } else {
182 0 : sd_netlink_ref(slot->netlink);
183 0 : sd_netlink_slot_unref(slot);
184 : }
185 :
186 1 : return 1;
187 : }
188 :
189 3 : int sd_netlink_slot_get_description(sd_netlink_slot *slot, const char **description) {
190 3 : assert_return(slot, -EINVAL);
191 :
192 3 : if (description)
193 2 : *description = slot->description;
194 :
195 3 : return !!slot->description;
196 : }
197 :
198 1 : int sd_netlink_slot_set_description(sd_netlink_slot *slot, const char *description) {
199 1 : assert_return(slot, -EINVAL);
200 :
201 1 : return free_and_strdup(&slot->description, description);
202 : }
|