Blame view

net/can/bcm.c 39 KB
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  /*
   * bcm.c - Broadcast Manager to filter/send (cyclic) CAN content
   *
   * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. Neither the name of Volkswagen nor the names of its contributors
   *    may be used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * Alternatively, provided that this notice is retained in full, this
   * software may be distributed under the terms of the GNU General
   * Public License ("GPL") version 2, in which case the provisions of the
   * GPL apply INSTEAD OF those given above.
   *
   * The provided data structures and external interfaces from this code
   * are not restricted to be used by modules with a GPL compatible license.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
   * DAMAGE.
   *
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
40
41
42
43
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
a6b7a4078   Alexey Dobriyan   net: remove inter...
44
  #include <linux/interrupt.h>
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
45
  #include <linux/hrtimer.h>
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
46
47
  #include <linux/list.h>
  #include <linux/proc_fs.h>
ea00b8e22   Alexey Dobriyan   can: switch to se...
48
  #include <linux/seq_file.h>
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
49
50
51
52
53
54
55
56
57
  #include <linux/uio.h>
  #include <linux/net.h>
  #include <linux/netdevice.h>
  #include <linux/socket.h>
  #include <linux/if_arp.h>
  #include <linux/skbuff.h>
  #include <linux/can.h>
  #include <linux/can/core.h>
  #include <linux/can/bcm.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
58
  #include <linux/slab.h>
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
59
60
  #include <net/sock.h>
  #include <net/net_namespace.h>
5b75c4973   Oliver Hartkopp   can: add limit fo...
61
62
63
64
65
66
  /*
   * To send multiple CAN frame content within TX_SETUP or to filter
   * CAN messages with multiplex index within RX_SETUP, the number of
   * different filters is limited to 256 due to the one byte index value.
   */
  #define MAX_NFRAMES 256
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
67
68
69
70
71
72
  /* use of last_frames[index].can_dlc */
  #define RX_RECV    0x40 /* received data for this element */
  #define RX_THR     0x80 /* element not been sent due to throttle feature */
  #define BCM_CAN_DLC_MASK 0x0F /* clean private flags in can_dlc by masking */
  
  /* get best masking value for can_rx_register() for a given single can_id */
