1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2010-2011 EIA Electronics, |
3 | // Kurt Van Dijck <kurt.van.dijck@eia.be> |
4 | // Copyright (c) 2017-2019 Pengutronix, |
5 | // Marc Kleine-Budde <kernel@pengutronix.de> |
6 | // Copyright (c) 2017-2019 Pengutronix, |
7 | // Oleksij Rempel <kernel@pengutronix.de> |
8 | |
9 | /* bus for j1939 remote devices |
10 | * Since rtnetlink, no real bus is used. |
11 | */ |
12 | |
13 | #include <net/sock.h> |
14 | |
15 | #include "j1939-priv.h" |
16 | |
17 | static void __j1939_ecu_release(struct kref *kref) |
18 | { |
19 | struct j1939_ecu *ecu = container_of(kref, struct j1939_ecu, kref); |
20 | struct j1939_priv *priv = ecu->priv; |
21 | |
22 | list_del(entry: &ecu->list); |
23 | kfree(objp: ecu); |
24 | j1939_priv_put(priv); |
25 | } |
26 | |
27 | void j1939_ecu_put(struct j1939_ecu *ecu) |
28 | { |
29 | kref_put(kref: &ecu->kref, release: __j1939_ecu_release); |
30 | } |
31 | |
32 | static void j1939_ecu_get(struct j1939_ecu *ecu) |
33 | { |
34 | kref_get(kref: &ecu->kref); |
35 | } |
36 | |
37 | static bool j1939_ecu_is_mapped_locked(struct j1939_ecu *ecu) |
38 | { |
39 | struct j1939_priv *priv = ecu->priv; |
40 | |
41 | lockdep_assert_held(&priv->lock); |
42 | |
43 | return j1939_ecu_find_by_addr_locked(priv, addr: ecu->addr) == ecu; |
44 | } |
45 | |
46 | /* ECU device interface */ |
47 | /* map ECU to a bus address space */ |
48 | static void j1939_ecu_map_locked(struct j1939_ecu *ecu) |
49 | { |
50 | struct j1939_priv *priv = ecu->priv; |
51 | struct j1939_addr_ent *ent; |
52 | |
53 | lockdep_assert_held(&priv->lock); |
54 | |
55 | if (!j1939_address_is_unicast(addr: ecu->addr)) |
56 | return; |
57 | |
58 | ent = &priv->ents[ecu->addr]; |
59 | |
60 | if (ent->ecu) { |
61 | netdev_warn(dev: priv->ndev, format: "Trying to map already mapped ECU, addr: 0x%02x, name: 0x%016llx. Skip it.\n" , |
62 | ecu->addr, ecu->name); |
63 | return; |
64 | } |
65 | |
66 | j1939_ecu_get(ecu); |
67 | ent->ecu = ecu; |
68 | ent->nusers += ecu->nusers; |
69 | } |
70 | |
71 | /* unmap ECU from a bus address space */ |
72 | void j1939_ecu_unmap_locked(struct j1939_ecu *ecu) |
73 | { |
74 | struct j1939_priv *priv = ecu->priv; |
75 | struct j1939_addr_ent *ent; |
76 | |
77 | lockdep_assert_held(&priv->lock); |
78 | |
79 | if (!j1939_address_is_unicast(addr: ecu->addr)) |
80 | return; |
81 | |
82 | if (!j1939_ecu_is_mapped_locked(ecu)) |
83 | return; |
84 | |
85 | ent = &priv->ents[ecu->addr]; |
86 | ent->ecu = NULL; |
87 | ent->nusers -= ecu->nusers; |
88 | j1939_ecu_put(ecu); |
89 | } |
90 | |
91 | void j1939_ecu_unmap(struct j1939_ecu *ecu) |
92 | { |
93 | write_lock_bh(&ecu->priv->lock); |
94 | j1939_ecu_unmap_locked(ecu); |
95 | write_unlock_bh(&ecu->priv->lock); |
96 | } |
97 | |
98 | void j1939_ecu_unmap_all(struct j1939_priv *priv) |
99 | { |
100 | int i; |
101 | |
102 | write_lock_bh(&priv->lock); |
103 | for (i = 0; i < ARRAY_SIZE(priv->ents); i++) |
104 | if (priv->ents[i].ecu) |
105 | j1939_ecu_unmap_locked(ecu: priv->ents[i].ecu); |
106 | write_unlock_bh(&priv->lock); |
107 | } |
108 | |
109 | void j1939_ecu_timer_start(struct j1939_ecu *ecu) |
110 | { |
111 | /* The ECU is held here and released in the |
112 | * j1939_ecu_timer_handler() or j1939_ecu_timer_cancel(). |
113 | */ |
114 | j1939_ecu_get(ecu); |
115 | |
116 | /* Schedule timer in 250 msec to commit address change. */ |
117 | hrtimer_start(timer: &ecu->ac_timer, tim: ms_to_ktime(ms: 250), |
118 | mode: HRTIMER_MODE_REL_SOFT); |
119 | } |
120 | |
121 | void j1939_ecu_timer_cancel(struct j1939_ecu *ecu) |
122 | { |
123 | if (hrtimer_cancel(timer: &ecu->ac_timer)) |
124 | j1939_ecu_put(ecu); |
125 | } |
126 | |
127 | static enum hrtimer_restart j1939_ecu_timer_handler(struct hrtimer *hrtimer) |
128 | { |
129 | struct j1939_ecu *ecu = |
130 | container_of(hrtimer, struct j1939_ecu, ac_timer); |
131 | struct j1939_priv *priv = ecu->priv; |
132 | |
133 | write_lock_bh(&priv->lock); |
134 | /* TODO: can we test if ecu->addr is unicast before starting |
135 | * the timer? |
136 | */ |
137 | j1939_ecu_map_locked(ecu); |
138 | |
139 | /* The corresponding j1939_ecu_get() is in |
140 | * j1939_ecu_timer_start(). |
141 | */ |
142 | j1939_ecu_put(ecu); |
143 | write_unlock_bh(&priv->lock); |
144 | |
145 | return HRTIMER_NORESTART; |
146 | } |
147 | |
148 | struct j1939_ecu *j1939_ecu_create_locked(struct j1939_priv *priv, name_t name) |
149 | { |
150 | struct j1939_ecu *ecu; |
151 | |
152 | lockdep_assert_held(&priv->lock); |
153 | |
154 | ecu = kzalloc(size: sizeof(*ecu), flags: gfp_any()); |
155 | if (!ecu) |
156 | return ERR_PTR(error: -ENOMEM); |
157 | kref_init(kref: &ecu->kref); |
158 | ecu->addr = J1939_IDLE_ADDR; |
159 | ecu->name = name; |
160 | |
161 | hrtimer_init(timer: &ecu->ac_timer, CLOCK_MONOTONIC, mode: HRTIMER_MODE_REL_SOFT); |
162 | ecu->ac_timer.function = j1939_ecu_timer_handler; |
163 | INIT_LIST_HEAD(list: &ecu->list); |
164 | |
165 | j1939_priv_get(priv); |
166 | ecu->priv = priv; |
167 | list_add_tail(new: &ecu->list, head: &priv->ecus); |
168 | |
169 | return ecu; |
170 | } |
171 | |
172 | struct j1939_ecu *j1939_ecu_find_by_addr_locked(struct j1939_priv *priv, |
173 | u8 addr) |
174 | { |
175 | lockdep_assert_held(&priv->lock); |
176 | |
177 | return priv->ents[addr].ecu; |
178 | } |
179 | |
180 | struct j1939_ecu *j1939_ecu_get_by_addr_locked(struct j1939_priv *priv, u8 addr) |
181 | { |
182 | struct j1939_ecu *ecu; |
183 | |
184 | lockdep_assert_held(&priv->lock); |
185 | |
186 | if (!j1939_address_is_unicast(addr)) |
187 | return NULL; |
188 | |
189 | ecu = j1939_ecu_find_by_addr_locked(priv, addr); |
190 | if (ecu) |
191 | j1939_ecu_get(ecu); |
192 | |
193 | return ecu; |
194 | } |
195 | |
196 | struct j1939_ecu *j1939_ecu_get_by_addr(struct j1939_priv *priv, u8 addr) |
197 | { |
198 | struct j1939_ecu *ecu; |
199 | |
200 | read_lock_bh(&priv->lock); |
201 | ecu = j1939_ecu_get_by_addr_locked(priv, addr); |
202 | read_unlock_bh(&priv->lock); |
203 | |
204 | return ecu; |
205 | } |
206 | |
207 | /* get pointer to ecu without increasing ref counter */ |
208 | static struct j1939_ecu *j1939_ecu_find_by_name_locked(struct j1939_priv *priv, |
209 | name_t name) |
210 | { |
211 | struct j1939_ecu *ecu; |
212 | |
213 | lockdep_assert_held(&priv->lock); |
214 | |
215 | list_for_each_entry(ecu, &priv->ecus, list) { |
216 | if (ecu->name == name) |
217 | return ecu; |
218 | } |
219 | |
220 | return NULL; |
221 | } |
222 | |
223 | struct j1939_ecu *j1939_ecu_get_by_name_locked(struct j1939_priv *priv, |
224 | name_t name) |
225 | { |
226 | struct j1939_ecu *ecu; |
227 | |
228 | lockdep_assert_held(&priv->lock); |
229 | |
230 | if (!name) |
231 | return NULL; |
232 | |
233 | ecu = j1939_ecu_find_by_name_locked(priv, name); |
234 | if (ecu) |
235 | j1939_ecu_get(ecu); |
236 | |
237 | return ecu; |
238 | } |
239 | |
240 | struct j1939_ecu *j1939_ecu_get_by_name(struct j1939_priv *priv, name_t name) |
241 | { |
242 | struct j1939_ecu *ecu; |
243 | |
244 | read_lock_bh(&priv->lock); |
245 | ecu = j1939_ecu_get_by_name_locked(priv, name); |
246 | read_unlock_bh(&priv->lock); |
247 | |
248 | return ecu; |
249 | } |
250 | |
251 | u8 j1939_name_to_addr(struct j1939_priv *priv, name_t name) |
252 | { |
253 | struct j1939_ecu *ecu; |
254 | int addr = J1939_IDLE_ADDR; |
255 | |
256 | if (!name) |
257 | return J1939_NO_ADDR; |
258 | |
259 | read_lock_bh(&priv->lock); |
260 | ecu = j1939_ecu_find_by_name_locked(priv, name); |
261 | if (ecu && j1939_ecu_is_mapped_locked(ecu)) |
262 | /* ecu's SA is registered */ |
263 | addr = ecu->addr; |
264 | |
265 | read_unlock_bh(&priv->lock); |
266 | |
267 | return addr; |
268 | } |
269 | |
270 | /* TX addr/name accounting |
271 | * Transport protocol needs to know if a SA is local or not |
272 | * These functions originate from userspace manipulating sockets, |
273 | * so locking is straigforward |
274 | */ |
275 | |
276 | int j1939_local_ecu_get(struct j1939_priv *priv, name_t name, u8 sa) |
277 | { |
278 | struct j1939_ecu *ecu; |
279 | int err = 0; |
280 | |
281 | write_lock_bh(&priv->lock); |
282 | |
283 | if (j1939_address_is_unicast(addr: sa)) |
284 | priv->ents[sa].nusers++; |
285 | |
286 | if (!name) |
287 | goto done; |
288 | |
289 | ecu = j1939_ecu_get_by_name_locked(priv, name); |
290 | if (!ecu) |
291 | ecu = j1939_ecu_create_locked(priv, name); |
292 | err = PTR_ERR_OR_ZERO(ptr: ecu); |
293 | if (err) |
294 | goto done; |
295 | |
296 | ecu->nusers++; |
297 | /* TODO: do we care if ecu->addr != sa? */ |
298 | if (j1939_ecu_is_mapped_locked(ecu)) |
299 | /* ecu's sa is active already */ |
300 | priv->ents[ecu->addr].nusers++; |
301 | |
302 | done: |
303 | write_unlock_bh(&priv->lock); |
304 | |
305 | return err; |
306 | } |
307 | |
308 | void j1939_local_ecu_put(struct j1939_priv *priv, name_t name, u8 sa) |
309 | { |
310 | struct j1939_ecu *ecu; |
311 | |
312 | write_lock_bh(&priv->lock); |
313 | |
314 | if (j1939_address_is_unicast(addr: sa)) |
315 | priv->ents[sa].nusers--; |
316 | |
317 | if (!name) |
318 | goto done; |
319 | |
320 | ecu = j1939_ecu_find_by_name_locked(priv, name); |
321 | if (WARN_ON_ONCE(!ecu)) |
322 | goto done; |
323 | |
324 | ecu->nusers--; |
325 | /* TODO: do we care if ecu->addr != sa? */ |
326 | if (j1939_ecu_is_mapped_locked(ecu)) |
327 | /* ecu's sa is active already */ |
328 | priv->ents[ecu->addr].nusers--; |
329 | j1939_ecu_put(ecu); |
330 | |
331 | done: |
332 | write_unlock_bh(&priv->lock); |
333 | } |
334 | |