19d71dd0cSThe j1939 authors // SPDX-License-Identifier: GPL-2.0
29d71dd0cSThe j1939 authors // Copyright (c) 2010-2011 EIA Electronics,
39d71dd0cSThe j1939 authors // Kurt Van Dijck <kurt.van.dijck@eia.be>
49d71dd0cSThe j1939 authors // Copyright (c) 2017-2019 Pengutronix,
59d71dd0cSThe j1939 authors // Marc Kleine-Budde <kernel@pengutronix.de>
69d71dd0cSThe j1939 authors // Copyright (c) 2017-2019 Pengutronix,
79d71dd0cSThe j1939 authors // Oleksij Rempel <kernel@pengutronix.de>
89d71dd0cSThe j1939 authors
99d71dd0cSThe j1939 authors /* bus for j1939 remote devices
109d71dd0cSThe j1939 authors * Since rtnetlink, no real bus is used.
119d71dd0cSThe j1939 authors */
129d71dd0cSThe j1939 authors
139d71dd0cSThe j1939 authors #include <net/sock.h>
149d71dd0cSThe j1939 authors
159d71dd0cSThe j1939 authors #include "j1939-priv.h"
169d71dd0cSThe j1939 authors
__j1939_ecu_release(struct kref * kref)179d71dd0cSThe j1939 authors static void __j1939_ecu_release(struct kref *kref)
189d71dd0cSThe j1939 authors {
199d71dd0cSThe j1939 authors struct j1939_ecu *ecu = container_of(kref, struct j1939_ecu, kref);
209d71dd0cSThe j1939 authors struct j1939_priv *priv = ecu->priv;
219d71dd0cSThe j1939 authors
229d71dd0cSThe j1939 authors list_del(&ecu->list);
239d71dd0cSThe j1939 authors kfree(ecu);
249d71dd0cSThe j1939 authors j1939_priv_put(priv);
259d71dd0cSThe j1939 authors }
269d71dd0cSThe j1939 authors
j1939_ecu_put(struct j1939_ecu * ecu)279d71dd0cSThe j1939 authors void j1939_ecu_put(struct j1939_ecu *ecu)
289d71dd0cSThe j1939 authors {
299d71dd0cSThe j1939 authors kref_put(&ecu->kref, __j1939_ecu_release);
309d71dd0cSThe j1939 authors }
319d71dd0cSThe j1939 authors
j1939_ecu_get(struct j1939_ecu * ecu)329d71dd0cSThe j1939 authors static void j1939_ecu_get(struct j1939_ecu *ecu)
339d71dd0cSThe j1939 authors {
349d71dd0cSThe j1939 authors kref_get(&ecu->kref);
359d71dd0cSThe j1939 authors }
369d71dd0cSThe j1939 authors
j1939_ecu_is_mapped_locked(struct j1939_ecu * ecu)379d71dd0cSThe j1939 authors static bool j1939_ecu_is_mapped_locked(struct j1939_ecu *ecu)
389d71dd0cSThe j1939 authors {
399d71dd0cSThe j1939 authors struct j1939_priv *priv = ecu->priv;
409d71dd0cSThe j1939 authors
419d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
429d71dd0cSThe j1939 authors
439d71dd0cSThe j1939 authors return j1939_ecu_find_by_addr_locked(priv, ecu->addr) == ecu;
449d71dd0cSThe j1939 authors }
459d71dd0cSThe j1939 authors
469d71dd0cSThe j1939 authors /* ECU device interface */
479d71dd0cSThe j1939 authors /* map ECU to a bus address space */
j1939_ecu_map_locked(struct j1939_ecu * ecu)489d71dd0cSThe j1939 authors static void j1939_ecu_map_locked(struct j1939_ecu *ecu)
499d71dd0cSThe j1939 authors {
509d71dd0cSThe j1939 authors struct j1939_priv *priv = ecu->priv;
519d71dd0cSThe j1939 authors struct j1939_addr_ent *ent;
529d71dd0cSThe j1939 authors
539d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
549d71dd0cSThe j1939 authors
559d71dd0cSThe j1939 authors if (!j1939_address_is_unicast(ecu->addr))
569d71dd0cSThe j1939 authors return;
579d71dd0cSThe j1939 authors
589d71dd0cSThe j1939 authors ent = &priv->ents[ecu->addr];
599d71dd0cSThe j1939 authors
609d71dd0cSThe j1939 authors if (ent->ecu) {
619d71dd0cSThe j1939 authors netdev_warn(priv->ndev, "Trying to map already mapped ECU, addr: 0x%02x, name: 0x%016llx. Skip it.\n",
629d71dd0cSThe j1939 authors ecu->addr, ecu->name);
639d71dd0cSThe j1939 authors return;
649d71dd0cSThe j1939 authors }
659d71dd0cSThe j1939 authors
669d71dd0cSThe j1939 authors j1939_ecu_get(ecu);
679d71dd0cSThe j1939 authors ent->ecu = ecu;
689d71dd0cSThe j1939 authors ent->nusers += ecu->nusers;
699d71dd0cSThe j1939 authors }
709d71dd0cSThe j1939 authors
719d71dd0cSThe j1939 authors /* unmap ECU from a bus address space */
j1939_ecu_unmap_locked(struct j1939_ecu * ecu)729d71dd0cSThe j1939 authors void j1939_ecu_unmap_locked(struct j1939_ecu *ecu)
739d71dd0cSThe j1939 authors {
749d71dd0cSThe j1939 authors struct j1939_priv *priv = ecu->priv;
759d71dd0cSThe j1939 authors struct j1939_addr_ent *ent;
769d71dd0cSThe j1939 authors
779d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
789d71dd0cSThe j1939 authors
799d71dd0cSThe j1939 authors if (!j1939_address_is_unicast(ecu->addr))
809d71dd0cSThe j1939 authors return;
819d71dd0cSThe j1939 authors
829d71dd0cSThe j1939 authors if (!j1939_ecu_is_mapped_locked(ecu))
839d71dd0cSThe j1939 authors return;
849d71dd0cSThe j1939 authors
859d71dd0cSThe j1939 authors ent = &priv->ents[ecu->addr];
869d71dd0cSThe j1939 authors ent->ecu = NULL;
879d71dd0cSThe j1939 authors ent->nusers -= ecu->nusers;
889d71dd0cSThe j1939 authors j1939_ecu_put(ecu);
899d71dd0cSThe j1939 authors }
909d71dd0cSThe j1939 authors
j1939_ecu_unmap(struct j1939_ecu * ecu)919d71dd0cSThe j1939 authors void j1939_ecu_unmap(struct j1939_ecu *ecu)
929d71dd0cSThe j1939 authors {
939d71dd0cSThe j1939 authors write_lock_bh(&ecu->priv->lock);
949d71dd0cSThe j1939 authors j1939_ecu_unmap_locked(ecu);
959d71dd0cSThe j1939 authors write_unlock_bh(&ecu->priv->lock);
969d71dd0cSThe j1939 authors }
979d71dd0cSThe j1939 authors
j1939_ecu_unmap_all(struct j1939_priv * priv)989d71dd0cSThe j1939 authors void j1939_ecu_unmap_all(struct j1939_priv *priv)
999d71dd0cSThe j1939 authors {
1009d71dd0cSThe j1939 authors int i;
1019d71dd0cSThe j1939 authors
1029d71dd0cSThe j1939 authors write_lock_bh(&priv->lock);
1039d71dd0cSThe j1939 authors for (i = 0; i < ARRAY_SIZE(priv->ents); i++)
1049d71dd0cSThe j1939 authors if (priv->ents[i].ecu)
1059d71dd0cSThe j1939 authors j1939_ecu_unmap_locked(priv->ents[i].ecu);
1069d71dd0cSThe j1939 authors write_unlock_bh(&priv->lock);
1079d71dd0cSThe j1939 authors }
1089d71dd0cSThe j1939 authors
j1939_ecu_timer_start(struct j1939_ecu * ecu)1099d71dd0cSThe j1939 authors void j1939_ecu_timer_start(struct j1939_ecu *ecu)
1109d71dd0cSThe j1939 authors {
1119d71dd0cSThe j1939 authors /* The ECU is held here and released in the
1129d71dd0cSThe j1939 authors * j1939_ecu_timer_handler() or j1939_ecu_timer_cancel().
1139d71dd0cSThe j1939 authors */
1149d71dd0cSThe j1939 authors j1939_ecu_get(ecu);
1159d71dd0cSThe j1939 authors
1169d71dd0cSThe j1939 authors /* Schedule timer in 250 msec to commit address change. */
1179d71dd0cSThe j1939 authors hrtimer_start(&ecu->ac_timer, ms_to_ktime(250),
1189d71dd0cSThe j1939 authors HRTIMER_MODE_REL_SOFT);
1199d71dd0cSThe j1939 authors }
1209d71dd0cSThe j1939 authors
j1939_ecu_timer_cancel(struct j1939_ecu * ecu)1219d71dd0cSThe j1939 authors void j1939_ecu_timer_cancel(struct j1939_ecu *ecu)
1229d71dd0cSThe j1939 authors {
1239d71dd0cSThe j1939 authors if (hrtimer_cancel(&ecu->ac_timer))
1249d71dd0cSThe j1939 authors j1939_ecu_put(ecu);
1259d71dd0cSThe j1939 authors }
1269d71dd0cSThe j1939 authors
j1939_ecu_timer_handler(struct hrtimer * hrtimer)1279d71dd0cSThe j1939 authors static enum hrtimer_restart j1939_ecu_timer_handler(struct hrtimer *hrtimer)
1289d71dd0cSThe j1939 authors {
1299d71dd0cSThe j1939 authors struct j1939_ecu *ecu =
1309d71dd0cSThe j1939 authors container_of(hrtimer, struct j1939_ecu, ac_timer);
1319d71dd0cSThe j1939 authors struct j1939_priv *priv = ecu->priv;
1329d71dd0cSThe j1939 authors
1339d71dd0cSThe j1939 authors write_lock_bh(&priv->lock);
1349d71dd0cSThe j1939 authors /* TODO: can we test if ecu->addr is unicast before starting
1359d71dd0cSThe j1939 authors * the timer?
1369d71dd0cSThe j1939 authors */
1379d71dd0cSThe j1939 authors j1939_ecu_map_locked(ecu);
1389d71dd0cSThe j1939 authors
1399d71dd0cSThe j1939 authors /* The corresponding j1939_ecu_get() is in
1409d71dd0cSThe j1939 authors * j1939_ecu_timer_start().
1419d71dd0cSThe j1939 authors */
1429d71dd0cSThe j1939 authors j1939_ecu_put(ecu);
1439d71dd0cSThe j1939 authors write_unlock_bh(&priv->lock);
1449d71dd0cSThe j1939 authors
1459d71dd0cSThe j1939 authors return HRTIMER_NORESTART;
1469d71dd0cSThe j1939 authors }
1479d71dd0cSThe j1939 authors
j1939_ecu_create_locked(struct j1939_priv * priv,name_t name)1489d71dd0cSThe j1939 authors struct j1939_ecu *j1939_ecu_create_locked(struct j1939_priv *priv, name_t name)
1499d71dd0cSThe j1939 authors {
1509d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
1519d71dd0cSThe j1939 authors
1529d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
1539d71dd0cSThe j1939 authors
1549d71dd0cSThe j1939 authors ecu = kzalloc(sizeof(*ecu), gfp_any());
1559d71dd0cSThe j1939 authors if (!ecu)
1569d71dd0cSThe j1939 authors return ERR_PTR(-ENOMEM);
1579d71dd0cSThe j1939 authors kref_init(&ecu->kref);
1589d71dd0cSThe j1939 authors ecu->addr = J1939_IDLE_ADDR;
1599d71dd0cSThe j1939 authors ecu->name = name;
1609d71dd0cSThe j1939 authors
1619d71dd0cSThe j1939 authors hrtimer_init(&ecu->ac_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
1629d71dd0cSThe j1939 authors ecu->ac_timer.function = j1939_ecu_timer_handler;
1639d71dd0cSThe j1939 authors INIT_LIST_HEAD(&ecu->list);
1649d71dd0cSThe j1939 authors
1659d71dd0cSThe j1939 authors j1939_priv_get(priv);
1669d71dd0cSThe j1939 authors ecu->priv = priv;
1679d71dd0cSThe j1939 authors list_add_tail(&ecu->list, &priv->ecus);
1689d71dd0cSThe j1939 authors
1699d71dd0cSThe j1939 authors return ecu;
1709d71dd0cSThe j1939 authors }
1719d71dd0cSThe j1939 authors
j1939_ecu_find_by_addr_locked(struct j1939_priv * priv,u8 addr)1729d71dd0cSThe j1939 authors struct j1939_ecu *j1939_ecu_find_by_addr_locked(struct j1939_priv *priv,
1739d71dd0cSThe j1939 authors u8 addr)
1749d71dd0cSThe j1939 authors {
1759d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
1769d71dd0cSThe j1939 authors
1779d71dd0cSThe j1939 authors return priv->ents[addr].ecu;
1789d71dd0cSThe j1939 authors }
1799d71dd0cSThe j1939 authors
j1939_ecu_get_by_addr_locked(struct j1939_priv * priv,u8 addr)1809d71dd0cSThe j1939 authors struct j1939_ecu *j1939_ecu_get_by_addr_locked(struct j1939_priv *priv, u8 addr)
1819d71dd0cSThe j1939 authors {
1829d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
1839d71dd0cSThe j1939 authors
1849d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
1859d71dd0cSThe j1939 authors
1869d71dd0cSThe j1939 authors if (!j1939_address_is_unicast(addr))
1879d71dd0cSThe j1939 authors return NULL;
1889d71dd0cSThe j1939 authors
1899d71dd0cSThe j1939 authors ecu = j1939_ecu_find_by_addr_locked(priv, addr);
1909d71dd0cSThe j1939 authors if (ecu)
1919d71dd0cSThe j1939 authors j1939_ecu_get(ecu);
1929d71dd0cSThe j1939 authors
1939d71dd0cSThe j1939 authors return ecu;
1949d71dd0cSThe j1939 authors }
1959d71dd0cSThe j1939 authors
j1939_ecu_get_by_addr(struct j1939_priv * priv,u8 addr)1969d71dd0cSThe j1939 authors struct j1939_ecu *j1939_ecu_get_by_addr(struct j1939_priv *priv, u8 addr)
1979d71dd0cSThe j1939 authors {
1989d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
1999d71dd0cSThe j1939 authors
2009d71dd0cSThe j1939 authors read_lock_bh(&priv->lock);
2019d71dd0cSThe j1939 authors ecu = j1939_ecu_get_by_addr_locked(priv, addr);
2029d71dd0cSThe j1939 authors read_unlock_bh(&priv->lock);
2039d71dd0cSThe j1939 authors
2049d71dd0cSThe j1939 authors return ecu;
2059d71dd0cSThe j1939 authors }
2069d71dd0cSThe j1939 authors
2079d71dd0cSThe j1939 authors /* get pointer to ecu without increasing ref counter */
j1939_ecu_find_by_name_locked(struct j1939_priv * priv,name_t name)2089d71dd0cSThe j1939 authors static struct j1939_ecu *j1939_ecu_find_by_name_locked(struct j1939_priv *priv,
2099d71dd0cSThe j1939 authors name_t name)
2109d71dd0cSThe j1939 authors {
2119d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
2129d71dd0cSThe j1939 authors
2139d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
2149d71dd0cSThe j1939 authors
2159d71dd0cSThe j1939 authors list_for_each_entry(ecu, &priv->ecus, list) {
2169d71dd0cSThe j1939 authors if (ecu->name == name)
2179d71dd0cSThe j1939 authors return ecu;
2189d71dd0cSThe j1939 authors }
2199d71dd0cSThe j1939 authors
2209d71dd0cSThe j1939 authors return NULL;
2219d71dd0cSThe j1939 authors }
2229d71dd0cSThe j1939 authors
j1939_ecu_get_by_name_locked(struct j1939_priv * priv,name_t name)2239d71dd0cSThe j1939 authors struct j1939_ecu *j1939_ecu_get_by_name_locked(struct j1939_priv *priv,
2249d71dd0cSThe j1939 authors name_t name)
2259d71dd0cSThe j1939 authors {
2269d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
2279d71dd0cSThe j1939 authors
2289d71dd0cSThe j1939 authors lockdep_assert_held(&priv->lock);
2299d71dd0cSThe j1939 authors
2309d71dd0cSThe j1939 authors if (!name)
2319d71dd0cSThe j1939 authors return NULL;
2329d71dd0cSThe j1939 authors
2339d71dd0cSThe j1939 authors ecu = j1939_ecu_find_by_name_locked(priv, name);
2349d71dd0cSThe j1939 authors if (ecu)
2359d71dd0cSThe j1939 authors j1939_ecu_get(ecu);
2369d71dd0cSThe j1939 authors
2379d71dd0cSThe j1939 authors return ecu;
2389d71dd0cSThe j1939 authors }
2399d71dd0cSThe j1939 authors
j1939_ecu_get_by_name(struct j1939_priv * priv,name_t name)2409d71dd0cSThe j1939 authors struct j1939_ecu *j1939_ecu_get_by_name(struct j1939_priv *priv, name_t name)
2419d71dd0cSThe j1939 authors {
2429d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
2439d71dd0cSThe j1939 authors
2449d71dd0cSThe j1939 authors read_lock_bh(&priv->lock);
2459d71dd0cSThe j1939 authors ecu = j1939_ecu_get_by_name_locked(priv, name);
2469d71dd0cSThe j1939 authors read_unlock_bh(&priv->lock);
2479d71dd0cSThe j1939 authors
2489d71dd0cSThe j1939 authors return ecu;
2499d71dd0cSThe j1939 authors }
2509d71dd0cSThe j1939 authors
j1939_name_to_addr(struct j1939_priv * priv,name_t name)2519d71dd0cSThe j1939 authors u8 j1939_name_to_addr(struct j1939_priv *priv, name_t name)
2529d71dd0cSThe j1939 authors {
2539d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
2549d71dd0cSThe j1939 authors int addr = J1939_IDLE_ADDR;
2559d71dd0cSThe j1939 authors
2569d71dd0cSThe j1939 authors if (!name)
2579d71dd0cSThe j1939 authors return J1939_NO_ADDR;
2589d71dd0cSThe j1939 authors
2599d71dd0cSThe j1939 authors read_lock_bh(&priv->lock);
2609d71dd0cSThe j1939 authors ecu = j1939_ecu_find_by_name_locked(priv, name);
2619d71dd0cSThe j1939 authors if (ecu && j1939_ecu_is_mapped_locked(ecu))
2629d71dd0cSThe j1939 authors /* ecu's SA is registered */
2639d71dd0cSThe j1939 authors addr = ecu->addr;
2649d71dd0cSThe j1939 authors
2659d71dd0cSThe j1939 authors read_unlock_bh(&priv->lock);
2669d71dd0cSThe j1939 authors
2679d71dd0cSThe j1939 authors return addr;
2689d71dd0cSThe j1939 authors }
2699d71dd0cSThe j1939 authors
2709d71dd0cSThe j1939 authors /* TX addr/name accounting
2719d71dd0cSThe j1939 authors * Transport protocol needs to know if a SA is local or not
2729d71dd0cSThe j1939 authors * These functions originate from userspace manipulating sockets,
2739d71dd0cSThe j1939 authors * so locking is straigforward
2749d71dd0cSThe j1939 authors */
2759d71dd0cSThe j1939 authors
j1939_local_ecu_get(struct j1939_priv * priv,name_t name,u8 sa)2769d71dd0cSThe j1939 authors int j1939_local_ecu_get(struct j1939_priv *priv, name_t name, u8 sa)
2779d71dd0cSThe j1939 authors {
2789d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
2799d71dd0cSThe j1939 authors int err = 0;
2809d71dd0cSThe j1939 authors
2819d71dd0cSThe j1939 authors write_lock_bh(&priv->lock);
2829d71dd0cSThe j1939 authors
2839d71dd0cSThe j1939 authors if (j1939_address_is_unicast(sa))
2849d71dd0cSThe j1939 authors priv->ents[sa].nusers++;
2859d71dd0cSThe j1939 authors
2869d71dd0cSThe j1939 authors if (!name)
2879d71dd0cSThe j1939 authors goto done;
2889d71dd0cSThe j1939 authors
2899d71dd0cSThe j1939 authors ecu = j1939_ecu_get_by_name_locked(priv, name);
2909d71dd0cSThe j1939 authors if (!ecu)
2919d71dd0cSThe j1939 authors ecu = j1939_ecu_create_locked(priv, name);
2929d71dd0cSThe j1939 authors err = PTR_ERR_OR_ZERO(ecu);
2939d71dd0cSThe j1939 authors if (err)
2949d71dd0cSThe j1939 authors goto done;
2959d71dd0cSThe j1939 authors
2969d71dd0cSThe j1939 authors ecu->nusers++;
2979d71dd0cSThe j1939 authors /* TODO: do we care if ecu->addr != sa? */
2989d71dd0cSThe j1939 authors if (j1939_ecu_is_mapped_locked(ecu))
2999d71dd0cSThe j1939 authors /* ecu's sa is active already */
3009d71dd0cSThe j1939 authors priv->ents[ecu->addr].nusers++;
3019d71dd0cSThe j1939 authors
3029d71dd0cSThe j1939 authors done:
3039d71dd0cSThe j1939 authors write_unlock_bh(&priv->lock);
3049d71dd0cSThe j1939 authors
3059d71dd0cSThe j1939 authors return err;
3069d71dd0cSThe j1939 authors }
3079d71dd0cSThe j1939 authors
j1939_local_ecu_put(struct j1939_priv * priv,name_t name,u8 sa)3089d71dd0cSThe j1939 authors void j1939_local_ecu_put(struct j1939_priv *priv, name_t name, u8 sa)
3099d71dd0cSThe j1939 authors {
3109d71dd0cSThe j1939 authors struct j1939_ecu *ecu;
3119d71dd0cSThe j1939 authors
3129d71dd0cSThe j1939 authors write_lock_bh(&priv->lock);
3139d71dd0cSThe j1939 authors
3149d71dd0cSThe j1939 authors if (j1939_address_is_unicast(sa))
3159d71dd0cSThe j1939 authors priv->ents[sa].nusers--;
3169d71dd0cSThe j1939 authors
3179d71dd0cSThe j1939 authors if (!name)
3189d71dd0cSThe j1939 authors goto done;
3199d71dd0cSThe j1939 authors
3209d71dd0cSThe j1939 authors ecu = j1939_ecu_find_by_name_locked(priv, name);
3219d71dd0cSThe j1939 authors if (WARN_ON_ONCE(!ecu))
3229d71dd0cSThe j1939 authors goto done;
3239d71dd0cSThe j1939 authors
3249d71dd0cSThe j1939 authors ecu->nusers--;
3259d71dd0cSThe j1939 authors /* TODO: do we care if ecu->addr != sa? */
3269d71dd0cSThe j1939 authors if (j1939_ecu_is_mapped_locked(ecu))
3279d71dd0cSThe j1939 authors /* ecu's sa is active already */
3289d71dd0cSThe j1939 authors priv->ents[ecu->addr].nusers--;
3299d71dd0cSThe j1939 authors j1939_ecu_put(ecu);
3309d71dd0cSThe j1939 authors
3319d71dd0cSThe j1939 authors done:
3329d71dd0cSThe j1939 authors write_unlock_bh(&priv->lock);
3339d71dd0cSThe j1939 authors }
334