-static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size)
-{
- struct sock *sk = sock->sk;
- struct bcm_opt *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) {
- DBG("sock %p not bound\n", sk);
- return -ENOTCONN;
- }
-
- /* 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;
-
- if (addr->can_family != AF_CAN)
- return -EINVAL;
-
- ifindex = addr->can_ifindex; /* ifindex from sendto() */
-
- if (ifindex && !dev_get_by_index(ifindex)) {
- DBG("device %d not found\n", ifindex);
- return -ENODEV;
- }
- }
-
- /* read message head information */
-
- ret = memcpy_fromiovec((u8*)&msg_head, msg->msg_iov, MHSIZ);
- if (ret < 0)
- return ret;
-
- DBG("opcode %d for can_id %03X\n", msg_head.opcode, msg_head.can_id);
-
- 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:
-
- /* we need at least one can_frame */
- if (msg_head.nframes < 1)
- return -EINVAL;
-
- ret = bcm_tx_send(msg, ifindex, sk);
- break;
-
- default:
-
- DBG("Unknown opcode %d\n", msg_head.opcode);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-