d253eee20   Oliver Hartkopp   can: Fix CAN_(EFF...
73
74
75
  #define REGMASK(id) ((id & CAN_EFF_FLAG) ? \
  		     (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \
  		     (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG))
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
76

d253eee20   Oliver Hartkopp   can: Fix CAN_(EFF...
77
  #define CAN_BCM_VERSION CAN_VERSION
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
78
  static __initdata const char banner[] = KERN_INFO
6e5c172cf   Oliver Hartkopp   can: update can-b...
79
80
  	"can: broadcast manager protocol (rev " CAN_BCM_VERSION " t)
  ";
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
81
82
83
84
  
  MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
b13bb2e99   Lothar Waßmann   net/can: add modu...
85
  MODULE_ALIAS("can-proto-2");
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
86
87
88
89
90
91
92
93
94
95
96
  
  /* easy access to can_frame payload */
  static inline u64 GET_U64(const struct can_frame *cp)
  {
  	return *(u64 *)cp->data;
  }
  
  struct bcm_op {
  	struct list_head list;
  	int ifindex;
  	canid_t can_id;
5b75c4973   Oliver Hartkopp   can: add limit fo...
97
  	u32 flags;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
98
  	unsigned long frames_abs, frames_filtered;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
99
  	struct timeval ival1, ival2;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
100
  	struct hrtimer timer, thrtimer;
6e5c172cf   Oliver Hartkopp   can: update can-b...
101
  	struct tasklet_struct tsklet, thrtsklet;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
102
  	ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
103
  	int rx_ifindex;
5b75c4973   Oliver Hartkopp   can: add limit fo...
104
105
106
  	u32 count;
  	u32 nframes;
  	u32 currframe;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  	struct can_frame *frames;
  	struct can_frame *last_frames;
  	struct can_frame sframe;
  	struct can_frame last_sframe;
  	struct sock *sk;
  	struct net_device *rx_reg_dev;
  };
  
  static struct proc_dir_entry *proc_dir;
  
  struct bcm_sock {
  	struct sock sk;
  	int bound;
  	int ifindex;
  	struct notifier_block notifier;
  	struct list_head rx_ops;
  	struct list_head tx_ops;
  	unsigned long dropped_usr_msgs;
  	struct proc_dir_entry *bcm_proc_read;
9f260e0ef   Dan Rosenberg   CAN: Use inode in...
126
  	char procname [32]; /* inode number in decimal with \0 */
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
127
128
129
130
131
132
133
134
135
136
137
138
  };
  
  static inline struct bcm_sock *bcm_sk(const struct sock *sk)
  {
  	return (struct bcm_sock *)sk;
  }
  
  #define CFSIZ sizeof(struct can_frame)
  #define OPSIZ sizeof(struct bcm_op)
  #define MHSIZ sizeof(struct bcm_msg_head)
  
  /*
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
139
140
   * procfs functions
   */
6755aebaa   Eric Dumazet   can: should not u...
141
  static char *bcm_proc_getifname(char *result, int ifindex)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
142
143
144
145
146
  {
  	struct net_device *dev;
  
  	if (!ifindex)
  		return "any";
ff879eb61   stephen hemminger   CAN: use dev_get_...
147
148
  	rcu_read_lock();
  	dev = dev_get_by_index_rcu(&init_net, ifindex);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
149
  	if (dev)
6755aebaa   Eric Dumazet   can: should not u...
150
151
152
  		strcpy(result, dev->name);
  	else
  		strcpy(result, "???");
ff879eb61   stephen hemminger   CAN: use dev_get_...
153
  	rcu_read_unlock();
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
154

6755aebaa   Eric Dumazet   can: should not u...
155
  	return result;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
156
  }
ea00b8e22   Alexey Dobriyan   can: switch to se...
157
  static int bcm_proc_show(struct seq_file *m, void *v)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
158
  {
6755aebaa   Eric Dumazet   can: should not u...
159
  	char ifname[IFNAMSIZ];
ea00b8e22   Alexey Dobriyan   can: switch to se...
160
  	struct sock *sk = (struct sock *)m->private;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
161
162
  	struct bcm_sock *bo = bcm_sk(sk);
  	struct bcm_op *op;
71338aa7d   Dan Rosenberg   net: convert %p u...
163
164
165
  	seq_printf(m, ">>> socket %pK", sk->sk_socket);
  	seq_printf(m, " / sk %pK", sk);
  	seq_printf(m, " / bo %pK", bo);
ea00b8e22   Alexey Dobriyan   can: switch to se...
166
  	seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
6755aebaa   Eric Dumazet   can: should not u...
167
  	seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex));
ea00b8e22   Alexey Dobriyan   can: switch to se...
168
169
  	seq_printf(m, " <<<
  ");
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
170
171
172
173
174
175
176
177
  
  	list_for_each_entry(op, &bo->rx_ops, list) {
  
  		unsigned long reduction;
  
  		/* print only active entries & prevent division by zero */
  		if (!op->frames_abs)
  			continue;
ea00b8e22   Alexey Dobriyan   can: switch to se...
178
  		seq_printf(m, "rx_op: %03X %-5s ",
6755aebaa   Eric Dumazet   can: should not u...
179
  				op->can_id, bcm_proc_getifname(ifname, op->ifindex));
5b75c4973   Oliver Hartkopp   can: add limit fo...
180
  		seq_printf(m, "[%u]%c ", op->nframes,
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
181
  				(op->flags & RX_CHECK_DLC)?'d':' ');
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
182
  		if (op->kt_ival1.tv64)
ea00b8e22   Alexey Dobriyan   can: switch to se...
183
  			seq_printf(m, "timeo=%lld ",
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
184
185
  					(long long)
  					ktime_to_us(op->kt_ival1));
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
186

73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
187
  		if (op->kt_ival2.tv64)
ea00b8e22   Alexey Dobriyan   can: switch to se...
188
  			seq_printf(m, "thr=%lld ",
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
189
190
  					(long long)
  					ktime_to_us(op->kt_ival2));
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
191

ea00b8e22   Alexey Dobriyan   can: switch to se...
192
  		seq_printf(m, "# recv %ld (%ld) => reduction: ",
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
193
194
195
  				op->frames_filtered, op->frames_abs);
  
  		reduction = 100 - (op->frames_filtered * 100) / op->frames_abs;
ea00b8e22   Alexey Dobriyan   can: switch to se...
196
197
  		seq_printf(m, "%s%ld%%
  ",
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
198
  				(reduction == 100)?"near ":"", reduction);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
199
200
201
  	}
  
  	list_for_each_entry(op, &bo->tx_ops, list) {
5b75c4973   Oliver Hartkopp   can: add limit fo...
202
  		seq_printf(m, "tx_op: %03X %s [%u] ",
6755aebaa   Eric Dumazet   can: should not u...
203
204
  				op->can_id,
  				bcm_proc_getifname(ifname, op->ifindex),
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
205
  				op->nframes);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
206

73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
207
  		if (op->kt_ival1.tv64)
ea00b8e22   Alexey Dobriyan   can: switch to se...
208
  			seq_printf(m, "t1=%lld ",
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
209
210
211
  					(long long) ktime_to_us(op->kt_ival1));
  
  		if (op->kt_ival2.tv64)
ea00b8e22   Alexey Dobriyan   can: switch to se...
212
  			seq_printf(m, "t2=%lld ",
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
213
  					(long long) ktime_to_us(op->kt_ival2));
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
214

ea00b8e22   Alexey Dobriyan   can: switch to se...
215
216
  		seq_printf(m, "# sent %ld
  ", op->frames_abs);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
217
  	}
ea00b8e22   Alexey Dobriyan   can: switch to se...
218
219
220
221
  	seq_putc(m, '
  ');
  	return 0;
  }
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
222

ea00b8e22   Alexey Dobriyan   can: switch to se...
223
224
225
  static int bcm_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, bcm_proc_show, PDE(inode)->data);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
226
  }
ea00b8e22   Alexey Dobriyan   can: switch to se...
227
228
229
230
231
232
233
  static const struct file_operations bcm_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= bcm_proc_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  /*
   * bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface
   *              of the given bcm tx op
   */
  static void bcm_can_tx(struct bcm_op *op)
  {
  	struct sk_buff *skb;
  	struct net_device *dev;
  	struct can_frame *cf = &op->frames[op->currframe];
  
  	/* no target device? => exit */
  	if (!op->ifindex)
  		return;
  
  	dev = dev_get_by_index(&init_net, op->ifindex);
  	if (!dev) {
  		/* RFC: should this bcm_op remove itself here? */
  		return;
  	}
  
  	skb = alloc_skb(CFSIZ, gfp_any());
  	if (!skb)
  		goto out;
  
  	memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);
  
  	/* send with loopback */
  	skb->dev = dev;
  	skb->sk = op->sk;
  	can_send(skb, 1);
  
  	/* update statistics */
  	op->currframe++;
  	op->frames_abs++;
  
  	/* reached last frame? */
  	if (op->currframe >= op->nframes)
  		op->currframe = 0;
   out:
  	dev_put(dev);
  }
  
  /*
   * bcm_send_to_user - send a BCM message to the userspace
   *                    (consisting of bcm_msg_head + x CAN frames)
   */
  static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
  			     struct can_frame *frames, int has_timestamp)
  {
  	struct sk_buff *skb;
  	struct can_frame *firstframe;
  	struct sockaddr_can *addr;
  	struct sock *sk = op->sk;
5b75c4973   Oliver Hartkopp   can: add limit fo...
287
  	unsigned int datalen = head->nframes * CFSIZ;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
288
289
290
291
292
293
294
295
296
297
  	int err;
  
  	skb = alloc_skb(sizeof(*head) + datalen, gfp_any());
  	if (!skb)
  		return;
  
  	memcpy(skb_put(skb, sizeof(*head)), head, sizeof(*head));
  
  	if (head->nframes) {
  		/* can_frames starting here */
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
298
  		firstframe = (struct can_frame *)skb_tail_pointer(skb);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  
  		memcpy(skb_put(skb, datalen), frames, datalen);
  
  		/*
  		 * the BCM uses the can_dlc-element of the can_frame
  		 * structure for internal purposes. This is only
  		 * relevant for updates that are generated by the
  		 * BCM, where nframes is 1
  		 */
  		if (head->nframes == 1)
  			firstframe->can_dlc &= BCM_CAN_DLC_MASK;
  	}
  
  	if (has_timestamp) {
  		/* restore rx timestamp */
  		skb->tstamp = op->rx_stamp;
  	}
  
  	/*
  	 *  Put the datagram to the queue so that bcm_recvmsg() can
  	 *  get it from there.  We need to pass the interface index to
  	 *  bcm_recvmsg().  We pass a whole struct sockaddr_can in skb->cb
  	 *  containing the interface index.
  	 */
  
  	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_can));
  	addr = (struct sockaddr_can *)skb->cb;
  	memset(addr, 0, sizeof(*addr));
  	addr->can_family  = AF_CAN;
  	addr->can_ifindex = op->rx_ifindex;
  
  	err = sock_queue_rcv_skb(sk, skb);
  	if (err < 0) {
  		struct bcm_sock *bo = bcm_sk(sk);
  
  		kfree_skb(skb);
  		/* don't care about overflows in this statistic */
  		bo->dropped_usr_msgs++;
  	}
  }
12d0d0d3a   Oliver Hartkopp   can bcm: fix inco...
339
340
341
342
343
344
345
346
347
348
349
  static void bcm_tx_start_timer(struct bcm_op *op)
  {
  	if (op->kt_ival1.tv64 && op->count)
  		hrtimer_start(&op->timer,
  			      ktime_add(ktime_get(), op->kt_ival1),
  			      HRTIMER_MODE_ABS);
  	else if (op->kt_ival2.tv64)
  		hrtimer_start(&op->timer,
  			      ktime_add(ktime_get(), op->kt_ival2),
  			      HRTIMER_MODE_ABS);
  }
