IP_PUBLIC int
ipcom_rand(void)
{
    long rnd = ipcom_random();
    if (rnd < 0)
        rnd = -rnd;
    return (int)IP_MIN(rnd, IP_RAND_MAX);
}
Пример #2
0
/*
 *===========================================================================
 *                     ipnet_sock_tcp_append_send_data
 *===========================================================================
 * Description: Append data to the last packet in the send queue up to
 *              a full MSS segment.
 * Parameters:  send_tail - The last element of the send queue.
 *              pbuf - Pointer to the data buffer pointer. The buffer
 *                     pointer (*pbuf) will point to the first byte
 *                     that has not been copied.
 *              plen - A pointer to the length length of *pbuf, will
 *                     contain the number of bytes not copied when this
 *                     function returns.
 *              mss - The maximum segment size for this segment.
 * Returns:     Number of bytes appended.
 *
 */
IP_STATIC int
ipnet_sock_tcp_append_send_data(Ipcom_pkt *send_tail,
                                Ip_u8 **pbuf,
                                int *plen,
                                int mss)
{
    int bytes_appended;
    int len = *plen;

    if (mss <= send_tail->end - send_tail->start)
        /* mss must have been decresed after the send_tail was created */
        return 0;

    bytes_appended = IP_MIN(mss - (send_tail->end - send_tail->start), len);
    ip_assert(bytes_appended >= 0);

    if (send_tail->chk != 0 && (send_tail->end & 0x1) == 0)
    {
        /* End is even, just add the checksum of the appended data to
           the current checksum */
        send_tail->chk += ipnet_in_checksum_memcpy(&send_tail->data[send_tail->end],
                                                   *pbuf,
                                                   bytes_appended);
    }
    else
    {
        /* The checksum will be wrong unless the last odd byte is
           included in the new checksum, since odd bytes is handled as
           if the byte behind it is 0 (which is probably false now
           when more data is appended) */
        ipnet_copy_from_user(&send_tail->data[send_tail->end],
                             *pbuf,
                             bytes_appended);
        /* Calculate the checksum when sending instead */
        send_tail->chk = 0;
    }

    send_tail->end += bytes_appended;

    ip_assert(send_tail->end <= send_tail->maxlen);

    *pbuf = *pbuf + bytes_appended;
    *plen -= bytes_appended;

    return bytes_appended;
}
Пример #3
0
/*
 *===========================================================================
 *                   ipnet_usr_sock_tcp_pkts_from_iov
 *===========================================================================
 * Description: Copies the user data into MSS sized packets.
 * Parameters:  sock - The socket that will be use to send.
 *              msg - 'msg_iov' contains the buffer(s) to send.
 *              flags - IP_MSG_xxx flags.
 *              offset - Number of bytes into the msg->msg_iov buffers
 *                      where the copy into packets should start.
 *              total_buf_len - the sum of the length of all
 *                      msg->msg_iov buffers in 'msg'.
 *              ppkt -  Will point to the created packet(s) if the
 *                      operation is successfil. The (*ppkt)->next
 *                      points to the next packet in case of more than
 *                      one packet was allocated.
 * Returns:     <0 = error code (-IPNET_ERRNO_xxx)
 *               0 = this operation released the socket lock, the
 *                      sendmsg operation must be restarted
 *              >0 = number of bytes that has been allocated in the
 *                      socket send buffer and copied into the
 *                      packet(s) pointed to by *ppkt.
 */
