19d71dd0cSThe j1939 authors // SPDX-License-Identifier: GPL-2.0
29d71dd0cSThe j1939 authors // Copyright (c) 2010-2011 EIA Electronics,
39d71dd0cSThe j1939 authors // Pieter Beyens <pieter.beyens@eia.be>
49d71dd0cSThe j1939 authors // Copyright (c) 2010-2011 EIA Electronics,
59d71dd0cSThe j1939 authors // Kurt Van Dijck <kurt.van.dijck@eia.be>
69d71dd0cSThe j1939 authors // Copyright (c) 2018 Protonic,
79d71dd0cSThe j1939 authors // Robin van der Gracht <robin@protonic.nl>
89d71dd0cSThe j1939 authors // Copyright (c) 2017-2019 Pengutronix,
99d71dd0cSThe j1939 authors // Marc Kleine-Budde <kernel@pengutronix.de>
109d71dd0cSThe j1939 authors // Copyright (c) 2017-2019 Pengutronix,
119d71dd0cSThe j1939 authors // Oleksij Rempel <kernel@pengutronix.de>
129d71dd0cSThe j1939 authors
139d71dd0cSThe j1939 authors /* Core of can-j1939 that links j1939 to CAN. */
149d71dd0cSThe j1939 authors
159d71dd0cSThe j1939 authors #include <linux/can/can-ml.h>
169d71dd0cSThe j1939 authors #include <linux/can/core.h>
179d71dd0cSThe j1939 authors #include <linux/can/skb.h>
189d71dd0cSThe j1939 authors #include <linux/if_arp.h>
199d71dd0cSThe j1939 authors #include <linux/module.h>
209d71dd0cSThe j1939 authors
219d71dd0cSThe j1939 authors #include "j1939-priv.h"
229d71dd0cSThe j1939 authors
239d71dd0cSThe j1939 authors MODULE_DESCRIPTION("PF_CAN SAE J1939");
249d71dd0cSThe j1939 authors MODULE_LICENSE("GPL v2");
259d71dd0cSThe j1939 authors MODULE_AUTHOR("EIA Electronics (Kurt Van Dijck & Pieter Beyens)");
269d71dd0cSThe j1939 authors MODULE_ALIAS("can-proto-" __stringify(CAN_J1939));
279d71dd0cSThe j1939 authors
289d71dd0cSThe j1939 authors /* LOWLEVEL CAN interface */
299d71dd0cSThe j1939 authors
309d71dd0cSThe j1939 authors /* CAN_HDR: #bytes before can_frame data part */
319d71dd0cSThe j1939 authors #define J1939_CAN_HDR (offsetof(struct can_frame, data))
329d71dd0cSThe j1939 authors
339d71dd0cSThe j1939 authors /* lowest layer */
j1939_can_recv(struct sk_buff * iskb,void * data)349d71dd0cSThe j1939 authors static void j1939_can_recv(struct sk_buff *iskb, void *data)
359d71dd0cSThe j1939 authors {
369d71dd0cSThe j1939 authors struct j1939_priv *priv = data;
379d71dd0cSThe j1939 authors struct sk_buff *skb;
389d71dd0cSThe j1939 authors struct j1939_sk_buff_cb *skcb, *iskcb;
399d71dd0cSThe j1939 authors struct can_frame *cf;
409d71dd0cSThe j1939 authors
4196a7457aSOliver Hartkopp /* make sure we only get Classical CAN frames */
4296a7457aSOliver Hartkopp if (!can_is_can_skb(iskb))
4396a7457aSOliver Hartkopp return;
4496a7457aSOliver Hartkopp
459d71dd0cSThe j1939 authors /* create a copy of the skb
469d71dd0cSThe j1939 authors * j1939 only delivers the real data bytes,
479d71dd0cSThe j1939 authors * the header goes into sockaddr.
489d71dd0cSThe j1939 authors * j1939 may not touch the incoming skb in such way
499d71dd0cSThe j1939 authors */
509d71dd0cSThe j1939 authors skb = skb_clone(iskb, GFP_ATOMIC);
519d71dd0cSThe j1939 authors if (!skb)
529d71dd0cSThe j1939 authors return;
539d71dd0cSThe j1939 authors
54ddeeb7d4SOleksij Rempel j1939_priv_get(priv);
559d71dd0cSThe j1939 authors can_skb_set_owner(skb, iskb->sk);
569d71dd0cSThe j1939 authors
579d71dd0cSThe j1939 authors /* get a pointer to the header of the skb
589d71dd0cSThe j1939 authors * the skb payload (pointer) is moved, so that the next skb_data
599d71dd0cSThe j1939 authors * returns the actual payload
609d71dd0cSThe j1939 authors */
619d71dd0cSThe j1939 authors cf = (void *)skb->data;
629d71dd0cSThe j1939 authors skb_pull(skb, J1939_CAN_HDR);
639d71dd0cSThe j1939 authors
649d71dd0cSThe j1939 authors /* fix length, set to dlc, with 8 maximum */
65c7b74967SOliver Hartkopp skb_trim(skb, min_t(uint8_t, cf->len, 8));
669d71dd0cSThe j1939 authors
679d71dd0cSThe j1939 authors /* set addr */
689d71dd0cSThe j1939 authors skcb = j1939_skb_to_cb(skb);
699d71dd0cSThe j1939 authors memset(skcb, 0, sizeof(*skcb));
709d71dd0cSThe j1939 authors
719d71dd0cSThe j1939 authors iskcb = j1939_skb_to_cb(iskb);
729d71dd0cSThe j1939 authors skcb->tskey = iskcb->tskey;
739d71dd0cSThe j1939 authors skcb->priority = (cf->can_id >> 26) & 0x7;
749d71dd0cSThe j1939 authors skcb->addr.sa = cf->can_id;
759d71dd0cSThe j1939 authors skcb->addr.pgn = (cf->can_id >> 8) & J1939_PGN_MAX;
769d71dd0cSThe j1939 authors /* set default message type */
779d71dd0cSThe j1939 authors skcb->addr.type = J1939_TP;
78a79305e1SZhang Changzhong
79a79305e1SZhang Changzhong if (!j1939_address_is_valid(skcb->addr.sa)) {
80a79305e1SZhang Changzhong netdev_err_once(priv->ndev, "%s: sa is broadcast address, ignoring!\n",
81a79305e1SZhang Changzhong __func__);
82a79305e1SZhang Changzhong goto done;
83a79305e1SZhang Changzhong }
84a79305e1SZhang Changzhong
859d71dd0cSThe j1939 authors if (j1939_pgn_is_pdu1(skcb->addr.pgn)) {
869d71dd0cSThe j1939 authors /* Type 1: with destination address */
879d71dd0cSThe j1939 authors skcb->addr.da = skcb->addr.pgn;
889d71dd0cSThe j1939 authors /* normalize pgn: strip dst address */
899d71dd0cSThe j1939 authors skcb->addr.pgn &= 0x3ff00;
909d71dd0cSThe j1939 authors } else {
919d71dd0cSThe j1939 authors /* set broadcast address */
929d71dd0cSThe j1939 authors skcb->addr.da = J1939_NO_ADDR;
939d71dd0cSThe j1939 authors }
949d71dd0cSThe j1939 authors
959d71dd0cSThe j1939 authors /* update localflags */
969d71dd0cSThe j1939 authors read_lock_bh(&priv->lock);
979d71dd0cSThe j1939 authors if (j1939_address_is_unicast(skcb->addr.sa) &&
989d71dd0cSThe j1939 authors priv->ents[skcb->addr.sa].nusers)
999d71dd0cSThe j1939 authors skcb->flags |= J1939_ECU_LOCAL_SRC;
1009d71dd0cSThe j1939 authors if (j1939_address_is_unicast(skcb->addr.da) &&
1019d71dd0cSThe j1939 authors priv->ents[skcb->addr.da].nusers)
1029d71dd0cSThe j1939 authors skcb->flags |= J1939_ECU_LOCAL_DST;
1039d71dd0cSThe j1939 authors read_unlock_bh(&priv->lock);
1049d71dd0cSThe j1939 authors
1059d71dd0cSThe j1939 authors /* deliver into the j1939 stack ... */
1069d71dd0cSThe j1939 authors j1939_ac_recv(priv, skb);
1079d71dd0cSThe j1939 authors
1089d71dd0cSThe j1939 authors if (j1939_tp_recv(priv, skb))
1099d71dd0cSThe j1939 authors /* this means the transport layer processed the message */
1109d71dd0cSThe j1939 authors goto done;
1119d71dd0cSThe j1939 authors
1129d71dd0cSThe j1939 authors j1939_simple_recv(priv, skb);
1139d71dd0cSThe j1939 authors j1939_sk_recv(priv, skb);
1149d71dd0cSThe j1939 authors done:
115ddeeb7d4SOleksij Rempel j1939_priv_put(priv);
1169d71dd0cSThe j1939 authors kfree_skb(skb);
1179d71dd0cSThe j1939 authors }
1189d71dd0cSThe j1939 authors
1199d71dd0cSThe j1939 authors /* NETDEV MANAGEMENT */
1209d71dd0cSThe j1939 authors
1219d71dd0cSThe j1939 authors /* values for can_rx_(un)register */
1229d71dd0cSThe j1939 authors #define J1939_CAN_ID CAN_EFF_FLAG
1239d71dd0cSThe j1939 authors #define J1939_CAN_MASK (CAN_EFF_FLAG | CAN_RTR_FLAG)
1249d71dd0cSThe j1939 authors
125cd9c790dSFedor Pchelkin static DEFINE_MUTEX(j1939_netdev_lock);
1269d71dd0cSThe j1939 authors
j1939_priv_create(struct net_device * ndev)1279d71dd0cSThe j1939 authors static struct j1939_priv *j1939_priv_create(struct net_device *ndev)
1289d71dd0cSThe j1939 authors {
1299d71dd0cSThe j1939 authors struct j1939_priv *priv;
1309d71dd0cSThe j1939 authors
1319d71dd0cSThe j1939 authors priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1329d71dd0cSThe j1939 authors if (!priv)
1339d71dd0cSThe j1939 authors return NULL;
1349d71dd0cSThe j1939 authors
1359d71dd0cSThe j1939 authors rwlock_init(&priv->lock);
1369d71dd0cSThe j1939 authors INIT_LIST_HEAD(&priv->ecus);
1379d71dd0cSThe j1939 authors priv->ndev = ndev;
1389d71dd0cSThe j1939 authors kref_init(&priv->kref);
1399d71dd0cSThe j1939 authors kref_init(&priv->rx_kref);
1409d71dd0cSThe j1939 authors dev_hold(ndev);
1419d71dd0cSThe j1939 authors
1429d71dd0cSThe j1939 authors netdev_dbg(priv->ndev, "%s : 0x%p\n", __func__, priv);
1439d71dd0cSThe j1939 authors
1449d71dd0cSThe j1939 authors return priv;
1459d71dd0cSThe j1939 authors }
1469d71dd0cSThe j1939 authors
j1939_priv_set(struct net_device * ndev,struct j1939_priv * priv)1479d71dd0cSThe j1939 authors static inline void j1939_priv_set(struct net_device *ndev,
1489d71dd0cSThe j1939 authors struct j1939_priv *priv)
1499d71dd0cSThe j1939 authors {
1504e096a18SOleksij Rempel struct can_ml_priv *can_ml = can_get_ml_priv(ndev);
1519d71dd0cSThe j1939 authors
1524e096a18SOleksij Rempel can_ml->j1939_priv = priv;
1539d71dd0cSThe j1939 authors }
1549d71dd0cSThe j1939 authors
__j1939_priv_release(struct kref * kref)1559d71dd0cSThe j1939 authors static void __j1939_priv_release(struct kref *kref)
1569d71dd0cSThe j1939 authors {
1579d71dd0cSThe j1939 authors struct j1939_priv *priv = container_of(kref, struct j1939_priv, kref);
1589d71dd0cSThe j1939 authors struct net_device *ndev = priv->ndev;
1599d71dd0cSThe j1939 authors
1609d71dd0cSThe j1939 authors netdev_dbg(priv->ndev, "%s: 0x%p\n", __func__, priv);
1619d71dd0cSThe j1939 authors
1624a15d574SOleksij Rempel WARN_ON_ONCE(!list_empty(&priv->active_session_list));
1634a15d574SOleksij Rempel WARN_ON_ONCE(!list_empty(&priv->ecus));
1644a15d574SOleksij Rempel WARN_ON_ONCE(!list_empty(&priv->j1939_socks));
1654a15d574SOleksij Rempel
1669d71dd0cSThe j1939 authors dev_put(ndev);
1679d71dd0cSThe j1939 authors kfree(priv);
1689d71dd0cSThe j1939 authors }
1699d71dd0cSThe j1939 authors
j1939_priv_put(struct j1939_priv * priv)1709d71dd0cSThe j1939 authors void j1939_priv_put(struct j1939_priv *priv)
1719d71dd0cSThe j1939 authors {
1729d71dd0cSThe j1939 authors kref_put(&priv->kref, __j1939_priv_release);
1739d71dd0cSThe j1939 authors }
1749d71dd0cSThe j1939 authors
j1939_priv_get(struct j1939_priv * priv)1759d71dd0cSThe j1939 authors void j1939_priv_get(struct j1939_priv *priv)
1769d71dd0cSThe j1939 authors {
1779d71dd0cSThe j1939 authors kref_get(&priv->kref);
1789d71dd0cSThe j1939 authors }
1799d71dd0cSThe j1939 authors
j1939_can_rx_register(struct j1939_priv * priv)1809d71dd0cSThe j1939 authors static int j1939_can_rx_register(struct j1939_priv *priv)
1819d71dd0cSThe j1939 authors {
1829d71dd0cSThe j1939 authors struct net_device *ndev = priv->ndev;
1839d71dd0cSThe j1939 authors int ret;
1849d71dd0cSThe j1939 authors
1859d71dd0cSThe j1939 authors j1939_priv_get(priv);
1869d71dd0cSThe j1939 authors ret = can_rx_register(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK,
1879d71dd0cSThe j1939 authors j1939_can_recv, priv, "j1939", NULL);
1889d71dd0cSThe j1939 authors if (ret < 0) {
1899d71dd0cSThe j1939 authors j1939_priv_put(priv);
1909d71dd0cSThe j1939 authors return ret;
1919d71dd0cSThe j1939 authors }
1929d71dd0cSThe j1939 authors
1939d71dd0cSThe j1939 authors return 0;
1949d71dd0cSThe j1939 authors }
1959d71dd0cSThe j1939 authors
j1939_can_rx_unregister(struct j1939_priv * priv)1969d71dd0cSThe j1939 authors static void j1939_can_rx_unregister(struct j1939_priv *priv)
1979d71dd0cSThe j1939 authors {
1989d71dd0cSThe j1939 authors struct net_device *ndev = priv->ndev;
1999d71dd0cSThe j1939 authors
2009d71dd0cSThe j1939 authors can_rx_unregister(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK,
2019d71dd0cSThe j1939 authors j1939_can_recv, priv);
2029d71dd0cSThe j1939 authors
20322c696feSOleksij Rempel /* The last reference of priv is dropped by the RCU deferred
20422c696feSOleksij Rempel * j1939_sk_sock_destruct() of the last socket, so we can
20522c696feSOleksij Rempel * safely drop this reference here.
20622c696feSOleksij Rempel */
2079d71dd0cSThe j1939 authors j1939_priv_put(priv);
2089d71dd0cSThe j1939 authors }
2099d71dd0cSThe j1939 authors
__j1939_rx_release(struct kref * kref)2109d71dd0cSThe j1939 authors static void __j1939_rx_release(struct kref *kref)
2119d71dd0cSThe j1939 authors __releases(&j1939_netdev_lock)
2129d71dd0cSThe j1939 authors {
2139d71dd0cSThe j1939 authors struct j1939_priv *priv = container_of(kref, struct j1939_priv,
2149d71dd0cSThe j1939 authors rx_kref);
2159d71dd0cSThe j1939 authors
2169d71dd0cSThe j1939 authors j1939_can_rx_unregister(priv);
2179d71dd0cSThe j1939 authors j1939_ecu_unmap_all(priv);
2189d71dd0cSThe j1939 authors j1939_priv_set(priv->ndev, NULL);
219cd9c790dSFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
2209d71dd0cSThe j1939 authors }
2219d71dd0cSThe j1939 authors
2229d71dd0cSThe j1939 authors /* get pointer to priv without increasing ref counter */
j1939_ndev_to_priv(struct net_device * ndev)2239d71dd0cSThe j1939 authors static inline struct j1939_priv *j1939_ndev_to_priv(struct net_device *ndev)
2249d71dd0cSThe j1939 authors {
2254e096a18SOleksij Rempel struct can_ml_priv *can_ml = can_get_ml_priv(ndev);
2269d71dd0cSThe j1939 authors
2274e096a18SOleksij Rempel return can_ml->j1939_priv;
2289d71dd0cSThe j1939 authors }
2299d71dd0cSThe j1939 authors
j1939_priv_get_by_ndev_locked(struct net_device * ndev)2309d71dd0cSThe j1939 authors static struct j1939_priv *j1939_priv_get_by_ndev_locked(struct net_device *ndev)
2319d71dd0cSThe j1939 authors {
2329d71dd0cSThe j1939 authors struct j1939_priv *priv;
2339d71dd0cSThe j1939 authors
2349d71dd0cSThe j1939 authors lockdep_assert_held(&j1939_netdev_lock);
2359d71dd0cSThe j1939 authors
2369d71dd0cSThe j1939 authors priv = j1939_ndev_to_priv(ndev);
2379d71dd0cSThe j1939 authors if (priv)
2389d71dd0cSThe j1939 authors j1939_priv_get(priv);
2399d71dd0cSThe j1939 authors
2409d71dd0cSThe j1939 authors return priv;
2419d71dd0cSThe j1939 authors }
2429d71dd0cSThe j1939 authors
j1939_priv_get_by_ndev(struct net_device * ndev)2439d71dd0cSThe j1939 authors static struct j1939_priv *j1939_priv_get_by_ndev(struct net_device *ndev)
2449d71dd0cSThe j1939 authors {
2459d71dd0cSThe j1939 authors struct j1939_priv *priv;
2469d71dd0cSThe j1939 authors
247cd9c790dSFedor Pchelkin mutex_lock(&j1939_netdev_lock);
2489d71dd0cSThe j1939 authors priv = j1939_priv_get_by_ndev_locked(ndev);
249cd9c790dSFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
2509d71dd0cSThe j1939 authors
2519d71dd0cSThe j1939 authors return priv;
2529d71dd0cSThe j1939 authors }
2539d71dd0cSThe j1939 authors
j1939_netdev_start(struct net_device * ndev)2549d71dd0cSThe j1939 authors struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
2559d71dd0cSThe j1939 authors {
2569d71dd0cSThe j1939 authors struct j1939_priv *priv, *priv_new;
2579d71dd0cSThe j1939 authors int ret;
2589d71dd0cSThe j1939 authors
259cd9c790dSFedor Pchelkin mutex_lock(&j1939_netdev_lock);
260d9d52a3eSZiyang Xuan priv = j1939_priv_get_by_ndev_locked(ndev);
2619d71dd0cSThe j1939 authors if (priv) {
2629d71dd0cSThe j1939 authors kref_get(&priv->rx_kref);
263cd9c790dSFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
2649d71dd0cSThe j1939 authors return priv;
2659d71dd0cSThe j1939 authors }
266cd9c790dSFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
2679d71dd0cSThe j1939 authors
2689d71dd0cSThe j1939 authors priv = j1939_priv_create(ndev);
2699d71dd0cSThe j1939 authors if (!priv)
2709d71dd0cSThe j1939 authors return ERR_PTR(-ENOMEM);
2719d71dd0cSThe j1939 authors
2729d71dd0cSThe j1939 authors j1939_tp_init(priv);
27326dfe112SZiqi Zhao rwlock_init(&priv->j1939_socks_lock);
2749d71dd0cSThe j1939 authors INIT_LIST_HEAD(&priv->j1939_socks);
2759d71dd0cSThe j1939 authors
276cd9c790dSFedor Pchelkin mutex_lock(&j1939_netdev_lock);
2779d71dd0cSThe j1939 authors priv_new = j1939_priv_get_by_ndev_locked(ndev);
2789d71dd0cSThe j1939 authors if (priv_new) {
2799d71dd0cSThe j1939 authors /* Someone was faster than us, use their priv and roll
2809d71dd0cSThe j1939 authors * back our's.
2819d71dd0cSThe j1939 authors */
282d9d52a3eSZiyang Xuan kref_get(&priv_new->rx_kref);
283cd9c790dSFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
2849d71dd0cSThe j1939 authors dev_put(ndev);
2859d71dd0cSThe j1939 authors kfree(priv);
2869d71dd0cSThe j1939 authors return priv_new;
2879d71dd0cSThe j1939 authors }
2889d71dd0cSThe j1939 authors j1939_priv_set(ndev, priv);
2899d71dd0cSThe j1939 authors
2909d71dd0cSThe j1939 authors ret = j1939_can_rx_register(priv);
2919d71dd0cSThe j1939 authors if (ret < 0)
2929d71dd0cSThe j1939 authors goto out_priv_put;
2939d71dd0cSThe j1939 authors
2949f16eb10SFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
2959d71dd0cSThe j1939 authors return priv;
2969d71dd0cSThe j1939 authors
2979d71dd0cSThe j1939 authors out_priv_put:
2989d71dd0cSThe j1939 authors j1939_priv_set(ndev, NULL);
2999f16eb10SFedor Pchelkin mutex_unlock(&j1939_netdev_lock);
3009f16eb10SFedor Pchelkin
3019d71dd0cSThe j1939 authors dev_put(ndev);
3029d71dd0cSThe j1939 authors kfree(priv);
3039d71dd0cSThe j1939 authors
3049d71dd0cSThe j1939 authors return ERR_PTR(ret);
3059d71dd0cSThe j1939 authors }
3069d71dd0cSThe j1939 authors
j1939_netdev_stop(struct j1939_priv * priv)3079d71dd0cSThe j1939 authors void j1939_netdev_stop(struct j1939_priv *priv)
3089d71dd0cSThe j1939 authors {
309cd9c790dSFedor Pchelkin kref_put_mutex(&priv->rx_kref, __j1939_rx_release, &j1939_netdev_lock);
3109d71dd0cSThe j1939 authors j1939_priv_put(priv);
3119d71dd0cSThe j1939 authors }
3129d71dd0cSThe j1939 authors
j1939_send_one(struct j1939_priv * priv,struct sk_buff * skb)3139d71dd0cSThe j1939 authors int j1939_send_one(struct j1939_priv *priv, struct sk_buff *skb)
3149d71dd0cSThe j1939 authors {
3159d71dd0cSThe j1939 authors int ret, dlc;
3169d71dd0cSThe j1939 authors canid_t canid;
3179d71dd0cSThe j1939 authors struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
3189d71dd0cSThe j1939 authors struct can_frame *cf;
3199d71dd0cSThe j1939 authors
3209d71dd0cSThe j1939 authors /* apply sanity checks */
3219d71dd0cSThe j1939 authors if (j1939_pgn_is_pdu1(skcb->addr.pgn))
3229d71dd0cSThe j1939 authors skcb->addr.pgn &= J1939_PGN_PDU1_MAX;
3239d71dd0cSThe j1939 authors else
3249d71dd0cSThe j1939 authors skcb->addr.pgn &= J1939_PGN_MAX;
3259d71dd0cSThe j1939 authors
3269d71dd0cSThe j1939 authors if (skcb->priority > 7)
3279d71dd0cSThe j1939 authors skcb->priority = 6;
3289d71dd0cSThe j1939 authors
3299d71dd0cSThe j1939 authors ret = j1939_ac_fixup(priv, skb);
3309d71dd0cSThe j1939 authors if (unlikely(ret))
3319d71dd0cSThe j1939 authors goto failed;
3329d71dd0cSThe j1939 authors dlc = skb->len;
3339d71dd0cSThe j1939 authors
3349d71dd0cSThe j1939 authors /* re-claim the CAN_HDR from the SKB */
3359d71dd0cSThe j1939 authors cf = skb_push(skb, J1939_CAN_HDR);
3369d71dd0cSThe j1939 authors
3373eb3d283SOliver Hartkopp /* initialize header structure */
3383eb3d283SOliver Hartkopp memset(cf, 0, J1939_CAN_HDR);
3393eb3d283SOliver Hartkopp
3409d71dd0cSThe j1939 authors /* make it a full can frame again */
341*ab2a6839SShigeru Yoshida skb_put_zero(skb, 8 - dlc);
3429d71dd0cSThe j1939 authors
3439d71dd0cSThe j1939 authors canid = CAN_EFF_FLAG |
3449d71dd0cSThe j1939 authors (skcb->priority << 26) |
3459d71dd0cSThe j1939 authors (skcb->addr.pgn << 8) |
3469d71dd0cSThe j1939 authors skcb->addr.sa;
3479d71dd0cSThe j1939 authors if (j1939_pgn_is_pdu1(skcb->addr.pgn))
3489d71dd0cSThe j1939 authors canid |= skcb->addr.da << 8;
3499d71dd0cSThe j1939 authors
3509d71dd0cSThe j1939 authors cf->can_id = canid;
351c7b74967SOliver Hartkopp cf->len = dlc;
3529d71dd0cSThe j1939 authors
3539d71dd0cSThe j1939 authors return can_send(skb, 1);
3549d71dd0cSThe j1939 authors
3559d71dd0cSThe j1939 authors failed:
3569d71dd0cSThe j1939 authors kfree_skb(skb);
3579d71dd0cSThe j1939 authors return ret;
3589d71dd0cSThe j1939 authors }
3599d71dd0cSThe j1939 authors
j1939_netdev_notify(struct notifier_block * nb,unsigned long msg,void * data)3609d71dd0cSThe j1939 authors static int j1939_netdev_notify(struct notifier_block *nb,
3619d71dd0cSThe j1939 authors unsigned long msg, void *data)
3629d71dd0cSThe j1939 authors {
3639d71dd0cSThe j1939 authors struct net_device *ndev = netdev_notifier_info_to_dev(data);
3644e096a18SOleksij Rempel struct can_ml_priv *can_ml = can_get_ml_priv(ndev);
3659d71dd0cSThe j1939 authors struct j1939_priv *priv;
3669d71dd0cSThe j1939 authors
3674e096a18SOleksij Rempel if (!can_ml)
3684e096a18SOleksij Rempel goto notify_done;
3694e096a18SOleksij Rempel
3709d71dd0cSThe j1939 authors priv = j1939_priv_get_by_ndev(ndev);
3719d71dd0cSThe j1939 authors if (!priv)
3729d71dd0cSThe j1939 authors goto notify_done;
3739d71dd0cSThe j1939 authors
3749d71dd0cSThe j1939 authors switch (msg) {
3759d71dd0cSThe j1939 authors case NETDEV_DOWN:
3769d71dd0cSThe j1939 authors j1939_cancel_active_session(priv, NULL);
3779d71dd0cSThe j1939 authors j1939_sk_netdev_event_netdown(priv);
3789d71dd0cSThe j1939 authors j1939_ecu_unmap_all(priv);
3799d71dd0cSThe j1939 authors break;
3809d71dd0cSThe j1939 authors }
3819d71dd0cSThe j1939 authors
3829d71dd0cSThe j1939 authors j1939_priv_put(priv);
3839d71dd0cSThe j1939 authors
3849d71dd0cSThe j1939 authors notify_done:
3859d71dd0cSThe j1939 authors return NOTIFY_DONE;
3869d71dd0cSThe j1939 authors }
3879d71dd0cSThe j1939 authors
3889d71dd0cSThe j1939 authors static struct notifier_block j1939_netdev_notifier = {
3899d71dd0cSThe j1939 authors .notifier_call = j1939_netdev_notify,
3909d71dd0cSThe j1939 authors };
3919d71dd0cSThe j1939 authors
3929d71dd0cSThe j1939 authors /* MODULE interface */
j1939_module_init(void)3939d71dd0cSThe j1939 authors static __init int j1939_module_init(void)
3949d71dd0cSThe j1939 authors {
3959d71dd0cSThe j1939 authors int ret;
3969d71dd0cSThe j1939 authors
3979d71dd0cSThe j1939 authors pr_info("can: SAE J1939\n");
3989d71dd0cSThe j1939 authors
3999d71dd0cSThe j1939 authors ret = register_netdevice_notifier(&j1939_netdev_notifier);
4009d71dd0cSThe j1939 authors if (ret)
4019d71dd0cSThe j1939 authors goto fail_notifier;
4029d71dd0cSThe j1939 authors
4039d71dd0cSThe j1939 authors ret = can_proto_register(&j1939_can_proto);
4049d71dd0cSThe j1939 authors if (ret < 0) {
4059d71dd0cSThe j1939 authors pr_err("can: registration of j1939 protocol failed\n");
4069d71dd0cSThe j1939 authors goto fail_sk;
4079d71dd0cSThe j1939 authors }
4089d71dd0cSThe j1939 authors
4099d71dd0cSThe j1939 authors return 0;
4109d71dd0cSThe j1939 authors
4119d71dd0cSThe j1939 authors fail_sk:
4129d71dd0cSThe j1939 authors unregister_netdevice_notifier(&j1939_netdev_notifier);
4139d71dd0cSThe j1939 authors fail_notifier:
4149d71dd0cSThe j1939 authors return ret;
4159d71dd0cSThe j1939 authors }
4169d71dd0cSThe j1939 authors
j1939_module_exit(void)4179d71dd0cSThe j1939 authors static __exit void j1939_module_exit(void)
4189d71dd0cSThe j1939 authors {
4199d71dd0cSThe j1939 authors can_proto_unregister(&j1939_can_proto);
4209d71dd0cSThe j1939 authors
4219d71dd0cSThe j1939 authors unregister_netdevice_notifier(&j1939_netdev_notifier);
4229d71dd0cSThe j1939 authors }
4239d71dd0cSThe j1939 authors
4249d71dd0cSThe j1939 authors module_init(j1939_module_init);
4259d71dd0cSThe j1939 authors module_exit(j1939_module_exit);
426