6e5c172cf   Oliver Hartkopp   can: update can-b...
350
351
352
353
  static void bcm_tx_timeout_tsklet(unsigned long data)
  {
  	struct bcm_op *op = (struct bcm_op *)data;
  	struct bcm_msg_head msg_head;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
354
  	if (op->kt_ival1.tv64 && (op->count > 0)) {
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
355
356
  
  		op->count--;
c53a6ee88   Oliver Hartkopp   can: fix slowpath...
357
358
359
360
361
362
363
364
365
366
367
368
369
  		if (!op->count && (op->flags & TX_COUNTEVT)) {
  
  			/* create notification to user */
  			msg_head.opcode  = TX_EXPIRED;
  			msg_head.flags   = op->flags;
  			msg_head.count   = op->count;
  			msg_head.ival1   = op->ival1;
  			msg_head.ival2   = op->ival2;
  			msg_head.can_id  = op->can_id;
  			msg_head.nframes = 0;
  
  			bcm_send_to_user(op, &msg_head, NULL, 0);
  		}
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
370
  		bcm_can_tx(op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
371

12d0d0d3a   Oliver Hartkopp   can bcm: fix inco...
372
373
  	} else if (op->kt_ival2.tv64)
  		bcm_can_tx(op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
374

12d0d0d3a   Oliver Hartkopp   can bcm: fix inco...
375
  	bcm_tx_start_timer(op);
c53a6ee88   Oliver Hartkopp   can: fix slowpath...
376
377
378
  }
  
  /*
25985edce   Lucas De Marchi   Fix common misspe...
379
   * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions
c53a6ee88   Oliver Hartkopp   can: fix slowpath...
380
381
382
383
384
385
   */
  static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
  {
  	struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
  
  	tasklet_schedule(&op->tsklet);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
386

c53a6ee88   Oliver Hartkopp   can: fix slowpath...
387
  	return HRTIMER_NORESTART;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
388
389
390
391
392
393
394
395
  }
  
  /*
   * bcm_rx_changed - create a RX_CHANGED notification due to changed content
   */
  static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data)
  {
  	struct bcm_msg_head head;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
396
397
398
399
400
401
  	/* update statistics */
  	op->frames_filtered++;
  
  	/* prevent statistics overflow */
  	if (op->frames_filtered > ULONG_MAX/100)
  		op->frames_filtered = op->frames_abs = 0;
6e5c172cf   Oliver Hartkopp   can: update can-b...
402
403
  	/* this element is not throttled anymore */
  	data->can_dlc &= (BCM_CAN_DLC_MASK|RX_RECV);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  	head.opcode  = RX_CHANGED;
  	head.flags   = op->flags;
  	head.count   = op->count;
  	head.ival1   = op->ival1;
  	head.ival2   = op->ival2;
  	head.can_id  = op->can_id;
  	head.nframes = 1;
  
  	bcm_send_to_user(op, &head, data, 1);
  }
  
  /*
   * bcm_rx_update_and_send - process a detected relevant receive content change
   *                          1. update the last received data
   *                          2. send a notification to the user (if possible)
   */
  static void bcm_rx_update_and_send(struct bcm_op *op,
  				   struct can_frame *lastdata,
6e5c172cf   Oliver Hartkopp   can: update can-b...
422
  				   const struct can_frame *rxdata)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
423
  {
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
424
  	memcpy(lastdata, rxdata, CFSIZ);
6e5c172cf   Oliver Hartkopp   can: update can-b...
425
426
  	/* mark as used and throttled by default */
  	lastdata->can_dlc |= (RX_RECV|RX_THR);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
427

6e5c172cf   Oliver Hartkopp   can: update can-b...
428
429
  	/* throtteling mode inactive ? */
  	if (!op->kt_ival2.tv64) {
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
430
  		/* send RX_CHANGED to the user immediately */
6e5c172cf   Oliver Hartkopp   can: update can-b...
431
  		bcm_rx_changed(op, lastdata);
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
432
433
  		return;
  	}
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
434

6e5c172cf   Oliver Hartkopp   can: update can-b...
435
436
  	/* with active throttling timer we are just done here */
  	if (hrtimer_active(&op->thrtimer))
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
437
  		return;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
438

6e5c172cf   Oliver Hartkopp   can: update can-b...
439
440
441
  	/* first receiption with enabled throttling mode */
  	if (!op->kt_lastmsg.tv64)
  		goto rx_changed_settime;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
442

6e5c172cf   Oliver Hartkopp   can: update can-b...
443
  	/* got a second frame inside a potential throttle period? */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
444
445
  	if (ktime_us_delta(ktime_get(), op->kt_lastmsg) <
  	    ktime_to_us(op->kt_ival2)) {
6e5c172cf   Oliver Hartkopp   can: update can-b...
446
  		/* do not send the saved data - only start throttle timer */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
447
448
449
450
451
452
453
  		hrtimer_start(&op->thrtimer,
  			      ktime_add(op->kt_lastmsg, op->kt_ival2),
  			      HRTIMER_MODE_ABS);
  		return;
  	}
  
  	/* the gap was that big, that throttling was not needed here */
6e5c172cf   Oliver Hartkopp   can: update can-b...
454
455
  rx_changed_settime:
  	bcm_rx_changed(op, lastdata);
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
456
  	op->kt_lastmsg = ktime_get();
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
457
458
459
460
461
462
  }
  
  /*
   * bcm_rx_cmp_to_index - (bit)compares the currently received data to formerly
   *                       received data stored in op->last_frames[]
   */
5b75c4973   Oliver Hartkopp   can: add limit fo...
463
  static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index,
6e5c172cf   Oliver Hartkopp   can: update can-b...
464
  				const struct can_frame *rxdata)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  {
  	/*
  	 * no one uses the MSBs of can_dlc for comparation,
  	 * so we use it here to detect the first time of reception
  	 */
  
  	if (!(op->last_frames[index].can_dlc & RX_RECV)) {
  		/* received data for the first time => send update to user */
  		bcm_rx_update_and_send(op, &op->last_frames[index], rxdata);
  		return;
  	}
  
  	/* do a real check in can_frame data section */
  
  	if ((GET_U64(&op->frames[index]) & GET_U64(rxdata)) !=
  	    (GET_U64(&op->frames[index]) & GET_U64(&op->last_frames[index]))) {
  		bcm_rx_update_and_send(op, &op->last_frames[index], rxdata);
  		return;
  	}
  
  	if (op->flags & RX_CHECK_DLC) {
  		/* do a real check in can_frame dlc */
  		if (rxdata->can_dlc != (op->last_frames[index].can_dlc &
  					BCM_CAN_DLC_MASK)) {
  			bcm_rx_update_and_send(op, &op->last_frames[index],
  					       rxdata);
  			return;
  		}
  	}
  }
  
  /*
   * bcm_rx_starttimer - enable timeout monitoring for CAN frame receiption
   */
  static void bcm_rx_starttimer(struct bcm_op *op)
  {
  	if (op->flags & RX_NO_AUTOTIMER)
  		return;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
503
504
  	if (op->kt_ival1.tv64)
  		hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
505
  }
6e5c172cf   Oliver Hartkopp   can: update can-b...
506
  static void bcm_rx_timeout_tsklet(unsigned long data)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
507
  {
6e5c172cf   Oliver Hartkopp   can: update can-b...
508
  	struct bcm_op *op = (struct bcm_op *)data;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
509
  	struct bcm_msg_head msg_head;
6e5c172cf   Oliver Hartkopp   can: update can-b...
510
  	/* create notification to user */
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
511
512
513
514
515
516
517
518
519
  	msg_head.opcode  = RX_TIMEOUT;
  	msg_head.flags   = op->flags;
  	msg_head.count   = op->count;
  	msg_head.ival1   = op->ival1;
  	msg_head.ival2   = op->ival2;
  	msg_head.can_id  = op->can_id;
  	msg_head.nframes = 0;
  
  	bcm_send_to_user(op, &msg_head, NULL, 0);
6e5c172cf   Oliver Hartkopp   can: update can-b...
520
521
522
523
524
525
526
527
528
529
530
  }
  
  /*
   * bcm_rx_timeout_handler - when the (cyclic) CAN frame receiption timed out
   */
  static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
  {
  	struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
  
  	/* schedule before NET_RX_SOFTIRQ */
  	tasklet_hi_schedule(&op->tsklet);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
531
532
533
534
535
536
537
538
  
  	/* no restart of the timer is done here! */
  
  	/* if user wants to be informed, when cyclic CAN-Messages come back */
  	if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
  		/* clear received can_frames to indicate 'nothing received' */
  		memset(op->last_frames, 0, op->nframes * CFSIZ);
  	}
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
539
540
  
  	return HRTIMER_NORESTART;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