IP_STATIC int
ipnet_usr_sock_tcp_pkts_from_iov(Ipnet_socket *sock,
                                 IP_CONST struct Ip_msghdr *msg,
                                 int flags,
                                 int offset,
                                 int total_buf_len,
                                 Ipcom_pkt **ppkt)
{
    Ipcom_pkt *pkt_head;
    Ipcom_pkt *pkt_tail;
    Iptcp_tcb *tcb = sock->tcb;
    int        mss = tcb->mss;
    Ip_u8     *buf;
    int        buf_len;
    int        i = 0;
    int        len = 0;
    int        bytes_to_copy = total_buf_len - offset;
    Ip_bool    non_blocking;
    Ip_bool    urgent = IP_BIT_ISSET(flags, IP_MSG_OOB);

    *ppkt = IP_NULL;

    /*
     * If offset == total_buf_len, which can in particular happen
     * if both are zero, then the loop immediately below can
     * access beyond the end of the iovec array. Avoid this.
     */
    if (offset == total_buf_len)
        return 0;

    for (buf_len = 0; buf_len <= 0; offset = - buf_len)
    {
        struct Ip_iovec *iov = &msg->msg_iov[i++];

        buf = (Ip_u8 *) iov->iov_base + offset;
        buf_len = (int) iov->iov_len - offset;
    }

    if (IP_LIKELY(urgent == IP_FALSE))
    {
        iptcp_partial_lock(tcb->send.partial_lock);
        if (tcb->send.partial != IP_NULL)
        {
            len = ipnet_sock_tcp_append_send_data(tcb->send.partial,
                                                  &buf,
                                                  &buf_len,
                                                  mss);
            if (len > 0)
                ipcom_atomic_add(&sock->snd_bytes, len);
        }
        iptcp_partial_unlock(tcb->send.partial_lock);

        if (len == bytes_to_copy)
            /* All data that should be sent was queued to the end of the
               partial finished TCP segment */
            return len;
    }
    /* else: urgent packet must be sent in a separate signal since the
       flag field must have IP_MSG_OOB set for correct processing. */

    non_blocking = IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING)
        || IP_BIT_ISSET(flags, IP_MSG_DONTWAIT);

    bytes_to_copy = 0;
    do
    {
        int bytes_to_alloc = IP_MIN(mss, buf_len - bytes_to_copy);

        if (ipcom_atomic_add_and_return(&sock->snd_bytes, bytes_to_alloc)
            < sock->send_max_bytes + bytes_to_alloc)
        {
            bytes_to_copy += bytes_to_alloc;
        }
        else
        {
            int lowat;

            ipcom_atomic_sub(&sock->snd_bytes, bytes_to_alloc);

            if (bytes_to_copy > 0 || non_blocking)
                break;

            lowat = IP_MAX(mss, (int) sock->tcb->send.lowat);
            lowat = IP_MIN(lowat, sock->send_max_bytes);
            (void)ipnet_usr_sock_wait_until_writable(sock,
                                                     lowat,
                                                     IP_NULL);
            if (sock->ipcom.so_errno)
            {
                ipcom_atomic_sub(&sock->snd_bytes, bytes_to_copy);
                return len > 0 && sock->ipcom.so_errno != IP_ERRNO_EINTR ? len : -sock->ipcom.so_errno;
            }
        }
    } while (bytes_to_copy < buf_len);

    pkt_head = IP_NULL;
    pkt_tail = IP_NULL;
    while (bytes_to_copy > 0)
    {
        Ipcom_pkt *pkt;
        int        seg_len = IP_MIN(bytes_to_copy, mss);

        pkt = ipcom_pkt_malloc(mss + sock->max_hdrspace,
                               IP_FLAG_FC_STACKCONTEXT | (non_blocking ? 0 : IP_FLAG_FC_BLOCKOK));
        if (IP_UNLIKELY(pkt == IP_NULL))
            break;

        pkt->start = (pkt->maxlen - mss) & ~0x3;
        pkt->end   = pkt->start + seg_len;

        pkt->chk = ipnet_in_checksum_memcpy(&pkt->data[pkt->start],
                                            buf,
                                            seg_len);

        /* Add this packet to the list of packets that will be sent
           to ipnetd */
        if (pkt_head == IP_NULL)
            pkt_head = pkt;

        else
            pkt_tail->next = pkt;
        pkt_tail = pkt;

        len += seg_len;
        buf += seg_len;
        bytes_to_copy -= seg_len;
    }

    if (IP_LIKELY(pkt_tail != IP_NULL))
    {
        if (IP_UNLIKELY(urgent))
            IPNET_MARK_PKT_AS_URGENT(pkt_tail);

        iptcp_partial_lock(tcb->send.partial_lock);
        tcb->send.partial = pkt_tail;
        iptcp_partial_unlock(tcb->send.partial_lock);
    }

    *ppkt = pkt_head;
    return (len == 0 ? -IP_ERRNO_EWOULDBLOCK : len);
}
Пример #4
0
/*
 *===========================================================================
 *                    ipcom_cmd_sockperf_run
 *===========================================================================
 * Description: Sends/receives data.
 * Parameters:
 * Returns:
 */
