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(&ecu->list); 23 kfree(ecu); 24 j1939_priv_put(priv); 25 } 26 27 void j1939_ecu_put(struct j1939_ecu *ecu) 28 { 29 kref_put(&ecu->kref, __j1939_ecu_release); 30 } 31 32 static void j1939_ecu_get(struct j1939_ecu *ecu) 33 { 34 kref_get(&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, 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(ecu->addr)) 56 return; 57 58 ent = &priv->ents[ecu->addr]; 59 60 if (ent->ecu) { 61 netdev_warn(priv->ndev, "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(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(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(&ecu->ac_timer, ms_to_ktime(250), 118 HRTIMER_MODE_REL_SOFT); 119 } 120 121 void j1939_ecu_timer_cancel(struct j1939_ecu *ecu) 122 { 123 if (hrtimer_cancel(&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(sizeof(*ecu), gfp_any()); 155 if (!ecu) 156 return ERR_PTR(-ENOMEM); 157 kref_init(&ecu->kref); 158 ecu->addr = J1939_IDLE_ADDR; 159 ecu->name = name; 160 161 hrtimer_init(&ecu->ac_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); 162 ecu->ac_timer.function = j1939_ecu_timer_handler; 163 INIT_LIST_HEAD(&ecu->list); 164 165 j1939_priv_get(priv); 166 ecu->priv = priv; 167 list_add_tail(&ecu->list, &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(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(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(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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.