541
542
543
  }
  
  /*
6e5c172cf   Oliver Hartkopp   can: update can-b...
544
545
   * bcm_rx_do_flush - helper for bcm_rx_thr_flush
   */
5b75c4973   Oliver Hartkopp   can: add limit fo...
546
547
  static inline int bcm_rx_do_flush(struct bcm_op *op, int update,
  				  unsigned int index)
6e5c172cf   Oliver Hartkopp   can: update can-b...
548
549
550
551
552
553
554
555
556
557
  {
  	if ((op->last_frames) && (op->last_frames[index].can_dlc & RX_THR)) {
  		if (update)
  			bcm_rx_changed(op, &op->last_frames[index]);
  		return 1;
  	}
  	return 0;
  }
  
  /*
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
558
   * bcm_rx_thr_flush - Check for throttled data and send it to the userspace
6e5c172cf   Oliver Hartkopp   can: update can-b...
559
560
561
   *
   * update == 0 : just check if throttled data is available  (any irq context)
   * update == 1 : check and send throttled data to userspace (soft_irq context)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
562
   */
6e5c172cf   Oliver Hartkopp   can: update can-b...
563
  static int bcm_rx_thr_flush(struct bcm_op *op, int update)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
564
  {
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
565
  	int updated = 0;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
566
567
  
  	if (op->nframes > 1) {
5b75c4973   Oliver Hartkopp   can: add limit fo...
568
  		unsigned int i;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
569

ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
570
  		/* for MUX filter we start at index 1 */
6e5c172cf   Oliver Hartkopp   can: update can-b...
571
572
  		for (i = 1; i < op->nframes; i++)
  			updated += bcm_rx_do_flush(op, update, i);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
573
574
575
  
  	} else {
  		/* for RX_FILTER_ID and simple filter */
6e5c172cf   Oliver Hartkopp   can: update can-b...
576
  		updated += bcm_rx_do_flush(op, update, 0);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
577
  	}
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
578
579
580
  
  	return updated;
  }