IP_STATIC void
ipcom_cmd_sockperf_run(Ipcom_cmd_sockperf_t *cmd)
{
    struct Ip_timeval  tmo = { 0, 0 };
    struct Ip_timeval *ptmo;
    struct Ip_timeval  start;
    struct Ip_timeval  stop;
    Ip_u32             i;
    Ip_u32             c;
    int                num_ready;
    Ip_fd             *s = cmd->sock_array;
    Ip_u32             total_bytes_to_send = cmd->num_buf * cmd->buf_len;
    Ip_u32             finished_sockets = 0;
    Ip_u32             total_bytes_read = 0;
    Ip_ssize_t         bytes;
    Ip_fd_set          read_set;
    int                send_flags = (cmd->transmit && cmd->receive) ? IP_MSG_DONTWAIT : 0;

    if (cmd->transmit)
        ipcom_printf("sockperf-t: send buffer is %u"IP_LF, cmd->sendbuf_size);
    if (cmd->receive)
        ipcom_printf("sockperf-r: receive buffer is %u"IP_LF, cmd->sendbuf_size);
    for (i = 0; i < cmd->num_sock; i++)
    {
        int on = 1;

        if (ipcom_setsockopt(s[i],
                             IP_SOL_SOCKET,
                             IP_SO_REUSEADDR,
                             &on,
                             sizeof(on)) < 0)
        {
            ipcom_printf("sockperf-c: setsockopt IP_SO_REUSEADDR failed : %s"IP_LF,
                         ipcom_strerror(ipcom_errno));
            return;
        }

        if (ipcom_setsockopt(s[i],
                             IP_SOL_SOCKET,
                             IP_SO_SNDBUF,
                             &cmd->sendbuf_size,
                             sizeof(cmd->sendbuf_size)) < 0)
        {
            ipcom_printf("sockperf-c: setsockopt IP_SO_SNDBUF failed : %s"IP_LF,
                         ipcom_strerror(ipcom_errno));
            return;
        }

        if (ipcom_setsockopt(s[i],
                             IP_SOL_SOCKET,
                             IP_SO_RCVBUF,
                             &cmd->recvbuf_size,
                             sizeof(cmd->recvbuf_size)) < 0)
        {
            ipcom_printf("sockperf-c: setsockopt IP_SO_SNDBUF failed : %s"IP_LF,
                         ipcom_strerror(ipcom_errno));
            return;
        }
    }


    if (cmd->receive)
    {
        IP_FD_ZERO(&cmd->read_set);
        cmd->width = s[0];
        IP_FD_SET(s[0], &cmd->read_set);
        for (i = 1; i < cmd->num_sock; i++)
            if (s[i] != IP_INVALID_SOCKET)
            {
                cmd->width = IP_MAX(cmd->width, s[i]);
                IP_FD_SET(s[i], &cmd->read_set);
            }
    }

    ipcom_microtime(&start);
    while ((cmd->transmit && total_bytes_to_send)
           || (cmd->receive && finished_sockets < cmd->num_sock))
    {
        if (cmd->transmit && total_bytes_to_send)
        {
            for (i = 0; i < cmd->num_sock; i++)
            {
                if (cmd->testpattern)
                {
                    /* Test patter is "[B|E|D]xxxxxx ", B = first 8 byte in buffer, E = last 8 bytes, D = all other */
                    for (c = 0; c < cmd->buf_len; c += 8)
                        ipcom_sprintf(cmd->buf + c, "%c%06ld ",
                                      c == 0 ? '>' : (c >= cmd->buf_len - 8 ? '<' : '#'),
                                      cmd->send_pattern[i]++ % 1000000);
                }

                bytes = ipcom_send(s[i],
                                   cmd->buf,
                                   IP_MIN(cmd->buf_len, total_bytes_to_send),
                                   send_flags);
                if (bytes < 0 && ipcom_errno == IP_ERRNO_EWOULDBLOCK)
                    (void)ipcom_sleep(0);
                else
                {
                    if (bytes < 0)
                    {
                        ipcom_printf("sockperf-t: send failed : %s"IP_LF,
                                     ipcom_strerror(ipcom_errno));
                        return;
                    }
                    total_bytes_to_send -= bytes;
                }
            }

            if (cmd->receive && total_bytes_to_send == 0)
                for (i = 0; i < cmd->num_sock; i++)
                    if (ipcom_shutdown(s[i], IP_SHUT_WR) < 0)
                    {
                        ipcom_printf("sockperf-t: shutdown failed: %s"IP_LF,
                                     ipcom_strerror(ipcom_errno));
                        return;
                    }
        }

        if (cmd->receive)
        {
            ptmo = IP_NULL;
            while (finished_sockets < cmd->num_sock)
            {
                read_set = cmd->read_set;
                num_ready = ipcom_socketselect(cmd->width + 1, &read_set, IP_NULL, IP_NULL, ptmo);

                if (num_ready == 0)
                    break;

                if (num_ready < 0)
                {
                    ipcom_printf("sockperf-r: select failed: %s"IP_LF,
                                 ipcom_strerror(ipcom_errno));
                    return;
                }

                for (i = 0; i < cmd->num_sock; i++)
                {
                    if (IP_FD_ISSET(s[i], &read_set))
                    {
                        bytes = ipcom_recv(s[i], cmd->buf, cmd->buf_len, 0);
                        if (bytes < 0)
                        {
                            ipcom_printf("sockperf-r: recv failed: %s"IP_LF,
                                         ipcom_strerror(ipcom_errno));
                            return;
                        }

                        if (cmd->testpattern)
                        {
                            if (cmd->echo)
                                ipcom_cmd_sockperf_echo_buf(cmd->buf, bytes, cmd->recv_pattern[i]);
                            for (c = 0; c < (Ip_u32)bytes; c += 8)
                            {
                                if (cmd->buf[c] != '#' && cmd->buf[c] != '>' && cmd->buf[c] != '<')
                                {
                                    ipcom_printf("\nsockperf-r: test pattern error, expected B, D or E found %c(%d) offset %ld"IP_LF,
                                                 cmd->buf[c], (int)cmd->buf[c], c);
                                    ipcom_cmd_sockperf_echo_buf(cmd->buf, bytes, 0);
                                    return;
                                }

                                if (ipcom_atoi(cmd->buf + c + 1) != (int)(cmd->recv_pattern[i]++ % 1000000))
                                {
                                    ipcom_printf("\nsockperf-r: test pattern error, was %d should be %ld offset %ld"IP_LF,
                                                 ipcom_atoi(cmd->buf + c + 1), (cmd->recv_pattern[i] - 1) % 1000000, c);
                                    ipcom_cmd_sockperf_echo_buf(cmd->buf, bytes, 0);
                                    return;
                                }
                            }
                        }

                        if (bytes > 0)
                            total_bytes_read += bytes;
                        else
                        {
                            finished_sockets++;
                            IP_FD_CLR(s[i], &cmd->read_set);
                        }
                    }
                }

                if (cmd->transmit && total_bytes_to_send)
                    ptmo = &tmo;
            }
        }
    }
    ipcom_microtime(&stop);

    if (cmd->transmit)
        ipcom_printf("sockperf-t: %lu bytes sent in %ld ms (%lu kbyte/s)"IP_LF,
                     cmd->num_buf * cmd->buf_len,
                     ipcom_cmd_sockperf_tv_to_msec(&start, &stop),
                     cmd->num_buf * cmd->buf_len / (Ip_u32)ipcom_cmd_sockperf_tv_to_msec(&start, &stop) * 1000 / 1024);
    if (cmd->receive)
        ipcom_printf("sockperf-r: %lu bytes read in %ld ms (%lu kbyte/s)"IP_LF,
                     total_bytes_read,
                     ipcom_cmd_sockperf_tv_to_msec(&start, &stop),
                     total_bytes_read / (Ip_u32)ipcom_cmd_sockperf_tv_to_msec(&start, &stop) * 1000 / 1024);

}
/*
 *===========================================================================
 *                    ipnet_rtnetlink_sock_send
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_GLOBAL int
ipnet_rtnetlink_sock_send(Ipnet_socket                    *sock,
                          Ip_bool                         non_blocking,
                          struct Ip_nlmsghdr              *nlmsg)
{
	struct Ip_rtattr                **rta   = IP_NULL;
    int                             ret = 0;
    Ipnet_rtnetlink_func_table_t    *tbl;
    int                             family;

    /* Need to retrieve the family byte */
    if (nlmsg->nlmsg_len < IP_NLMSG_LENGTH(sizeof(struct Ip_rtgenmsg)))
        return 0;

    /* These messages are to be ignored */
    if (nlmsg->nlmsg_type < IP_RTM_BASE)
        return 0;

    /**/
    family = ((struct Ip_rtgenmsg*)IP_NLMSG_DATA(nlmsg))->rtgen_family;

    /* Dump */
    if (IP_BIT_ISSET(nlmsg->nlmsg_flags, IP_NLM_F_DUMP) && ((nlmsg->nlmsg_type - IP_RTM_BASE) & 0x3) == 2)
    {
        ret = -IP_ERRNO_EAFNOSUPPORT;
        tbl = ipnet_rtnetlink_family_get_dump(ipnet->rtnetlink_links, family, nlmsg->nlmsg_type);
        if (tbl == IP_NULL)
            goto error_out;

        ret = ipnet_netlink_dump(tbl->nl_dump, family, sock, nlmsg, non_blocking);
        goto error_out;
    }

    tbl = ipnet_rtnetlink_family_get_do(ipnet->rtnetlink_links, family, nlmsg->nlmsg_type);
    if (tbl == IP_NULL)
    {
        ret = -IP_ERRNO_EAFNOSUPPORT;
        goto error_out;
    }
    else
    {
        struct Ip_rtattr *attr      = IP_NULL;
        int              attrlen    = 0;

        /* Check minimum length. */
        if (nlmsg->nlmsg_len < tbl->nl_size_min)
        {
            ret = -IP_ERRNO_EINVAL;
            goto error_out;
        }

        /* */
        if (nlmsg->nlmsg_len > tbl->nl_size_min)
        {
            attrlen = nlmsg->nlmsg_len - IP_NLMSG_ALIGN(tbl->nl_size_min);
            attr = (struct Ip_rtattr*)((int)nlmsg + IP_NLMSG_ALIGN(tbl->nl_size_min));
        }

        ret = ipnet_rtnetlink_parse(tbl->nl_rta_max, attr, attrlen, &rta);
        if (ret < 0)
            goto error_out;
    }

    /* DO */
    ret = ipnet_rtnetlink_do(tbl->nl_do, family, sock, nlmsg, non_blocking, (void *)rta);

error_out:
    if (rta)
        ipcom_free(rta);
    return IP_MIN(ret, 0);
}