예제 #1
0
/***
 *  rt_packet_recvmsg
 */
static ssize_t
rt_packet_recvmsg(struct rtdm_fd *fd, struct msghdr *msg, int msg_flags)
{
    struct rtsocket     *sock = rtdm_fd_to_private(fd);
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    size_t              copy_len;
    size_t              real_len;
    struct rtskb        *rtskb;
    struct sockaddr_ll  *sll;
    int                 ret;
    nanosecs_rel_t      timeout = sock->timeout;


    /* non-blocking receive? */
    if (msg_flags & MSG_DONTWAIT)
	timeout = -1;

    ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL);
    if (unlikely(ret < 0))
	switch (ret) {
	    case -EWOULDBLOCK:
	    case -ETIMEDOUT:
	    case -EINTR:
		return ret;

	    default:
		return -EBADF;   /* socket has been closed */
	}

    rtskb = rtskb_dequeue_chain(&sock->incoming);
    RTNET_ASSERT(rtskb != NULL, return -EFAULT;);
예제 #2
0
/***
 *  rt_packet_recvmsg
 */
ssize_t rt_packet_recvmsg(struct rtdm_dev_context *sockctx,
                          rtdm_user_info_t *user_info, struct msghdr *msg,
                          int msg_flags)
{
    struct rtsocket     *sock = (struct rtsocket *)&sockctx->dev_private;
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    size_t              copy_len;
    size_t              real_len;
    struct rtskb        *skb;
    struct ethhdr       *eth;
    struct sockaddr_ll  *sll;
    int                 ret;
    nanosecs_t          timeout = sock->timeout;


    /* non-blocking receive? */
    if (testbits(msg_flags, MSG_DONTWAIT))
        timeout = -1;

    ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL);
    if (unlikely(ret < 0)) {
        if ((ret != -EWOULDBLOCK) && (ret != -ETIMEDOUT))
            ret = -EBADF;   /* socket has been closed */
        return ret;
    }

    skb = rtskb_dequeue_chain(&sock->incoming);
    RTNET_ASSERT(skb != NULL, return -EFAULT;);
예제 #3
0
/***
 *  rt_udp_recvmsg
 */
