xref: /openbmc/linux/net/can/j1939/main.c (revision f91ca89e924eb287915522664a31afc71a49c05b)
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