6e5c172cf   Oliver Hartkopp   can: update can-b...
581
582
583
584
585
586
587
  static void bcm_rx_thr_tsklet(unsigned long data)
  {
  	struct bcm_op *op = (struct bcm_op *)data;
  
  	/* push the changed data to the userspace */
  	bcm_rx_thr_flush(op, 1);
  }
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
588
589
590
591
592
593
594
  /*
   * bcm_rx_thr_handler - the time for blocked content updates is over now:
   *                      Check for throttled data and send it to the userspace
   */
  static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
  {
  	struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
6e5c172cf   Oliver Hartkopp   can: update can-b...
595
596
597
  	tasklet_schedule(&op->thrtsklet);
  
  	if (bcm_rx_thr_flush(op, 0)) {
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
598
599
600
601
602
603
604
  		hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2);
  		return HRTIMER_RESTART;
  	} else {
  		/* rearm throttle handling */
  		op->kt_lastmsg = ktime_set(0, 0);
  		return HRTIMER_NORESTART;
  	}
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
605
606
607
608
609
610
611
612
  }
  
  /*
   * bcm_rx_handler - handle a CAN frame receiption
   */
  static void bcm_rx_handler(struct sk_buff *skb, void *data)
  {
  	struct bcm_op *op = (struct bcm_op *)data;
6e5c172cf   Oliver Hartkopp   can: update can-b...
613
  	const struct can_frame *rxframe = (struct can_frame *)skb->data;
5b75c4973   Oliver Hartkopp   can: add limit fo...
614
  	unsigned int i;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
615
616
  
  	/* disable timeout */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
617
  	hrtimer_cancel(&op->timer);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
618

6e5c172cf   Oliver Hartkopp   can: update can-b...
619
  	if (op->can_id != rxframe->can_id)
1fa17d4ba   Oliver Hartkopp   can: omit unneede...
620
  		return;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
621

6e5c172cf   Oliver Hartkopp   can: update can-b...
622
623
624
625
626
627
  	/* save rx timestamp */
  	op->rx_stamp = skb->tstamp;
  	/* save originator for recvfrom() */
  	op->rx_ifindex = skb->dev->ifindex;
  	/* update statistics */
  	op->frames_abs++;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
628
629
630
631
  
  	if (op->flags & RX_RTR_FRAME) {
  		/* send reply for RTR-request (placed in op->frames[0]) */
  		bcm_can_tx(op);
1fa17d4ba   Oliver Hartkopp   can: omit unneede...
632
  		return;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
633
634
635
636
  	}
  
  	if (op->flags & RX_FILTER_ID) {
  		/* the easiest case */
6e5c172cf   Oliver Hartkopp   can: update can-b...
637
  		bcm_rx_update_and_send(op, &op->last_frames[0], rxframe);
1fa17d4ba   Oliver Hartkopp   can: omit unneede...
638
  		goto rx_starttimer;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
639
640
641
642
  	}
  
  	if (op->nframes == 1) {
  		/* simple compare with index 0 */
6e5c172cf   Oliver Hartkopp   can: update can-b...
643
  		bcm_rx_cmp_to_index(op, 0, rxframe);
1fa17d4ba   Oliver Hartkopp   can: omit unneede...
644
  		goto rx_starttimer;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
645
646
647
648
649
650
651
652
653
654
655
  	}
  
  	if (op->nframes > 1) {
  		/*
  		 * multiplex compare
  		 *
  		 * find the first multiplex mask that fits.
  		 * Remark: The MUX-mask is stored in index 0
  		 */
  
  		for (i = 1; i < op->nframes; i++) {
6e5c172cf   Oliver Hartkopp   can: update can-b...
656
  			if ((GET_U64(&op->frames[0]) & GET_U64(rxframe)) ==
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
657
658
  			    (GET_U64(&op->frames[0]) &
  			     GET_U64(&op->frames[i]))) {
6e5c172cf   Oliver Hartkopp   can: update can-b...
659
  				bcm_rx_cmp_to_index(op, i, rxframe);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
660
661
662
  				break;
  			}
  		}
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
663
  	}
6e5c172cf   Oliver Hartkopp   can: update can-b...
664

1fa17d4ba   Oliver Hartkopp   can: omit unneede...
665
  rx_starttimer:
6e5c172cf   Oliver Hartkopp   can: update can-b...
666
  	bcm_rx_starttimer(op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
  }
  
  /*
   * helpers for bcm_op handling: find & delete bcm [rx|tx] op elements
   */
  static struct bcm_op *bcm_find_op(struct list_head *ops, canid_t can_id,
  				  int ifindex)
  {
  	struct bcm_op *op;
  
  	list_for_each_entry(op, ops, list) {
  		if ((op->can_id == can_id) && (op->ifindex == ifindex))
  			return op;
  	}
  
  	return NULL;
  }
  
  static void bcm_remove_op(struct bcm_op *op)
  {
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
687
688
  	hrtimer_cancel(&op->timer);
  	hrtimer_cancel(&op->thrtimer);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
689

6e5c172cf   Oliver Hartkopp   can: update can-b...
690
691
692
693
694
  	if (op->tsklet.func)
  		tasklet_kill(&op->tsklet);
  
  	if (op->thrtsklet.func)
  		tasklet_kill(&op->thrtsklet);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
695
696
697
698
699
700
701
  	if ((op->frames) && (op->frames != &op->sframe))
  		kfree(op->frames);
  
  	if ((op->last_frames) && (op->last_frames != &op->last_sframe))
  		kfree(op->last_frames);
  
  	kfree(op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
  }
  
  static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
  {
  	if (op->rx_reg_dev == dev) {
  		can_rx_unregister(dev, op->can_id, REGMASK(op->can_id),
  				  bcm_rx_handler, op);
  
  		/* mark as removed subscription */
  		op->rx_reg_dev = NULL;
  	} else
  		printk(KERN_ERR "can-bcm: bcm_rx_unreg: registered device "
  		       "mismatch %p %p
  ", op->rx_reg_dev, dev);
  }
  
  /*
   * bcm_delete_rx_op - find and remove a rx op (returns number of removed ops)
   */
  static int bcm_delete_rx_op(struct list_head *ops, canid_t can_id, int ifindex)
  {
  	struct bcm_op *op, *n;
  
  	list_for_each_entry_safe(op, n, ops, list) {
  		if ((op->can_id == can_id) && (op->ifindex == ifindex)) {
  
  			/*
  			 * Don't care if we're bound or not (due to netdev
  			 * problems) can_rx_unregister() is always a save
  			 * thing to do here.
  			 */
  			if (op->ifindex) {
  				/*
  				 * Only remove subscriptions that had not
  				 * been removed due to NETDEV_UNREGISTER
  				 * in bcm_notifier()
  				 */
  				if (op->rx_reg_dev) {
  					struct net_device *dev;
  
  					dev = dev_get_by_index(&init_net,
  							       op->ifindex);
  					if (dev) {
  						bcm_rx_unreg(dev, op);
  						dev_put(dev);
  					}
  				}
  			} else
  				can_rx_unregister(NULL, op->can_id,
  						  REGMASK(op->can_id),
  						  bcm_rx_handler, op);
  
  			list_del(&op->list);
  			bcm_remove_op(op);
  			return 1; /* done */
  		}
  	}
  
  	return 0; /* not found */
  }
  
  /*
   * bcm_delete_tx_op - find and remove a tx op (returns number of removed ops)
   */
  static int bcm_delete_tx_op(struct list_head *ops, canid_t can_id, int ifindex)
  {
  	struct bcm_op *op, *n;
  
  	list_for_each_entry_safe(op, n, ops, list) {
  		if ((op->can_id == can_id) && (op->ifindex == ifindex)) {
  			list_del(&op->list);
  			bcm_remove_op(op);
  			return 1; /* done */
  		}
  	}
  
  	return 0; /* not found */
  }
  
  /*
   * bcm_read_op - read out a bcm_op and send it to the user (for bcm_sendmsg)
   */
  static int bcm_read_op(struct list_head *ops, struct bcm_msg_head *msg_head,
  		       int ifindex)
  {
  	struct bcm_op *op = bcm_find_op(ops, msg_head->can_id, ifindex);
  
  	if (!op)
  		return -EINVAL;
  
  	/* put current values into msg_head */
  	msg_head->flags   = op->flags;
  	msg_head->count   = op->count;
  	msg_head->ival1   = op->ival1;
  	msg_head->ival2   = op->ival2;
  	msg_head->nframes = op->nframes;
  
  	bcm_send_to_user(op, msg_head, op->frames, 0);
  
  	return MHSIZ;
  }
  
  /*
   * bcm_tx_setup - create or update a bcm tx op (for bcm_sendmsg)
   */
  static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
  			int ifindex, struct sock *sk)
  {
  	struct bcm_sock *bo = bcm_sk(sk);
  	struct bcm_op *op;
5b75c4973   Oliver Hartkopp   can: add limit fo...
812
813
  	unsigned int i;
  	int err;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
814
815
816
817
  
  	/* we need a real device to send frames */
  	if (!ifindex)
  		return -ENODEV;
5b75c4973   Oliver Hartkopp   can: add limit fo...
818
819
  	/* check nframes boundaries - we need at least one can_frame */
  	if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES)
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  		return -EINVAL;
  
  	/* check the given can_id */
  	op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex);
  
  	if (op) {
  		/* update existing BCM operation */
  
  		/*
  		 * Do we need more space for the can_frames than currently
  		 * allocated? -> This is a _really_ unusual use-case and
  		 * therefore (complexity / locking) it is not supported.
  		 */
  		if (msg_head->nframes > op->nframes)
  			return -E2BIG;
  
  		/* update can_frames content */
  		for (i = 0; i < msg_head->nframes; i++) {
  			err = memcpy_fromiovec((u8 *)&op->frames[i],
  					       msg->msg_iov, CFSIZ);
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
840
841
842
  
  			if (op->frames[i].can_dlc > 8)
  				err = -EINVAL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
  			if (err < 0)
  				return err;
  
  			if (msg_head->flags & TX_CP_CAN_ID) {
  				/* copy can_id into frame */
  				op->frames[i].can_id = msg_head->can_id;
  			}
  		}
  
  	} else {
  		/* insert new BCM operation for the given can_id */
  
  		op = kzalloc(OPSIZ, GFP_KERNEL);
  		if (!op)
  			return -ENOMEM;
  
  		op->can_id    = msg_head->can_id;
  
  		/* create array for can_frames and copy the data */
  		if (msg_head->nframes > 1) {
  			op->frames = kmalloc(msg_head->nframes * CFSIZ,
  					     GFP_KERNEL);
  			if (!op->frames) {
  				kfree(op);
  				return -ENOMEM;
  			}
  		} else
  			op->frames = &op->sframe;
  
  		for (i = 0; i < msg_head->nframes; i++) {
  			err = memcpy_fromiovec((u8 *)&op->frames[i],
  					       msg->msg_iov, CFSIZ);
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
875
876
877
  
  			if (op->frames[i].can_dlc > 8)
  				err = -EINVAL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
  			if (err < 0) {
  				if (op->frames != &op->sframe)
  					kfree(op->frames);
  				kfree(op);
  				return err;
  			}
  
  			if (msg_head->flags & TX_CP_CAN_ID) {
  				/* copy can_id into frame */
  				op->frames[i].can_id = msg_head->can_id;
  			}
  		}
  
  		/* tx_ops never compare with previous received messages */
  		op->last_frames = NULL;
  
  		/* bcm_can_tx / bcm_tx_timeout_handler needs this */
  		op->sk = sk;
  		op->ifindex = ifindex;
  
  		/* initialize uninitialized (kzalloc) structure */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
899
900
  		hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  		op->timer.function = bcm_tx_timeout_handler;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
901

6e5c172cf   Oliver Hartkopp   can: update can-b...
902
903
904
  		/* initialize tasklet for tx countevent notification */
  		tasklet_init(&op->tsklet, bcm_tx_timeout_tsklet,
  			     (unsigned long) op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
905
  		/* currently unused in tx_ops */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
906
  		hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
  
  		/* add this bcm_op to the list of the tx_ops */
  		list_add(&op->list, &bo->tx_ops);
  
  	} /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */
  
  	if (op->nframes != msg_head->nframes) {
  		op->nframes   = msg_head->nframes;
  		/* start multiple frame transmission with index 0 */
  		op->currframe = 0;
  	}
  
  	/* check flags */
  
  	op->flags = msg_head->flags;
  
  	if (op->flags & TX_RESET_MULTI_IDX) {
  		/* start multiple frame transmission with index 0 */
  		op->currframe = 0;
  	}
  
  	if (op->flags & SETTIMER) {
  		/* set timer values */
  		op->count = msg_head->count;
  		op->ival1 = msg_head->ival1;
  		op->ival2 = msg_head->ival2;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
933
934
  		op->kt_ival1 = timeval_to_ktime(msg_head->ival1);
  		op->kt_ival2 = timeval_to_ktime(msg_head->ival2);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
935
936
  
  		/* disable an active timer due to zero values? */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
937
938
  		if (!op->kt_ival1.tv64 && !op->kt_ival2.tv64)
  			hrtimer_cancel(&op->timer);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
939
  	}
12d0d0d3a   Oliver Hartkopp   can bcm: fix inco...
940
941
  	if (op->flags & STARTTIMER) {
  		hrtimer_cancel(&op->timer);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
942
943
  		/* spec: send can_frame when starting timer */
  		op->flags |= TX_ANNOUNCE;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
944
  	}
aabdcb0b5   Oliver Hartkopp   can bcm: fix tx_s...
945
  	if (op->flags & TX_ANNOUNCE) {
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
946
  		bcm_can_tx(op);
12d0d0d3a   Oliver Hartkopp   can bcm: fix inco...
947
  		if (op->count)
aabdcb0b5   Oliver Hartkopp   can bcm: fix tx_s...
948
949
  			op->count--;
  	}
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
950

12d0d0d3a   Oliver Hartkopp   can bcm: fix inco...
951
952
  	if (op->flags & STARTTIMER)
  		bcm_tx_start_timer(op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  	return msg_head->nframes * CFSIZ + MHSIZ;
  }
  
  /*
   * bcm_rx_setup - create or update a bcm rx op (for bcm_sendmsg)
   */
  static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
  			int ifindex, struct sock *sk)
  {
  	struct bcm_sock *bo = bcm_sk(sk);
  	struct bcm_op *op;
  	int do_rx_register;
  	int err = 0;
  
  	if ((msg_head->flags & RX_FILTER_ID) || (!(msg_head->nframes))) {
  		/* be robust against wrong usage ... */
  		msg_head->flags |= RX_FILTER_ID;
  		/* ignore trailing garbage */
  		msg_head->nframes = 0;
  	}
5b75c4973   Oliver Hartkopp   can: add limit fo...
973
974
975
  	/* the first element contains the mux-mask => MAX_NFRAMES + 1  */
  	if (msg_head->nframes > MAX_NFRAMES + 1)
  		return -EINVAL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
  	if ((msg_head->flags & RX_RTR_FRAME) &&
  	    ((msg_head->nframes != 1) ||
  	     (!(msg_head->can_id & CAN_RTR_FLAG))))
  		return -EINVAL;
  
  	/* check the given can_id */
  	op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex);
  	if (op) {
  		/* update existing BCM operation */
  
  		/*
  		 * Do we need more space for the can_frames than currently
  		 * allocated? -> This is a _really_ unusual use-case and
  		 * therefore (complexity / locking) it is not supported.
  		 */
  		if (msg_head->nframes > op->nframes)
  			return -E2BIG;
  
  		if (msg_head->nframes) {
  			/* update can_frames content */
  			err = memcpy_fromiovec((u8 *)op->frames,
  					       msg->msg_iov,
  					       msg_head->nframes * CFSIZ);
  			if (err < 0)
  				return err;
  
  			/* clear last_frames to indicate 'nothing received' */
  			memset(op->last_frames, 0, msg_head->nframes * CFSIZ);
  		}
  
  		op->nframes = msg_head->nframes;
  
  		/* Only an update -> do not call can_rx_register() */
  		do_rx_register = 0;
  
  	} else {
  		/* insert new BCM operation for the given can_id */
  		op = kzalloc(OPSIZ, GFP_KERNEL);
  		if (!op)
  			return -ENOMEM;
  
  		op->can_id    = msg_head->can_id;
  		op->nframes   = msg_head->nframes;
  
  		if (msg_head->nframes > 1) {
  			/* create array for can_frames and copy the data */
  			op->frames = kmalloc(msg_head->nframes * CFSIZ,
  					     GFP_KERNEL);
  			if (!op->frames) {
  				kfree(op);
  				return -ENOMEM;
  			}
  
  			/* create and init array for received can_frames */
  			op->last_frames = kzalloc(msg_head->nframes * CFSIZ,
  						  GFP_KERNEL);
  			if (!op->last_frames) {
  				kfree(op->frames);
  				kfree(op);
  				return -ENOMEM;
  			}
  
  		} else {
  			op->frames = &op->sframe;
  			op->last_frames = &op->last_sframe;
  		}
  
  		if (msg_head->nframes) {
  			err = memcpy_fromiovec((u8 *)op->frames, msg->msg_iov,
  					       msg_head->nframes * CFSIZ);
  			if (err < 0) {
  				if (op->frames != &op->sframe)
  					kfree(op->frames);
  				if (op->last_frames != &op->last_sframe)
  					kfree(op->last_frames);
  				kfree(op);
  				return err;
  			}
  		}
  
  		/* bcm_can_tx / bcm_tx_timeout_handler needs this */
  		op->sk = sk;
  		op->ifindex = ifindex;
  
  		/* initialize uninitialized (kzalloc) structure */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1061
1062
  		hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  		op->timer.function = bcm_rx_timeout_handler;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1063

6e5c172cf   Oliver Hartkopp   can: update can-b...
1064
1065
1066
  		/* initialize tasklet for rx timeout notification */
  		tasklet_init(&op->tsklet, bcm_rx_timeout_tsklet,
  			     (unsigned long) op);
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1067
1068
  		hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  		op->thrtimer.function = bcm_rx_thr_handler;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1069

6e5c172cf   Oliver Hartkopp   can: update can-b...
1070
1071
1072
  		/* initialize tasklet for rx throttle handling */
  		tasklet_init(&op->thrtsklet, bcm_rx_thr_tsklet,
  			     (unsigned long) op);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  		/* add this bcm_op to the list of the rx_ops */
  		list_add(&op->list, &bo->rx_ops);
  
  		/* call can_rx_register() */
  		do_rx_register = 1;
  
  	} /* if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) */
  
  	/* check flags */
  	op->flags = msg_head->flags;
  
  	if (op->flags & RX_RTR_FRAME) {
  
  		/* no timers in RTR-mode */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1087
1088
  		hrtimer_cancel(&op->thrtimer);
  		hrtimer_cancel(&op->timer);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  
  		/*
  		 * funny feature in RX(!)_SETUP only for RTR-mode:
  		 * copy can_id into frame BUT without RTR-flag to
  		 * prevent a full-load-loopback-test ... ;-]
  		 */
  		if ((op->flags & TX_CP_CAN_ID) ||
  		    (op->frames[0].can_id == op->can_id))
  			op->frames[0].can_id = op->can_id & ~CAN_RTR_FLAG;
  
  	} else {
  		if (op->flags & SETTIMER) {
  
  			/* set timer value */
  			op->ival1 = msg_head->ival1;
  			op->ival2 = msg_head->ival2;
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1105
1106
  			op->kt_ival1 = timeval_to_ktime(msg_head->ival1);
  			op->kt_ival2 = timeval_to_ktime(msg_head->ival2);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1107
1108
  
  			/* disable an active timer due to zero value? */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1109
1110
  			if (!op->kt_ival1.tv64)
  				hrtimer_cancel(&op->timer);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1111
1112
  
  			/*
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1113
1114
  			 * In any case cancel the throttle timer, flush
  			 * potentially blocked msgs and reset throttle handling
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1115
  			 */
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1116
1117
  			op->kt_lastmsg = ktime_set(0, 0);
  			hrtimer_cancel(&op->thrtimer);
6e5c172cf   Oliver Hartkopp   can: update can-b...
1118
  			bcm_rx_thr_flush(op, 1);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1119
  		}
73e87e02e   Oliver Hartkopp   CAN: use hrtimers...
1120
1121
1122
  		if ((op->flags & STARTTIMER) && op->kt_ival1.tv64)
  			hrtimer_start(&op->timer, op->kt_ival1,
  				      HRTIMER_MODE_REL);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
  	}
  
  	/* now we can register for can_ids, if we added a new bcm_op */
  	if (do_rx_register) {
  		if (ifindex) {
  			struct net_device *dev;
  
  			dev = dev_get_by_index(&init_net, ifindex);
  			if (dev) {
  				err = can_rx_register(dev, op->can_id,
  						      REGMASK(op->can_id),
  						      bcm_rx_handler, op,
  						      "bcm");
  
  				op->rx_reg_dev = dev;
  				dev_put(dev);
  			}
  
  		} else
  			err = can_rx_register(NULL, op->can_id,
  					      REGMASK(op->can_id),
  					      bcm_rx_handler, op, "bcm");
  		if (err) {
  			/* this bcm rx op is broken -> remove it */
  			list_del(&op->list);
  			bcm_remove_op(op);
  			return err;
  		}
  	}
  
  	return msg_head->nframes * CFSIZ + MHSIZ;
  }
  
  /*
   * bcm_tx_send - send a single CAN frame to the CAN interface (for bcm_sendmsg)
   */
  static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
  {
  	struct sk_buff *skb;
  	struct net_device *dev;
  	int err;
  
  	/* we need a real device to send frames */
  	if (!ifindex)
  		return -ENODEV;
  
  	skb = alloc_skb(CFSIZ, GFP_KERNEL);
  
  	if (!skb)
  		return -ENOMEM;
  
  	err = memcpy_fromiovec(skb_put(skb, CFSIZ), msg->msg_iov, CFSIZ);
  	if (err < 0) {
  		kfree_skb(skb);
  		return err;
  	}
  
  	dev = dev_get_by_index(&init_net, ifindex);
  	if (!dev) {
  		kfree_skb(skb);
  		return -ENODEV;
  	}
  
  	skb->dev = dev;
  	skb->sk  = sk;
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
1188
  	err = can_send(skb, 1); /* send with loopback */
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1189
  	dev_put(dev);
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
1190
1191
  	if (err)
  		return err;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  	return CFSIZ + MHSIZ;
  }
  
  /*
   * bcm_sendmsg - process BCM commands (opcodes) from the userspace
   */
  static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
  		       struct msghdr *msg, size_t size)
  {
  	struct sock *sk = sock->sk;
  	struct bcm_sock *bo = bcm_sk(sk);
  	int ifindex = bo->ifindex; /* default ifindex for this bcm_op */
  	struct bcm_msg_head msg_head;
  	int ret; /* read bytes or error codes as return value */
  
  	if (!bo->bound)
  		return -ENOTCONN;
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
1209
1210
1211
  	/* check for valid message length from userspace */
  	if (size < MHSIZ || (size - MHSIZ) % CFSIZ)
  		return -EINVAL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1212
1213
1214
1215
1216
1217
  	/* check for alternative ifindex for this bcm_op */
  
  	if (!ifindex && msg->msg_name) {
  		/* no bound device as default => check msg_name */
  		struct sockaddr_can *addr =
  			(struct sockaddr_can *)msg->msg_name;
5e5073280   Kurt Van Dijck   can: test size of...
1218
1219
  		if (msg->msg_namelen < sizeof(*addr))
  			return -EINVAL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
  		if (addr->can_family != AF_CAN)
  			return -EINVAL;
  
  		/* ifindex from sendto() */
  		ifindex = addr->can_ifindex;
  
  		if (ifindex) {
  			struct net_device *dev;
  
  			dev = dev_get_by_index(&init_net, ifindex);
  			if (!dev)
  				return -ENODEV;
  
  			if (dev->type != ARPHRD_CAN) {
  				dev_put(dev);
  				return -ENODEV;
  			}
  
  			dev_put(dev);
  		}
  	}
  
  	/* read message head information */
  
  	ret = memcpy_fromiovec((u8 *)&msg_head, msg->msg_iov, MHSIZ);
  	if (ret < 0)
  		return ret;
  
  	lock_sock(sk);
  
  	switch (msg_head.opcode) {
  
  	case TX_SETUP:
  		ret = bcm_tx_setup(&msg_head, msg, ifindex, sk);
  		break;
  
  	case RX_SETUP:
  		ret = bcm_rx_setup(&msg_head, msg, ifindex, sk);
  		break;
  
  	case TX_DELETE:
  		if (bcm_delete_tx_op(&bo->tx_ops, msg_head.can_id, ifindex))
  			ret = MHSIZ;
  		else
  			ret = -EINVAL;
  		break;
  
  	case RX_DELETE:
  		if (bcm_delete_rx_op(&bo->rx_ops, msg_head.can_id, ifindex))
  			ret = MHSIZ;
  		else
  			ret = -EINVAL;
  		break;
  
  	case TX_READ:
  		/* reuse msg_head for the reply to TX_READ */
  		msg_head.opcode  = TX_STATUS;
  		ret = bcm_read_op(&bo->tx_ops, &msg_head, ifindex);
  		break;
  
  	case RX_READ:
  		/* reuse msg_head for the reply to RX_READ */
  		msg_head.opcode  = RX_STATUS;
  		ret = bcm_read_op(&bo->rx_ops, &msg_head, ifindex);
  		break;
  
  	case TX_SEND:
7f2d38eb7   Oliver Hartkopp   can: add sanity c...
1287
1288
  		/* we need exactly one can_frame behind the msg head */
  		if ((msg_head.nframes != 1) || (size != CFSIZ + MHSIZ))
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  			ret = -EINVAL;
  		else
  			ret = bcm_tx_send(msg, ifindex, sk);
  		break;
  
  	default:
  		ret = -EINVAL;
  		break;
  	}
  
  	release_sock(sk);
  
  	return ret;
  }
  
  /*
   * notification handler for netdevice status changes
   */
  static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
  			void *data)
  {
  	struct net_device *dev = (struct net_device *)data;
  	struct bcm_sock *bo = container_of(nb, struct bcm_sock, notifier);
  	struct sock *sk = &bo->sk;
  	struct bcm_op *op;
  	int notify_enodev = 0;
721499e89   YOSHIFUJI Hideaki   netns: Use net_eq...
1315
  	if (!net_eq(dev_net(dev), &init_net))
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
  		return NOTIFY_DONE;
  
  	if (dev->type != ARPHRD_CAN)
  		return NOTIFY_DONE;
  
  	switch (msg) {
  
  	case NETDEV_UNREGISTER:
  		lock_sock(sk);
  
  		/* remove device specific receive entries */
  		list_for_each_entry(op, &bo->rx_ops, list)
  			if (op->rx_reg_dev == dev)
  				bcm_rx_unreg(dev, op);
  
  		/* remove device reference, if this is our bound device */
  		if (bo->bound && bo->ifindex == dev->ifindex) {
  			bo->bound   = 0;
  			bo->ifindex = 0;
  			notify_enodev = 1;
  		}
  
  		release_sock(sk);
  
  		if (notify_enodev) {
  			sk->sk_err = ENODEV;
  			if (!sock_flag(sk, SOCK_DEAD))
  				sk->sk_error_report(sk);
  		}
  		break;
  
  	case NETDEV_DOWN:
  		if (bo->bound && bo->ifindex == dev->ifindex) {
  			sk->sk_err = ENETDOWN;
  			if (!sock_flag(sk, SOCK_DEAD))
  				sk->sk_error_report(sk);
  		}
  	}
  
  	return NOTIFY_DONE;
  }
  
  /*
   * initial settings for all BCM sockets to be set at socket creation time
   */
  static int bcm_init(struct sock *sk)
  {
  	struct bcm_sock *bo = bcm_sk(sk);
  
  	bo->bound            = 0;
  	bo->ifindex          = 0;
  	bo->dropped_usr_msgs = 0;
  	bo->bcm_proc_read    = NULL;
  
  	INIT_LIST_HEAD(&bo->tx_ops);
  	INIT_LIST_HEAD(&bo->rx_ops);
  
  	/* set notifier */
  	bo->notifier.notifier_call = bcm_notifier;
  
  	register_netdevice_notifier(&bo->notifier);
  
  	return 0;
  }
  
  /*
   * standard socket functions
   */
  static int bcm_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