ssize_t rt_udp_recvmsg(struct rtdm_dev_context *context,
                       rtdm_user_info_t *user_info, struct msghdr *msg,
                       int msg_flags)
{
    struct rtsocket     *sock = (struct rtsocket *)&context->dev_private;
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    struct rtskb        *skb;
    struct rtskb        *first_skb;
    size_t              copied = 0;
    size_t              block_size;
    size_t              data_len;
    struct udphdr       *uh;
    struct sockaddr_in  *sin;
    nanosecs_t          timeout = sock->timeout;
    int                 ret;


    /* non-blocking receive? */
    if (test_bit(RT_SOCK_NONBLOCK, &context->context_flags) ||
        (msg_flags & MSG_DONTWAIT))
        timeout = -1;

    ret = rtos_sem_down(&sock->pending_sem, timeout);
    if (unlikely(ret < 0)) {
        if (ret == -EWOULDBLOCK)
            ret = -EAGAIN;
        else if (ret != -ETIMEDOUT)
            ret = -ENOTSOCK;
        return ret;
    }

    skb = rtskb_dequeue_chain(&sock->incoming);
    RTNET_ASSERT(skb != NULL, return -EFAULT;);
예제 #4
0
/***
 *  rt_packet_sendmsg
 */
ssize_t rt_packet_sendmsg(struct rtdm_dev_context *context, int call_flags,
                          const struct msghdr *msg, int flags)
{
    struct rtsocket     *sock = (struct rtsocket *)&context->dev_private;
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    struct sockaddr_ll  *sll  = (struct sockaddr_ll*)msg->msg_name;
    struct rtnet_device *rtdev;
    struct rtskb        *rtskb;
    int                 ret = 0;


    if (flags & MSG_OOB)   /* Mirror BSD error message compatibility */
        return -EOPNOTSUPP;

    /* a lot of sanity checks */
    if ((flags & ~MSG_DONTWAIT) ||
        (sll == NULL) || (msg->msg_namelen != sizeof(struct sockaddr_ll)) ||
        ((sll->sll_family != AF_PACKET) && (sll->sll_family != AF_UNSPEC)) ||
        (sll->sll_ifindex <= 0))
        return -EINVAL;

    if ((rtdev = rtdev_get_by_index(sll->sll_ifindex)) == NULL)
        return -ENODEV;

    rtskb = alloc_rtskb(rtdev->hard_header_len + len, &sock->skb_pool);
    if (rtskb == NULL) {
        ret = -ENOBUFS;
        goto out;
    }

    if ((len < 0) || (len > rtdev->mtu)) {
        ret = -EMSGSIZE;
        goto err;
    }

    if (sll->sll_halen != rtdev->addr_len) {
        ret = -EINVAL;
        goto err;
    }

    rtskb_reserve(rtskb, rtdev->hard_header_len);

    rt_memcpy_fromkerneliovec(rtskb_put(rtskb, len), msg->msg_iov, len);

    rtskb->rtdev    = rtdev;
    rtskb->priority = sock->priority;

    if (rtdev->hard_header) {
        ret = rtdev->hard_header(rtskb, rtdev, ntohs(sll->sll_protocol),
                                 sll->sll_addr, rtdev->dev_addr, rtskb->len);
        if (ret < 0)
            goto err;
    }

    if ((rtdev->flags & IFF_UP) != 0) {
        if (rtdev_xmit(rtskb) == 0)
            ret = len;
        else
            ret = -EAGAIN;
    } else {
        ret = -ENETDOWN;
        goto err;
    }

out:
    rtdev_dereference(rtdev);
    return ret;

err:
    kfree_rtskb(rtskb);
    rtdev_dereference(rtdev);
    return ret;
}
예제 #5
0
/***
 *  rt_packet_recvmsg
 */
ssize_t rt_packet_recvmsg(struct rtdm_dev_context *context, int call_flags,
                          struct msghdr *msg, int msg_flags)
{
    struct rtsocket     *sock = (struct rtsocket *)&context->dev_private;
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    size_t              copy_len;
    size_t              real_len;
    struct rtskb        *skb;
    struct ethhdr       *eth;
    struct sockaddr_ll  *sll;
    int                 ret;
    unsigned long       flags;
    rtos_time_t         timeout;


    /* block on receive event */
    if (!test_bit(RT_SOCK_NONBLOCK, &context->context_flags) &&
        ((msg_flags & MSG_DONTWAIT) == 0))
        while ((skb = rtskb_dequeue_chain(&sock->incoming)) == NULL) {
            rtos_spin_lock_irqsave(&sock->param_lock, flags);
            memcpy(&timeout, &sock->timeout, sizeof(timeout));
            rtos_spin_unlock_irqrestore(&sock->param_lock, flags);

            if (!RTOS_TIME_IS_ZERO(&timeout)) {
                ret = rtos_event_sem_wait_timed(&sock->wakeup_event, &timeout);
                if (ret == RTOS_EVENT_TIMEOUT)
                    return -ETIMEDOUT;
            } else
                ret = rtos_event_sem_wait(&sock->wakeup_event);

            if (RTOS_EVENT_ERROR(ret))
                return -ENOTSOCK;
        }
    else {
        skb = rtskb_dequeue_chain(&sock->incoming);
        if (skb == NULL)
            return -EAGAIN;
    }

    eth = skb->mac.ethernet;

    sll = msg->msg_name;

    /* copy the address */
    msg->msg_namelen = sizeof(*sll);
    if (sll != NULL) {
        sll->sll_family   = AF_PACKET;
        sll->sll_protocol = skb->protocol;
        sll->sll_ifindex  = skb->rtdev->ifindex;
        sll->sll_pkttype  = skb->pkt_type;

        /* Ethernet specific */
        sll->sll_hatype   = ARPHRD_ETHER;
        sll->sll_halen    = ETH_ALEN;
        memcpy(sll->sll_addr, eth->h_source, ETH_ALEN);
    }

    copy_len = real_len = skb->len;

    /* The data must not be longer than the available buffer size */
    if (copy_len > len) {
        copy_len = len;
        msg->msg_flags |= MSG_TRUNC;
    }

    /* copy the data */
    rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, copy_len);

    if ((msg_flags & MSG_PEEK) == 0) {
        rtdev_dereference(skb->rtdev);
        kfree_rtskb(skb);
    } else
        rtskb_queue_head(&sock->incoming, skb);

    return real_len;
}
예제 #6
0
/***
 *  rt_udp_sendmsg
 */
