linux/net/can/j1939/bus.c
<<
>>
Prefs
   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
  17static 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
  27void j1939_ecu_put(struct j1939_ecu *ecu)
  28{
  29        kref_put(&ecu->kref, __j1939_ecu_release);
  30}
  31
  32static void j1939_ecu_get(struct j1939_ecu *ecu)
  33{
  34        kref_get(&ecu->kref);
  35}
  36
  37static 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 */
  48static 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 */
  72void 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
  91void 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
  98void 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
 109void 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
 121void j1939_ecu_timer_cancel(struct j1939_ecu *ecu)
 122{
 123        if (hrtimer_cancel(&ecu->ac_timer))
 124                j1939_ecu_put(ecu);
 125}
 126
 127static 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
 148struct 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
 172struct 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
 180struct 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
 196struct 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 */
 208static 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
 223struct 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
 240struct 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
 251u8 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
 276int 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
 308void 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