c6914a6f2   Dave Jones   can: Add missing ...
1387
  	struct bcm_sock *bo;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1388
  	struct bcm_op *op, *next;
c6914a6f2   Dave Jones   can: Add missing ...
1389
1390
1391
1392
  	if (sk == NULL)
  		return 0;
  
  	bo = bcm_sk(sk);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
  	/* remove bcm_ops, timer, rx_unregister(), etc. */
  
  	unregister_netdevice_notifier(&bo->notifier);
  
  	lock_sock(sk);
  
  	list_for_each_entry_safe(op, next, &bo->tx_ops, list)
  		bcm_remove_op(op);
  
  	list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
  		/*
  		 * Don't care if we're bound or not (due to netdev problems)
  		 * can_rx_unregister() is always a save thing to do here.
  		 */
  		if (op->ifindex) {
  			/*
  			 * Only remove subscriptions that had not
  			 * been removed due to NETDEV_UNREGISTER
  			 * in bcm_notifier()
  			 */
  			if (op->rx_reg_dev) {
  				struct net_device *dev;
  
  				dev = dev_get_by_index(&init_net, op->ifindex);
  				if (dev) {
  					bcm_rx_unreg(dev, op);
  					dev_put(dev);
  				}
  			}
  		} else
  			can_rx_unregister(NULL, op->can_id,
  					  REGMASK(op->can_id),
  					  bcm_rx_handler, op);
  
  		bcm_remove_op(op);
  	}
  
  	/* remove procfs entry */
  	if (proc_dir && bo->bcm_proc_read)
  		remove_proc_entry(bo->procname, proc_dir);
  
  	/* remove device reference */
  	if (bo->bound) {
  		bo->bound   = 0;
  		bo->ifindex = 0;
  	}