ssize_t rt_udp_sendmsg(struct rtdm_dev_context *context, int call_flags,
                       const struct msghdr *msg, int msg_flags)
{
    struct rtsocket     *sock = (struct rtsocket *)&context->dev_private;
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    int                 ulen  = len + sizeof(struct udphdr);
    struct sockaddr_in  *usin;
    struct udpfakehdr   ufh;
    struct dest_route   rt;
    u32                 saddr;
    u32                 daddr;
    u16                 dport;
    int                 err;
    unsigned long       flags;


    if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr)))
        return -EMSGSIZE;

    if (msg_flags & MSG_OOB)   /* Mirror BSD error message compatibility */
        return -EOPNOTSUPP;

    if (msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT) )
        return -EINVAL;

    if ((msg->msg_name) && (msg->msg_namelen==sizeof(struct sockaddr_in))) {
        usin = (struct sockaddr_in*) msg->msg_name;

        if ((usin->sin_family != AF_INET) && (usin->sin_family != AF_UNSPEC))
            return -EINVAL;

        daddr = usin->sin_addr.s_addr;
        dport = usin->sin_port;

        rtos_spin_lock_irqsave(&sock->param_lock, flags);
    } else {
        rtos_spin_lock_irqsave(&sock->param_lock, flags);

        if (sock->prot.inet.state != TCP_ESTABLISHED)
            return -ENOTCONN;

        daddr = sock->prot.inet.daddr;
        dport = sock->prot.inet.dport;
    }
    saddr         = sock->prot.inet.saddr;
    ufh.uh.source = sock->prot.inet.sport;

    rtos_spin_unlock_irqrestore(&sock->param_lock, flags);

    if ((daddr | dport) == 0)
        return -EINVAL;

    /* get output route */
    err = rt_ip_route_output(&rt, daddr);
    if (err)
        return err;

    /* check if specified source address fits */
    if ((saddr != INADDR_ANY) && (saddr != rt.rtdev->local_ip)) {
        rtdev_dereference(rt.rtdev);
        return -EHOSTUNREACH;
    }

    /* we found a route, remember the routing dest-addr could be the netmask */
    ufh.saddr     = rt.rtdev->local_ip;
    ufh.daddr     = daddr;
    ufh.uh.dest   = dport;
    ufh.uh.len    = htons(ulen);
    ufh.uh.check  = 0;
    ufh.iov       = msg->msg_iov;
    ufh.iovlen    = msg->msg_iovlen;
    ufh.wcheck    = 0;

    err = rt_ip_build_xmit(sock, rt_udp_getfrag, &ufh, ulen, &rt, msg_flags);

    rtdev_dereference(rt.rtdev);

    if (!err)
        return len;
    else
        return err;
}
예제 #7
0
/***
 *  rt_udp_recvmsg
 */
ssize_t rt_udp_recvmsg(struct rtdm_dev_context *context, int call_flags,
                       struct msghdr *msg, int msg_flags)
{
    struct rtsocket     *sock = (struct rtsocket *)&context->dev_private;
    size_t              len   = rt_iovec_len(msg->msg_iov, msg->msg_iovlen);
    struct rtskb        *skb;
    struct rtskb        *first_skb;
    size_t              copied = 0;
    size_t              block_size;
    size_t              data_len;
    struct udphdr       *uh;
    struct sockaddr_in  *sin;
    int                 ret;
    unsigned long       flags;
    rtos_time_t         timeout;


    /* block on receive event */
    if (!test_bit(RT_SOCK_NONBLOCK, &context->context_flags) &&
        ((msg_flags & MSG_DONTWAIT) == 0))
        while ((skb = rtskb_dequeue_chain(&sock->incoming)) == NULL) {
            rtos_spin_lock_irqsave(&sock->param_lock, flags);
            memcpy(&timeout, &sock->timeout, sizeof(timeout));
            rtos_spin_unlock_irqrestore(&sock->param_lock, flags);

            if (!RTOS_TIME_IS_ZERO(&timeout)) {
                ret = rtos_event_sem_wait_timed(&sock->wakeup_event, &timeout);
                if (ret == RTOS_EVENT_TIMEOUT)
                    return -ETIMEDOUT;
            } else
                ret = rtos_event_sem_wait(&sock->wakeup_event);

            if (RTOS_EVENT_ERROR(ret))
                return -ENOTSOCK;
        }
    else {
        skb = rtskb_dequeue_chain(&sock->incoming);
        if (skb == NULL)
            return -EAGAIN;
    }

    uh = skb->h.uh;
    data_len = ntohs(uh->len) - sizeof(struct udphdr);
    sin = msg->msg_name;

    /* copy the address */
    msg->msg_namelen = sizeof(*sin);
    if (sin) {
        sin->sin_family      = AF_INET;
        sin->sin_port        = uh->source;
        sin->sin_addr.s_addr = skb->nh.iph->saddr;
    }

    /* remove the UDP header */
    __rtskb_pull(skb, sizeof(struct udphdr));

    first_skb = skb;

    /* iterate over all IP fragments */
    do {
        rtskb_trim(skb, data_len);

        block_size = skb->len;
        copied += block_size;
        data_len -= block_size;

        /* The data must not be longer than the available buffer size */
        if (copied > len) {
            block_size -= copied - len;
            copied = len;
            msg->msg_flags |= MSG_TRUNC;

            /* copy the data */
            rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size);

            break;
        }

        /* copy the data */
        rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size);

        /* next fragment */
        skb = skb->next;
    } while (skb != NULL);

    /* did we copied all bytes? */
    if (data_len > 0)
        msg->msg_flags |= MSG_TRUNC;

    if ((msg_flags & MSG_PEEK) == 0)
        kfree_rtskb(first_skb);
    else {
        __rtskb_push(first_skb, sizeof(struct udphdr));
        rtskb_queue_head(&sock->incoming, first_skb);
    }

    return copied;
}