123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- // SPDX-License-Identifier: GPL-2.0
- // Copyright (c) 2010-2011 EIA Electronics,
- // Kurt Van Dijck <[email protected]>
- // Copyright (c) 2010-2011 EIA Electronics,
- // Pieter Beyens <[email protected]>
- // Copyright (c) 2017-2019 Pengutronix,
- // Marc Kleine-Budde <[email protected]>
- // Copyright (c) 2017-2019 Pengutronix,
- // Oleksij Rempel <[email protected]>
- /* J1939 Address Claiming.
- * Address Claiming in the kernel
- * - keeps track of the AC states of ECU's,
- * - resolves NAME<=>SA taking into account the AC states of ECU's.
- *
- * All Address Claim msgs (including host-originated msg) are processed
- * at the receive path (a sent msg is always received again via CAN echo).
- * As such, the processing of AC msgs is done in the order on which msgs
- * are sent on the bus.
- *
- * This module doesn't send msgs itself (e.g. replies on Address Claims),
- * this is the responsibility of a user space application or daemon.
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #include <linux/netdevice.h>
- #include <linux/skbuff.h>
- #include "j1939-priv.h"
- static inline name_t j1939_skb_to_name(const struct sk_buff *skb)
- {
- return le64_to_cpup((__le64 *)skb->data);
- }
- static inline bool j1939_ac_msg_is_request(struct sk_buff *skb)
- {
- struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
- int req_pgn;
- if (skb->len < 3 || skcb->addr.pgn != J1939_PGN_REQUEST)
- return false;
- req_pgn = skb->data[0] | (skb->data[1] << 8) | (skb->data[2] << 16);
- return req_pgn == J1939_PGN_ADDRESS_CLAIMED;
- }
- static int j1939_ac_verify_outgoing(struct j1939_priv *priv,
- struct sk_buff *skb)
- {
- struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
- if (skb->len != 8) {
- netdev_notice(priv->ndev, "tx address claim with dlc %i\n",
- skb->len);
- return -EPROTO;
- }
- if (skcb->addr.src_name != j1939_skb_to_name(skb)) {
- netdev_notice(priv->ndev, "tx address claim with different name\n");
- return -EPROTO;
- }
- if (skcb->addr.sa == J1939_NO_ADDR) {
- netdev_notice(priv->ndev, "tx address claim with broadcast sa\n");
- return -EPROTO;
- }
- /* ac must always be a broadcast */
- if (skcb->addr.dst_name || skcb->addr.da != J1939_NO_ADDR) {
- netdev_notice(priv->ndev, "tx address claim with dest, not broadcast\n");
- return -EPROTO;
- }
- return 0;
- }
- int j1939_ac_fixup(struct j1939_priv *priv, struct sk_buff *skb)
- {
- struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
- int ret;
- u8 addr;
- /* network mgmt: address claiming msgs */
- if (skcb->addr.pgn == J1939_PGN_ADDRESS_CLAIMED) {
- struct j1939_ecu *ecu;
- ret = j1939_ac_verify_outgoing(priv, skb);
- /* return both when failure & when successful */
- if (ret < 0)
- return ret;
- ecu = j1939_ecu_get_by_name(priv, skcb->addr.src_name);
- if (!ecu)
- return -ENODEV;
- if (ecu->addr != skcb->addr.sa)
- /* hold further traffic for ecu, remove from parent */
- j1939_ecu_unmap(ecu);
- j1939_ecu_put(ecu);
- } else if (skcb->addr.src_name) {
- /* assign source address */
- addr = j1939_name_to_addr(priv, skcb->addr.src_name);
- if (!j1939_address_is_unicast(addr) &&
- !j1939_ac_msg_is_request(skb)) {
- netdev_notice(priv->ndev, "tx drop: invalid sa for name 0x%016llx\n",
- skcb->addr.src_name);
- return -EADDRNOTAVAIL;
- }
- skcb->addr.sa = addr;
- }
- /* assign destination address */
- if (skcb->addr.dst_name) {
- addr = j1939_name_to_addr(priv, skcb->addr.dst_name);
- if (!j1939_address_is_unicast(addr)) {
- netdev_notice(priv->ndev, "tx drop: invalid da for name 0x%016llx\n",
- skcb->addr.dst_name);
- return -EADDRNOTAVAIL;
- }
- skcb->addr.da = addr;
- }
- return 0;
- }
- static void j1939_ac_process(struct j1939_priv *priv, struct sk_buff *skb)
- {
- struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
- struct j1939_ecu *ecu, *prev;
- name_t name;
- if (skb->len != 8) {
- netdev_notice(priv->ndev, "rx address claim with wrong dlc %i\n",
- skb->len);
- return;
- }
- name = j1939_skb_to_name(skb);
- skcb->addr.src_name = name;
- if (!name) {
- netdev_notice(priv->ndev, "rx address claim without name\n");
- return;
- }
- if (!j1939_address_is_valid(skcb->addr.sa)) {
- netdev_notice(priv->ndev, "rx address claim with broadcast sa\n");
- return;
- }
- write_lock_bh(&priv->lock);
- /* Few words on the ECU ref counting:
- *
- * First we get an ECU handle, either with
- * j1939_ecu_get_by_name_locked() (increments the ref counter)
- * or j1939_ecu_create_locked() (initializes an ECU object
- * with a ref counter of 1).
- *
- * j1939_ecu_unmap_locked() will decrement the ref counter,
- * but only if the ECU was mapped before. So "ecu" still
- * belongs to us.
- *
- * j1939_ecu_timer_start() will increment the ref counter
- * before it starts the timer, so we can put the ecu when
- * leaving this function.
- */
- ecu = j1939_ecu_get_by_name_locked(priv, name);
- if (ecu && ecu->addr == skcb->addr.sa) {
- /* The ISO 11783-5 standard, in "4.5.2 - Address claim
- * requirements", states:
- * d) No CF shall begin, or resume, transmission on the
- * network until 250 ms after it has successfully claimed
- * an address except when responding to a request for
- * address-claimed.
- *
- * But "Figure 6" and "Figure 7" in "4.5.4.2 - Address-claim
- * prioritization" show that the CF begins the transmission
- * after 250 ms from the first AC (address-claimed) message
- * even if it sends another AC message during that time window
- * to resolve the address contention with another CF.
- *
- * As stated in "4.4.2.3 - Address-claimed message":
- * In order to successfully claim an address, the CF sending
- * an address claimed message shall not receive a contending
- * claim from another CF for at least 250 ms.
- *
- * As stated in "4.4.3.2 - NAME management (NM) message":
- * 1) A commanding CF can
- * d) request that a CF with a specified NAME transmit
- * the address-claimed message with its current NAME.
- * 2) A target CF shall
- * d) send an address-claimed message in response to a
- * request for a matching NAME
- *
- * Taking the above arguments into account, the 250 ms wait is
- * requested only during network initialization.
- *
- * Do not restart the timer on AC message if both the NAME and
- * the address match and so if the address has already been
- * claimed (timer has expired) or the AC message has been sent
- * to resolve the contention with another CF (timer is still
- * running).
- */
- goto out_ecu_put;
- }
- if (!ecu && j1939_address_is_unicast(skcb->addr.sa))
- ecu = j1939_ecu_create_locked(priv, name);
- if (IS_ERR_OR_NULL(ecu))
- goto out_unlock_bh;
- /* cancel pending (previous) address claim */
- j1939_ecu_timer_cancel(ecu);
- if (j1939_address_is_idle(skcb->addr.sa)) {
- j1939_ecu_unmap_locked(ecu);
- goto out_ecu_put;
- }
- /* save new addr */
- if (ecu->addr != skcb->addr.sa)
- j1939_ecu_unmap_locked(ecu);
- ecu->addr = skcb->addr.sa;
- prev = j1939_ecu_get_by_addr_locked(priv, skcb->addr.sa);
- if (prev) {
- if (ecu->name > prev->name) {
- j1939_ecu_unmap_locked(ecu);
- j1939_ecu_put(prev);
- goto out_ecu_put;
- } else {
- /* kick prev if less or equal */
- j1939_ecu_unmap_locked(prev);
- j1939_ecu_put(prev);
- }
- }
- j1939_ecu_timer_start(ecu);
- out_ecu_put:
- j1939_ecu_put(ecu);
- out_unlock_bh:
- write_unlock_bh(&priv->lock);
- }
- void j1939_ac_recv(struct j1939_priv *priv, struct sk_buff *skb)
- {
- struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
- struct j1939_ecu *ecu;
- /* network mgmt */
- if (skcb->addr.pgn == J1939_PGN_ADDRESS_CLAIMED) {
- j1939_ac_process(priv, skb);
- } else if (j1939_address_is_unicast(skcb->addr.sa)) {
- /* assign source name */
- ecu = j1939_ecu_get_by_addr(priv, skcb->addr.sa);
- if (ecu) {
- skcb->addr.src_name = ecu->name;
- j1939_ecu_put(ecu);
- }
- }
- /* assign destination name */
- ecu = j1939_ecu_get_by_addr(priv, skcb->addr.da);
- if (ecu) {
- skcb->addr.dst_name = ecu->name;
- j1939_ecu_put(ecu);
- }
- }
|