f7e5cc0c4   Lothar Waßmann   net/can bugfix: u...
1439
1440
  	sock_orphan(sk);
  	sock->sk = NULL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
  	release_sock(sk);
  	sock_put(sk);
  
  	return 0;
  }
  
  static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
  		       int flags)
  {
  	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
  	struct sock *sk = sock->sk;
  	struct bcm_sock *bo = bcm_sk(sk);
6503d9616   Changli Gao   net: check the le...
1453
1454
  	if (len < sizeof(*addr))
  		return -EINVAL;
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  	if (bo->bound)
  		return -EISCONN;
  
  	/* bind a device to this socket */
  	if (addr->can_ifindex) {
  		struct net_device *dev;
  
  		dev = dev_get_by_index(&init_net, addr->can_ifindex);
  		if (!dev)
  			return -ENODEV;
  
  		if (dev->type != ARPHRD_CAN) {
  			dev_put(dev);
  			return -ENODEV;
  		}
  
  		bo->ifindex = dev->ifindex;
  		dev_put(dev);
  
  	} else {
  		/* no interface reference for ifindex = 0 ('any' CAN device) */
  		bo->ifindex = 0;
  	}
  
  	bo->bound = 1;
  
  	if (proc_dir) {
  		/* unique socket address as filename */
9f260e0ef   Dan Rosenberg   CAN: Use inode in...
1483
  		sprintf(bo->procname, "%lu", sock_i_ino(sk));
ea00b8e22   Alexey Dobriyan   can: switch to se...
1484
1485
1486
  		bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
  						     proc_dir,
  						     &bcm_proc_fops, sk);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  	}
  
  	return 0;
  }
  
  static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
  		       struct msghdr *msg, size_t size, int flags)
  {
  	struct sock *sk = sock->sk;
  	struct sk_buff *skb;
  	int error = 0;
  	int noblock;
  	int err;
  
  	noblock =  flags & MSG_DONTWAIT;
  	flags   &= ~MSG_DONTWAIT;
  	skb = skb_recv_datagram(sk, flags, noblock, &error);
  	if (!skb)
  		return error;
  
  	if (skb->len < size)
  		size = skb->len;
  
  	err = memcpy_toiovec(msg->msg_iov, skb->data, size);
  	if (err < 0) {
  		skb_free_datagram(sk, skb);
  		return err;
  	}
3b885787e   Neil Horman   net: Generalize s...
1515
  	sock_recv_ts_and_drops(msg, sk, skb);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
  
  	if (msg->msg_name) {
  		msg->msg_namelen = sizeof(struct sockaddr_can);
  		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
  	}
  
  	skb_free_datagram(sk, skb);
  
  	return size;
  }
