- }
- } else {
- /* op->frames = NULL due to memset in kzalloc() */
-
- /*
- * even when we have the RX_FILTER_ID case, we need
- * to store the last frame for the throttle feature
- */
-
- /* create and init array for received can_frames */
- op->last_frames = kzalloc(CFSIZ, GFP_KERNEL);
- if (!op->last_frames) {
- kfree(op);
- return -ENOMEM;
- }
- }
-
- op->sk = sk; /* bcm_delete_rx_op() needs this */
- op->ifindex = ifindex;
-
- /* initialize uninitialized (kmalloc) structure */
- init_timer(&op->timer);
-
- /* init throttle timer for RX_CHANGED */
- init_timer(&op->thrtimer);
-
- /* handler for rx timeouts */
- op->timer.function = bcm_rx_timeout_handler;
-
- /* timer.data points to this op-structure */
- op->timer.data = (unsigned long)op;
-
- /* handler for RX_CHANGED throttle timeouts */
- op->thrtimer.function = bcm_rx_thr_handler;
-
- /* timer.data points to this op-structure */
- op->thrtimer.data = (unsigned long)op;
-
- op->thrtimer.expires = 0; /* mark disabled timer */
-
- /* add this bcm_op to the list of the tx_ops */
- list_add(&op->list, &bo->rx_ops);
-
- do_rx_register = 1; /* call can_rx_register() */
-
- } /* 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 */
- del_timer(&op->thrtimer);
- del_timer(&op->timer);
-
- /*
- * 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;
- op->j_ival1 = timeval2jiffies(&msg_head->ival1, 1);
- op->j_ival2 = timeval2jiffies(&msg_head->ival2, 1);
-
- DBG("RX_SETUP: SETTIMER j_ival1=%ld j_ival2=%ld\n",
- op->j_ival1, op->j_ival2);
-
- /* disable an active timer due to zero value? */
- if (!op->j_ival1) {
- del_timer(&op->timer);
- DBG("RX_SETUP: disabled timer rx timeouts.\n");
- }
-
- /* free currently blocked msgs ? */
- if (op->thrtimer.expires) {
- DBG("RX_SETUP: unblocking throttled msgs.\n");
- del_timer(&op->thrtimer);
- /* send blocked msgs hereafter */
- op->thrtimer.expires = jiffies + 2;
- add_timer(&op->thrtimer);
- }
- /*
- * if (op->j_ival2) is zero, no (new) throttling
- * will happen. For details see functions
- * bcm_rx_update_and_send() and bcm_rx_thr_handler()
- */
- }
-
- if ((op->flags & STARTTIMER) && op->j_ival1) {
-
- del_timer(&op->timer);
-
- op->timer.expires = jiffies + op->j_ival1;
-
- DBG("RX_SETUP: adding timer ival1. func=%p data=%p"
- " exp=0x%08X\n",
- (char *) op->timer.function,
- (char *) op->timer.data,
- (unsigned int) op->timer.expires);
-
- add_timer(&op->timer);
- }
- }
-
- /* now we can register for can_ids, if we added a new bcm_op */
- if (do_rx_register) {
- DBG("RX_SETUP: can_rx_register() for can_id %03X. "
- "rx_op is %p\n", op->can_id, op);
-
- if (ifindex) {
- struct net_device *dev = dev_get_by_index(ifindex);
-
- if (dev) {
- can_rx_register(dev, op->can_id,
- REGMASK(op->can_id),
- bcm_rx_handler, op, IDENT);
- dev_put(dev);
- }
- } else
- can_rx_register(NULL, op->can_id, REGMASK(op->can_id),
- bcm_rx_handler, op, IDENT);
- }
-
- return msg_head->nframes * CFSIZ + MHSIZ;
-}
-
-static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
-{
- struct sk_buff *skb;
- struct net_device *dev;
- int err;
-
- /* just copy and send one can_frame */
-
- if (!ifindex) /* we need a real device to send frames */
- 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;
- }
-
- DBG_FRAME("BCM: TX_SEND: sending frame",
- (struct can_frame *)skb->data);
-
- dev = dev_get_by_index(ifindex);
- if (!dev) {
- kfree_skb(skb);
- return -ENODEV;
- }
-
- skb->dev = dev;
- skb->sk = sk;
- can_send(skb, 1); /* send with loopback */
- dev_put(dev);
-
- return CFSIZ + MHSIZ;
-}
-
-static int bcm_read_op(struct list_head *ops, struct bcm_msg_head *msg_head,
- int ifindex)
-{
- struct bcm_op *op;
- int ret;
-
- op = bcm_find_op(ops, msg_head->can_id, ifindex);
- if (op) {
-
- DBG("TRX_READ: sending status for can_id %03X\n",
- msg_head->can_id);
- /* 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, NULL);
-
- ret = MHSIZ;
-
- } else {
-
- DBG("TRX_READ: did not find op for can_id %03X\n",
- msg_head->can_id);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/* procfs functions */
-
-static char *bcm_proc_getifname(int ifindex)
-{
- struct net_device *dev;
-
- if (!ifindex)
- return "any";
-
- dev = __dev_get_by_index(ifindex); /* no usage counting */
- if (dev)
- return dev->name;
-
- return "???";
-}
-
-static int bcm_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = 0;
- struct sock *sk = (struct sock *)data;
- struct bcm_opt *bo = bcm_sk(sk);
- struct bcm_op *op;
-
- len += snprintf(page + len, PAGE_SIZE - len, ">>> socket %p",
- sk->sk_socket);
- len += snprintf(page + len, PAGE_SIZE - len, " / sk %p", sk);
- len += snprintf(page + len, PAGE_SIZE - len, " / bo %p", bo);
- len += snprintf(page + len, PAGE_SIZE - len, " / dropped %lu",
- bo->dropped_usr_msgs);
- len += snprintf(page + len, PAGE_SIZE - len, " / bound %s",
- bcm_proc_getifname(bo->ifindex));
- len += snprintf(page + len, PAGE_SIZE - len, " <<<\n");
-
- 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;
-
- len += snprintf(page + len, PAGE_SIZE - len,
- "rx_op: %03X %-5s ",
- op->can_id, bcm_proc_getifname(op->ifindex));
- len += snprintf(page + len, PAGE_SIZE - len, "[%d]%c ",
- op->nframes,
- (op->flags & RX_CHECK_DLC)?'d':' ');
- if (op->j_ival1)
- len += snprintf(page + len, PAGE_SIZE - len,
- "timeo=%ld ", op->j_ival1);
-
- if (op->j_ival2)
- len += snprintf(page + len, PAGE_SIZE - len,
- "thr=%ld ", op->j_ival2);
-
- len += snprintf(page + len, PAGE_SIZE - len,
- "# recv %ld (%ld) => reduction: ",
- op->frames_filtered, op->frames_abs);
-
- reduction = 100 - (op->frames_filtered * 100) / op->frames_abs;
-
- len += snprintf(page + len, PAGE_SIZE - len, "%s%ld%%\n",
- (reduction == 100)?"near ":"", reduction);
-
- if (len > PAGE_SIZE - 200) {
- /* mark output cut off */
- len += snprintf(page + len, PAGE_SIZE - len, "(..)\n");
- break;
- }
- }
-
- list_for_each_entry(op, &bo->tx_ops, list) {
-
- len += snprintf(page + len, PAGE_SIZE - len,
- "tx_op: %03X %s [%d] ",
- op->can_id, bcm_proc_getifname(op->ifindex),
- op->nframes);
- if (op->j_ival1)
- len += snprintf(page + len, PAGE_SIZE - len, "t1=%ld ",
- op->j_ival1);
-
- if (op->j_ival2)
- len += snprintf(page + len, PAGE_SIZE - len, "t2=%ld ",
- op->j_ival2);
-
- len += snprintf(page + len, PAGE_SIZE - len, "# sent %ld\n",
- op->frames_abs);
-
- if (len > PAGE_SIZE - 100) {
- /* mark output cut off */
- len += snprintf(page + len, PAGE_SIZE - len, "(..)\n");
- break;
- }
- }
-
- len += snprintf(page + len, PAGE_SIZE - len, "\n");
-
- *eof = 1;
- return len;
-}
-
-/* bcm_op handling tx path */
-
-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];
-
- DBG_FRAME("BCM: bcm_can_tx: sending frame", cf);