xref: /linux/net/can/j1939/address-claim.c (revision 9d71dd0c70099914fcd063135da3c580865e924c)
1*9d71dd0cSThe j1939 authors // SPDX-License-Identifier: GPL-2.0
2*9d71dd0cSThe j1939 authors // Copyright (c) 2010-2011 EIA Electronics,
3*9d71dd0cSThe j1939 authors //                         Kurt Van Dijck <kurt.van.dijck@eia.be>
4*9d71dd0cSThe j1939 authors // Copyright (c) 2010-2011 EIA Electronics,
5*9d71dd0cSThe j1939 authors //                         Pieter Beyens <pieter.beyens@eia.be>
6*9d71dd0cSThe j1939 authors // Copyright (c) 2017-2019 Pengutronix,
7*9d71dd0cSThe j1939 authors //                         Marc Kleine-Budde <kernel@pengutronix.de>
8*9d71dd0cSThe j1939 authors // Copyright (c) 2017-2019 Pengutronix,
9*9d71dd0cSThe j1939 authors //                         Oleksij Rempel <kernel@pengutronix.de>
10*9d71dd0cSThe j1939 authors 
11*9d71dd0cSThe j1939 authors /* J1939 Address Claiming.
12*9d71dd0cSThe j1939 authors  * Address Claiming in the kernel
13*9d71dd0cSThe j1939 authors  * - keeps track of the AC states of ECU's,
14*9d71dd0cSThe j1939 authors  * - resolves NAME<=>SA taking into account the AC states of ECU's.
15*9d71dd0cSThe j1939 authors  *
16*9d71dd0cSThe j1939 authors  * All Address Claim msgs (including host-originated msg) are processed
17*9d71dd0cSThe j1939 authors  * at the receive path (a sent msg is always received again via CAN echo).
18*9d71dd0cSThe j1939 authors  * As such, the processing of AC msgs is done in the order on which msgs
19*9d71dd0cSThe j1939 authors  * are sent on the bus.
20*9d71dd0cSThe j1939 authors  *
21*9d71dd0cSThe j1939 authors  * This module doesn't send msgs itself (e.g. replies on Address Claims),
22*9d71dd0cSThe j1939 authors  * this is the responsibility of a user space application or daemon.
23*9d71dd0cSThe j1939 authors  */
24*9d71dd0cSThe j1939 authors 
25*9d71dd0cSThe j1939 authors #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26*9d71dd0cSThe j1939 authors 
27*9d71dd0cSThe j1939 authors #include <linux/netdevice.h>
28*9d71dd0cSThe j1939 authors #include <linux/skbuff.h>
29*9d71dd0cSThe j1939 authors 
30*9d71dd0cSThe j1939 authors #include "j1939-priv.h"
31*9d71dd0cSThe j1939 authors 
32*9d71dd0cSThe j1939 authors static inline name_t j1939_skb_to_name(const struct sk_buff *skb)
33*9d71dd0cSThe j1939 authors {
34*9d71dd0cSThe j1939 authors 	return le64_to_cpup((__le64 *)skb->data);
35*9d71dd0cSThe j1939 authors }
36*9d71dd0cSThe j1939 authors 
37*9d71dd0cSThe j1939 authors static inline bool j1939_ac_msg_is_request(struct sk_buff *skb)
38*9d71dd0cSThe j1939 authors {
39*9d71dd0cSThe j1939 authors 	struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
40*9d71dd0cSThe j1939 authors 	int req_pgn;
41*9d71dd0cSThe j1939 authors 
42*9d71dd0cSThe j1939 authors 	if (skb->len < 3 || skcb->addr.pgn != J1939_PGN_REQUEST)
43*9d71dd0cSThe j1939 authors 		return false;
44*9d71dd0cSThe j1939 authors 
45*9d71dd0cSThe j1939 authors 	req_pgn = skb->data[0] | (skb->data[1] << 8) | (skb->data[2] << 16);
46*9d71dd0cSThe j1939 authors 
47*9d71dd0cSThe j1939 authors 	return req_pgn == J1939_PGN_ADDRESS_CLAIMED;
48*9d71dd0cSThe j1939 authors }
49*9d71dd0cSThe j1939 authors 
50*9d71dd0cSThe j1939 authors static int j1939_ac_verify_outgoing(struct j1939_priv *priv,
51*9d71dd0cSThe j1939 authors 				    struct sk_buff *skb)
52*9d71dd0cSThe j1939 authors {
53*9d71dd0cSThe j1939 authors 	struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
54*9d71dd0cSThe j1939 authors 
55*9d71dd0cSThe j1939 authors 	if (skb->len != 8) {
56*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "tx address claim with dlc %i\n",
57*9d71dd0cSThe j1939 authors 			      skb->len);
58*9d71dd0cSThe j1939 authors 		return -EPROTO;
59*9d71dd0cSThe j1939 authors 	}
60*9d71dd0cSThe j1939 authors 
61*9d71dd0cSThe j1939 authors 	if (skcb->addr.src_name != j1939_skb_to_name(skb)) {
62*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "tx address claim with different name\n");
63*9d71dd0cSThe j1939 authors 		return -EPROTO;
64*9d71dd0cSThe j1939 authors 	}
65*9d71dd0cSThe j1939 authors 
66*9d71dd0cSThe j1939 authors 	if (skcb->addr.sa == J1939_NO_ADDR) {
67*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "tx address claim with broadcast sa\n");
68*9d71dd0cSThe j1939 authors 		return -EPROTO;
69*9d71dd0cSThe j1939 authors 	}
70*9d71dd0cSThe j1939 authors 
71*9d71dd0cSThe j1939 authors 	/* ac must always be a broadcast */
72*9d71dd0cSThe j1939 authors 	if (skcb->addr.dst_name || skcb->addr.da != J1939_NO_ADDR) {
73*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "tx address claim with dest, not broadcast\n");
74*9d71dd0cSThe j1939 authors 		return -EPROTO;
75*9d71dd0cSThe j1939 authors 	}
76*9d71dd0cSThe j1939 authors 	return 0;
77*9d71dd0cSThe j1939 authors }
78*9d71dd0cSThe j1939 authors 
79*9d71dd0cSThe j1939 authors int j1939_ac_fixup(struct j1939_priv *priv, struct sk_buff *skb)
80*9d71dd0cSThe j1939 authors {
81*9d71dd0cSThe j1939 authors 	struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
82*9d71dd0cSThe j1939 authors 	int ret;
83*9d71dd0cSThe j1939 authors 	u8 addr;
84*9d71dd0cSThe j1939 authors 
85*9d71dd0cSThe j1939 authors 	/* network mgmt: address claiming msgs */
86*9d71dd0cSThe j1939 authors 	if (skcb->addr.pgn == J1939_PGN_ADDRESS_CLAIMED) {
87*9d71dd0cSThe j1939 authors 		struct j1939_ecu *ecu;
88*9d71dd0cSThe j1939 authors 
89*9d71dd0cSThe j1939 authors 		ret = j1939_ac_verify_outgoing(priv, skb);
90*9d71dd0cSThe j1939 authors 		/* return both when failure & when successful */
91*9d71dd0cSThe j1939 authors 		if (ret < 0)
92*9d71dd0cSThe j1939 authors 			return ret;
93*9d71dd0cSThe j1939 authors 		ecu = j1939_ecu_get_by_name(priv, skcb->addr.src_name);
94*9d71dd0cSThe j1939 authors 		if (!ecu)
95*9d71dd0cSThe j1939 authors 			return -ENODEV;
96*9d71dd0cSThe j1939 authors 
97*9d71dd0cSThe j1939 authors 		if (ecu->addr != skcb->addr.sa)
98*9d71dd0cSThe j1939 authors 			/* hold further traffic for ecu, remove from parent */
99*9d71dd0cSThe j1939 authors 			j1939_ecu_unmap(ecu);
100*9d71dd0cSThe j1939 authors 		j1939_ecu_put(ecu);
101*9d71dd0cSThe j1939 authors 	} else if (skcb->addr.src_name) {
102*9d71dd0cSThe j1939 authors 		/* assign source address */
103*9d71dd0cSThe j1939 authors 		addr = j1939_name_to_addr(priv, skcb->addr.src_name);
104*9d71dd0cSThe j1939 authors 		if (!j1939_address_is_unicast(addr) &&
105*9d71dd0cSThe j1939 authors 		    !j1939_ac_msg_is_request(skb)) {
106*9d71dd0cSThe j1939 authors 			netdev_notice(priv->ndev, "tx drop: invalid sa for name 0x%016llx\n",
107*9d71dd0cSThe j1939 authors 				      skcb->addr.src_name);
108*9d71dd0cSThe j1939 authors 			return -EADDRNOTAVAIL;
109*9d71dd0cSThe j1939 authors 		}
110*9d71dd0cSThe j1939 authors 		skcb->addr.sa = addr;
111*9d71dd0cSThe j1939 authors 	}
112*9d71dd0cSThe j1939 authors 
113*9d71dd0cSThe j1939 authors 	/* assign destination address */
114*9d71dd0cSThe j1939 authors 	if (skcb->addr.dst_name) {
115*9d71dd0cSThe j1939 authors 		addr = j1939_name_to_addr(priv, skcb->addr.dst_name);
116*9d71dd0cSThe j1939 authors 		if (!j1939_address_is_unicast(addr)) {
117*9d71dd0cSThe j1939 authors 			netdev_notice(priv->ndev, "tx drop: invalid da for name 0x%016llx\n",
118*9d71dd0cSThe j1939 authors 				      skcb->addr.dst_name);
119*9d71dd0cSThe j1939 authors 			return -EADDRNOTAVAIL;
120*9d71dd0cSThe j1939 authors 		}
121*9d71dd0cSThe j1939 authors 		skcb->addr.da = addr;
122*9d71dd0cSThe j1939 authors 	}
123*9d71dd0cSThe j1939 authors 	return 0;
124*9d71dd0cSThe j1939 authors }
125*9d71dd0cSThe j1939 authors 
126*9d71dd0cSThe j1939 authors static void j1939_ac_process(struct j1939_priv *priv, struct sk_buff *skb)
127*9d71dd0cSThe j1939 authors {
128*9d71dd0cSThe j1939 authors 	struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
129*9d71dd0cSThe j1939 authors 	struct j1939_ecu *ecu, *prev;
130*9d71dd0cSThe j1939 authors 	name_t name;
131*9d71dd0cSThe j1939 authors 
132*9d71dd0cSThe j1939 authors 	if (skb->len != 8) {
133*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "rx address claim with wrong dlc %i\n",
134*9d71dd0cSThe j1939 authors 			      skb->len);
135*9d71dd0cSThe j1939 authors 		return;
136*9d71dd0cSThe j1939 authors 	}
137*9d71dd0cSThe j1939 authors 
138*9d71dd0cSThe j1939 authors 	name = j1939_skb_to_name(skb);
139*9d71dd0cSThe j1939 authors 	skcb->addr.src_name = name;
140*9d71dd0cSThe j1939 authors 	if (!name) {
141*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "rx address claim without name\n");
142*9d71dd0cSThe j1939 authors 		return;
143*9d71dd0cSThe j1939 authors 	}
144*9d71dd0cSThe j1939 authors 
145*9d71dd0cSThe j1939 authors 	if (!j1939_address_is_valid(skcb->addr.sa)) {
146*9d71dd0cSThe j1939 authors 		netdev_notice(priv->ndev, "rx address claim with broadcast sa\n");
147*9d71dd0cSThe j1939 authors 		return;
148*9d71dd0cSThe j1939 authors 	}
149*9d71dd0cSThe j1939 authors 
150*9d71dd0cSThe j1939 authors 	write_lock_bh(&priv->lock);
151*9d71dd0cSThe j1939 authors 
152*9d71dd0cSThe j1939 authors 	/* Few words on the ECU ref counting:
153*9d71dd0cSThe j1939 authors 	 *
154*9d71dd0cSThe j1939 authors 	 * First we get an ECU handle, either with
155*9d71dd0cSThe j1939 authors 	 * j1939_ecu_get_by_name_locked() (increments the ref counter)
156*9d71dd0cSThe j1939 authors 	 * or j1939_ecu_create_locked() (initializes an ECU object
157*9d71dd0cSThe j1939 authors 	 * with a ref counter of 1).
158*9d71dd0cSThe j1939 authors 	 *
159*9d71dd0cSThe j1939 authors 	 * j1939_ecu_unmap_locked() will decrement the ref counter,
160*9d71dd0cSThe j1939 authors 	 * but only if the ECU was mapped before. So "ecu" still
161*9d71dd0cSThe j1939 authors 	 * belongs to us.
162*9d71dd0cSThe j1939 authors 	 *
163*9d71dd0cSThe j1939 authors 	 * j1939_ecu_timer_start() will increment the ref counter
164*9d71dd0cSThe j1939 authors 	 * before it starts the timer, so we can put the ecu when
165*9d71dd0cSThe j1939 authors 	 * leaving this function.
166*9d71dd0cSThe j1939 authors 	 */
167*9d71dd0cSThe j1939 authors 	ecu = j1939_ecu_get_by_name_locked(priv, name);
168*9d71dd0cSThe j1939 authors 	if (!ecu && j1939_address_is_unicast(skcb->addr.sa))
169*9d71dd0cSThe j1939 authors 		ecu = j1939_ecu_create_locked(priv, name);
170*9d71dd0cSThe j1939 authors 
171*9d71dd0cSThe j1939 authors 	if (IS_ERR_OR_NULL(ecu))
172*9d71dd0cSThe j1939 authors 		goto out_unlock_bh;
173*9d71dd0cSThe j1939 authors 
174*9d71dd0cSThe j1939 authors 	/* cancel pending (previous) address claim */
175*9d71dd0cSThe j1939 authors 	j1939_ecu_timer_cancel(ecu);
176*9d71dd0cSThe j1939 authors 
177*9d71dd0cSThe j1939 authors 	if (j1939_address_is_idle(skcb->addr.sa)) {
178*9d71dd0cSThe j1939 authors 		j1939_ecu_unmap_locked(ecu);
179*9d71dd0cSThe j1939 authors 		goto out_ecu_put;
180*9d71dd0cSThe j1939 authors 	}
181*9d71dd0cSThe j1939 authors 
182*9d71dd0cSThe j1939 authors 	/* save new addr */
183*9d71dd0cSThe j1939 authors 	if (ecu->addr != skcb->addr.sa)
184*9d71dd0cSThe j1939 authors 		j1939_ecu_unmap_locked(ecu);
185*9d71dd0cSThe j1939 authors 	ecu->addr = skcb->addr.sa;
186*9d71dd0cSThe j1939 authors 
187*9d71dd0cSThe j1939 authors 	prev = j1939_ecu_get_by_addr_locked(priv, skcb->addr.sa);
188*9d71dd0cSThe j1939 authors 	if (prev) {
189*9d71dd0cSThe j1939 authors 		if (ecu->name > prev->name) {
190*9d71dd0cSThe j1939 authors 			j1939_ecu_unmap_locked(ecu);
191*9d71dd0cSThe j1939 authors 			j1939_ecu_put(prev);
192*9d71dd0cSThe j1939 authors 			goto out_ecu_put;
193*9d71dd0cSThe j1939 authors 		} else {
194*9d71dd0cSThe j1939 authors 			/* kick prev if less or equal */
195*9d71dd0cSThe j1939 authors 			j1939_ecu_unmap_locked(prev);
196*9d71dd0cSThe j1939 authors 			j1939_ecu_put(prev);
197*9d71dd0cSThe j1939 authors 		}
198*9d71dd0cSThe j1939 authors 	}
199*9d71dd0cSThe j1939 authors 
200*9d71dd0cSThe j1939 authors 	j1939_ecu_timer_start(ecu);
201*9d71dd0cSThe j1939 authors  out_ecu_put:
202*9d71dd0cSThe j1939 authors 	j1939_ecu_put(ecu);
203*9d71dd0cSThe j1939 authors  out_unlock_bh:
204*9d71dd0cSThe j1939 authors 	write_unlock_bh(&priv->lock);
205*9d71dd0cSThe j1939 authors }
206*9d71dd0cSThe j1939 authors 
207*9d71dd0cSThe j1939 authors void j1939_ac_recv(struct j1939_priv *priv, struct sk_buff *skb)
208*9d71dd0cSThe j1939 authors {
209*9d71dd0cSThe j1939 authors 	struct j1939_sk_buff_cb *skcb = j1939_skb_to_cb(skb);
210*9d71dd0cSThe j1939 authors 	struct j1939_ecu *ecu;
211*9d71dd0cSThe j1939 authors 
212*9d71dd0cSThe j1939 authors 	/* network mgmt */
213*9d71dd0cSThe j1939 authors 	if (skcb->addr.pgn == J1939_PGN_ADDRESS_CLAIMED) {
214*9d71dd0cSThe j1939 authors 		j1939_ac_process(priv, skb);
215*9d71dd0cSThe j1939 authors 	} else if (j1939_address_is_unicast(skcb->addr.sa)) {
216*9d71dd0cSThe j1939 authors 		/* assign source name */
217*9d71dd0cSThe j1939 authors 		ecu = j1939_ecu_get_by_addr(priv, skcb->addr.sa);
218*9d71dd0cSThe j1939 authors 		if (ecu) {
219*9d71dd0cSThe j1939 authors 			skcb->addr.src_name = ecu->name;
220*9d71dd0cSThe j1939 authors 			j1939_ecu_put(ecu);
221*9d71dd0cSThe j1939 authors 		}
222*9d71dd0cSThe j1939 authors 	}
223*9d71dd0cSThe j1939 authors 
224*9d71dd0cSThe j1939 authors 	/* assign destination name */
225*9d71dd0cSThe j1939 authors 	ecu = j1939_ecu_get_by_addr(priv, skcb->addr.da);
226*9d71dd0cSThe j1939 authors 	if (ecu) {
227*9d71dd0cSThe j1939 authors 		skcb->addr.dst_name = ecu->name;
228*9d71dd0cSThe j1939 authors 		j1939_ecu_put(ecu);
229*9d71dd0cSThe j1939 authors 	}
230*9d71dd0cSThe j1939 authors }
231