53914b679   Oliver Hartkopp   can: make struct ...
1526
  static const struct proto_ops bcm_ops = {
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1527
1528
1529
1530
1531
1532
1533
1534
  	.family        = PF_CAN,
  	.release       = bcm_release,
  	.bind          = sock_no_bind,
  	.connect       = bcm_connect,
  	.socketpair    = sock_no_socketpair,
  	.accept        = sock_no_accept,
  	.getname       = sock_no_getname,
  	.poll          = datagram_poll,
53914b679   Oliver Hartkopp   can: make struct ...
1535
  	.ioctl         = can_ioctl,	/* use can_ioctl() from af_can.c */
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
  	.listen        = sock_no_listen,
  	.shutdown      = sock_no_shutdown,
  	.setsockopt    = sock_no_setsockopt,
  	.getsockopt    = sock_no_getsockopt,
  	.sendmsg       = bcm_sendmsg,
  	.recvmsg       = bcm_recvmsg,
  	.mmap          = sock_no_mmap,
  	.sendpage      = sock_no_sendpage,
  };
  
  static struct proto bcm_proto __read_mostly = {
  	.name       = "CAN_BCM",
  	.owner      = THIS_MODULE,
  	.obj_size   = sizeof(struct bcm_sock),
  	.init       = bcm_init,
  };
1650629d1   Kurt Van Dijck   can: make struct ...
1552
  static const struct can_proto bcm_can_proto = {
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1553
1554
  	.type       = SOCK_DGRAM,
  	.protocol   = CAN_BCM,
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
  	.ops        = &bcm_ops,
  	.prot       = &bcm_proto,
  };
  
  static int __init bcm_module_init(void)
  {
  	int err;
  
  	printk(banner);
  
  	err = can_proto_register(&bcm_can_proto);
  	if (err < 0) {
  		printk(KERN_ERR "can: registration of bcm protocol failed
  ");
  		return err;
  	}
  
  	/* create /proc/net/can-bcm directory */
  	proc_dir = proc_mkdir("can-bcm", init_net.proc_net);
ffd980f97   Oliver Hartkopp   [CAN]: Add broadc...
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
  	return 0;
  }
  
  static void __exit bcm_module_exit(void)
  {
  	can_proto_unregister(&bcm_can_proto);
  
  	if (proc_dir)
  		proc_net_remove(&init_net, "can-bcm");
  }
  
  module_init(bcm_module_init);
  module_exit(bcm_module_exit);