Esempio n. 1
0
/*
 *===========================================================================
 *                     ipnet_udp_fast_deliver_data
 *===========================================================================
 * Description: Deliver an UDP packet to a socket that is bound to a unicast
 *              address.
 * Parameters:  sock - The socket the packet will be delivered to.
 *              pkt - The UDP packet to deliver.
 *              nat_t - NAT_T processing.
 * Returns:     IP_TRUE - The fast path processing was successful.
 *              IP_FALSE - Need to use the normal receive path.
 *
 */
IP_STATIC Ip_bool
ipnet_udp_fast_deliver_data(Ipnet_socket *sock, Ipcom_pkt *pkt, int *nat_t)
{
    Ipnet_pkt_udp       *udp_hdr;
    int                  original_start = pkt->start;
    Ipcom_socket_eventcb event_cb = sock->ipcom.event_cb;

    udp_hdr = (Ipnet_pkt_udp*) &pkt->data[pkt->tlstart];
    if (IP_UNLIKELY(pkt->end - pkt->tlstart < IPNET_UDP_HDR_SIZE
                    || pkt->end - pkt->tlstart < ip_ntohs(udp_hdr->ulen)))
        return IP_FALSE;

    if (udp_hdr->sum != 0 && IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK))
    {
        Ip_u16 chksum;
        /* Only check packets that was not created locally */
#ifdef IPCOM_USE_HW_CHECKSUM_RX
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_HW_CHECKSUM))
            chksum = 0;
        else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_TL_CHECKSUM))
            chksum = ipcom_in_checksum_finish(pkt->chk);
        else
#endif /* IPCOM_USE_HW_CHECKSUM_RX */
        {
            pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->tlstart],
                                                 (Ip_size_t) ip_ntohs(udp_hdr->ulen));
            chksum = ipcom_in_checksum_finish(pkt->chk);
        }

        if (IP_UNLIKELY(chksum != 0))
            return IP_FALSE;
    }

    pkt->fd    = sock->ipcom.fd;
    pkt->start = pkt->tlstart + IPNET_UDP_HDR_SIZE;

    if (IP_UNLIKELY(ipnet_udp_encapsulation(sock, pkt, nat_t)))
    {
        /* Continue processing */
        ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_ENCAP_UDP, sizeof(*udp_hdr), udp_hdr);
        pkt->start = original_start;
        return IP_FALSE;
    }

    if (ipnet_queue_received_packet(pkt, sock) != 0)
    {
        pkt->start = original_start;
        return IP_FALSE;
    }

    if (event_cb != IP_NULL)
        event_cb(&sock->ipcom, pkt, IP_SOEVENT_CB_INPKT);

    IPCOM_MIB2(udpInDatagrams++);
    IPCOM_MIB2_U64_INC(udpHCInDatagrams);
    return IP_TRUE;
}
/*
 *===========================================================================
 *                    ipnet_gre_tmo
 *===========================================================================
 * Description: Reassembly timeout handler.
 * Parameters:  netif - A GRE tunnel interface.
 * Returns:     0 = success, <0 = error code.
 *
 */
IP_STATIC void
ipnet_gre_seq_tmo(Ipnet_netif *netif)
{
    Ipnet_pkt_gre *gre_hdr;
    Ipcom_pkt     *pkt;
    Ipnet_gre_t   *gre = netif->ipcom.pdrv;

    /* RFC 2890, chapter 2.2
       ...
       Under no circumstances should a packet wait more that
       OUTOFORDER_TIMER milliseconds in the buffer.  If a packet has been
       waiting that long, the receiver MUST immediately traverse the buffer
       in sorted order, decapsulating packets (and ignoring any sequence
       number gaps) until there are no more packets in the buffer that have
       been waiting longer than OUTOFORDER_TIMER milliseconds. The "last
       successfully decapsulated sequence number" should then be set to the
       last packet so decapsulated.
       ...
    */
    pkt = ipcom_pqueue_get_next(gre->reassembly_queue);
    ip_assert(pkt != IP_NULL);
    gre->recv_seqnum = IP_GET_NTOHL(&pkt->data[pkt->start]);

    do
    {
        pkt = ipcom_pqueue_remove_next(gre->reassembly_queue);
        /* Discard the sequence number option and make place for a GRE header */
        pkt->start += IPNET_GRE_OPT_SEQNUM_SIZE - IPNET_GRE_HDR_SIZE;

        gre_hdr = (Ipnet_pkt_gre *)&pkt->data[pkt->start];
        gre_hdr->flags_reserved0_ver = 0;
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_IPV4))
            gre_hdr->protocol_type = ip_htons(0x0800);
        else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_IPV6))
            gre_hdr->protocol_type = ip_htons(0x86DD);

        (void) ipnet_gre_input(netif, pkt);
        ++gre->recv_seqnum;
    } while (IP_NULL != (pkt = ipcom_pqueue_get_next(gre->reassembly_queue))
             && gre->recv_seqnum == IP_GET_NTOHL(&pkt->data[pkt->start]));

    if (pkt != IP_NULL)
    {
        Ip_u32 timeout = IPNET_PKT_GET_TIMEOUT_ABS(pkt);

        /* More out of order packets waiting, schedule a timeout of
           the time remaining until this packet sequence timer timeouts */
        (void) ipnet_timeout_schedule((timeout < ipnet->msec_now
                                       ? 0
                                       : timeout - ipnet->msec_now),
                                      (Ipnet_timeout_handler) ipnet_gre_seq_tmo,
                                      netif,
                                      &gre->reassembly_tmo);
    }
}
/*
 *===========================================================================
 *                           netsysctlname2oid
 *===========================================================================
 * Description:
 * Parameters:  ctl -
 *              name -
 *              pNewName -
 *              nameLen -
 * Returns:
 *
 */
IP_PUBLIC int
netsysctlname2oid(Ipnet_cmd_sysctl *ctl, char* name, int* pNewName, int* nameLen)
{
#ifdef IPCOM_USE_INET
    int i;
  
    if(ctl == IP_NULL)
    {
        ctl = ipnet_sysctl_inet_table;
        pNewName[(*nameLen)++] = IP_IPPROTO_IP;
    }
    
    /* if you want to support trunk node, pls change this function */
    while (ctl->comp != IP_NULL)
    {
        if (IP_BIT_ISSET(ctl->argument, IPNET_CMD_SYSCTL_NETIF_NO))
        {
            if (ipcom_strcasecmp(name, ctl->comp) == 0)
            {
                for (i = 0; ctl->ctl[i] != -1; i++);
                pNewName[(*nameLen)++] = ctl->ctl[i ? i-1 : i];
            }
        }
        
        /* Do the netifs */
        if (IP_BIT_ISSET(ctl->argument, IPNET_CMD_SYSCTL_NETIF_YES))
        {
            /* Dump the arguments */
            char **argv = ipnet_cmd_sysctl_dump_netif();

            if (argv)
            {
                for (i = 0; argv[i] != IP_NULL; i++)
                {
                    if(ipcom_strcasecmp(name, argv[i])==0)
                    {
                        name += ipcom_strlen(argv[i]) + 1;
                        pNewName[(*nameLen)++] = i;
                        netsysctlname2oid(ipnet_sysctl_inet_table, name, pNewName, nameLen);
                    }
                    
                    ipcom_free(argv[i]);
                }
                
                ipcom_free(argv);
            }
        }
        
        ctl++;
    }
#endif
    
    return 0;
}
/*
 *===========================================================================
 *                    ipnet_rtnetlink_neigh_is
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_GLOBAL Ip_bool
ipnet_rtnetlink_neigh_is(struct Ipnet_route_entry_struct    *rt)
{
    /* Find the first NC entry */
    if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_LLINFO)
        && IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_HOST)
        && IP_BIT_ISFALSE(rt->hdr.flags, IPNET_RTF_PROTO2)
        && rt->gateway
        && rt->gateway->sa_family == IP_AF_LINK)
    {
        /* Found a NC entry */
        return IP_TRUE;
    }
    return IP_FALSE;
}
/*
 *===========================================================================
 *                    ipnet_sysctl_route_dump_elem_len
 *===========================================================================
 * Description: Calculates the length needed to write down address information
 *              for the specified route entry.
 * Parameters:  rt - a route entry.
 * Returns:     Length in bytes.
 *
 */
IP_STATIC Ip_u16
ipnet_sysctl_route_dump_elem_len(Ipnet_route_entry *rt)
{
    Ip_u16 len;
    Ip_u16 addr_len;

    len = sizeof(struct Ipnet_rt_msghdr);
    if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET)
        addr_len = sizeof(struct Ip_sockaddr_in);
    else
        addr_len = sizeof(struct Ip_sockaddr_in6);

    /* Length of destination address */
    len += addr_len;

    /* Length of destination mask */
    if (rt->hdr.mask)
        len += addr_len;

    /* Length of gateway address */
    if (rt->gateway)
        len += IPCOM_SA_LEN_GET(rt->gateway);
    else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING))
        len += sizeof(struct Ip_sockaddr_dl);

    return len;
}
/*
 *===========================================================================
 *                   ipnet_rtnetlink_neigh_nud2nc
 *===========================================================================
 * Description: Converts neighbor states from NETLINK standard to IPNET
 * Parameters:  ndm_state - NETLINK neighbor state
 * Returns:     IPNET neighbor state.
 *
 */
IP_GLOBAL int
ipnet_rtnetlink_neigh_nud2nc(Ip_u16 ndm_state)
{
    if (IP_BIT_ISSET(ndm_state, IP_NUD_PERMANENT|IP_NUD_REACHABLE))
        return IPNET_ND_REACHABLE;
    else if (IP_BIT_ISSET(ndm_state, IP_NUD_STALE))
        return IPNET_ND_STALE;
    else if (IP_BIT_ISSET(ndm_state, IP_NUD_PROBE))
        return IPNET_ND_PROBE;
    else if (IP_BIT_ISSET(ndm_state, IP_NUD_DELAY))
        return IPNET_ND_DELAY;
    else if (IP_BIT_ISSET(ndm_state, IP_NUD_INCOMPLETE))
        return IPNET_ND_INCOMPLETE;
    else
        return IPNET_ND_UNINITIALIZED;
}
IP_STATIC Ip_size_t
ipcom_create_ifaddrs_inet6(Ip_fd                    fd,
                           const char               *ifname,
                           Ip_u8                    *ifa_first,
                           Ip_size_t                buf_len,
                           struct Ipnet_if_msghdr   *ifm,
                           struct Ip_ifaddrs        ***tail)
{
    struct Ip_in6_aliasreq   ifareq;
    struct Ipnet_ifa_msghdr *ifa;
    struct Ip_sockaddr_in6  *addrs[IPNET_RTAX_MAX];
    Ip_size_t                offset = 0;

    offset = 0;
    while (offset < buf_len)
    {
        struct Ip_ifaddrs        *nifa;

        ifa = (struct Ipnet_ifa_msghdr *) &ifa_first[offset];
#if defined(IP_PORT_VXWORKS) && !defined(_WRS_KERNEL)
        ipnet_cmd_init_addrs_rtp(ifa + 1, ifa->ifam_addrs, (struct Ip_sockaddr **) addrs);
#else
        ipnet_cmd_init_addrs(ifa + 1, ifa->ifam_addrs, (struct Ip_sockaddr **) addrs);
#endif

        if (ifa->ifam_type != IPNET_RTM_NEWADDR || addrs[IPNET_RTAX_IFA]->sin6_family != IP_AF_INET6)
            break;

        offset += ifa->ifam_msglen;

        ipcom_memset(&ifareq, 0, sizeof(ifareq));
        ipcom_memcpy(ifareq.ifra_name, ifname, IP_IFNAMSIZ);
        ipcom_memcpy(&ifareq.ifra_addr, addrs[IPNET_RTAX_IFA], sizeof(ifareq.ifra_addr));
        (void)ipcom_socketioctl(fd, IP_SIOCXGIFADDR_IN6, &ifareq);

        if (IP_BIT_ISSET(ifareq.ifra_flags, IP_IN6_IFF_ANYCAST))
            continue;

        if (IP_IN6_IS_ADDR_MULTICAST(&addrs[IPNET_RTAX_IFA]->sin6_addr))
            continue;

        nifa = ipcom_create_ifaddrs_entry(ifname, ifm, ifa, (struct Ip_sockaddr **)addrs);
        if (nifa != IP_NULL)
        {
            **tail = nifa;
            *tail  = &nifa->ifa_next;
        }
    }

    return offset;
}
/*
 *===========================================================================
 *                    ipcom_create_ifaddrs_entry
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC struct Ip_ifaddrs *
ipcom_create_ifaddrs_entry(const char                *ifname,
                           struct Ipnet_if_msghdr    *ifm,
                           struct Ipnet_ifa_msghdr   *ifa,
                           struct Ip_sockaddr        **addrs)
{
    /**/
    struct Ip_ifaddrs        *nifa = ipcom_calloc(1, sizeof(*nifa));

    if (nifa == IP_NULL)
        return IP_NULL;

    /* Interface name */
    nifa->ifa_name = ipcom_strdup(ifname);
    if(nifa->ifa_name == IP_NULL)
        goto fail;

    /* Interface flags */
    nifa->ifa_flags = ifm->ifm_flags;

    /* Interface address */
    nifa->ifa_addr = ipcom_malloc(sizeof(union Ip_sockaddr_union));
    if(nifa->ifa_addr == IP_NULL)
        goto fail;

    ipcom_memcpy(nifa->ifa_addr, addrs[IPNET_RTAX_IFA], IPCOM_SA_LEN_GET(addrs[IPNET_RTAX_IFA]));

    nifa->ifa_netmask = ipcom_malloc(sizeof(union Ip_sockaddr_union));
    if(nifa->ifa_netmask == IP_NULL)
        goto fail;

    ipcom_memcpy(nifa->ifa_netmask, addrs[IPNET_RTAX_NETMASK], IPCOM_SA_LEN_GET(addrs[IPNET_RTAX_IFA]));


    if (IP_BIT_ISSET(ifa->ifam_addrs, IPNET_RTA_BRD))
    {
        nifa->ifa_broadaddr = ipcom_malloc(sizeof(union Ip_sockaddr_union));
        if(nifa->ifa_broadaddr == IP_NULL)
            goto fail;

        ipcom_memcpy(nifa->ifa_broadaddr, addrs[IPNET_RTAX_BRD], IPCOM_SA_LEN_GET(addrs[IPNET_RTAX_BRD]));
    }

    return nifa;

fail:
    ipcom_ifaddrs_free(nifa);
    return IP_NULL;
}
/*
 *===========================================================================
 *                    ipnet_sysctl_if_add_addrs
 *===========================================================================
 * Description: Adds a Ipnet_ifa_msghdr structure for each address matching
 *              the domain assigned to the specified interface.
 * Parameters:  buf - buffer to where the addresses will be copied.
 *              netif - interface for which all addresses should be added.
 *              domain - the domain to return addresses for (0=all domains)
 * Returns:     Number of bytes added or bytes needed if buf == IP_NULL
 *
 */
IP_STATIC Ip_u16
ipnet_sysctl_if_add_addrs(void *buf, Ipnet_netif *netif, int domain)
{
    Ip_size_t len = 0;

#ifdef IPCOM_USE_INET
    if (domain == 0 || domain == IP_AF_INET)
    {
        Ipnet_ip4_addr_entry *addr4;

        addr4 = netif->inet4_addr_list;
        if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT) && addr4 == IP_NULL)
            buf = ipnet_sysctl_if_add_addrs_one(buf, netif, IP_AF_INET, IP_NULL, &len);
        else
            for (; addr4 != IP_NULL; addr4 = addr4->next)
            {
#if defined (IPNGC) || defined (IPQUAGGA)
                /*!! show them or not? */
                if (addr4->type == IPNET_ADDR_TYPE_MULTICAST)
                    continue;
#endif
                if (addr4->type == IPNET_ADDR_TYPE_NETBROADCAST)
                    continue;

                buf = ipnet_sysctl_if_add_addrs_one(buf, netif, IP_AF_INET, addr4, &len);
            }
    }
#endif /* IPCOM_USE_INET */

#ifdef IPCOM_USE_INET6
    if (domain == 0 || domain == IP_AF_INET6)
    {
        Ipnet_ip6_addr_entry *addr6;

        for (addr6 = netif->inet6_addr_list; addr6 != IP_NULL; addr6 = addr6->next)
        {
#if defined (IPNGC) || defined (IPQUAGGA)
            /*!! show them or not? */
            if (addr6->type == IPNET_ADDR_TYPE_MULTICAST)
              continue;
#endif
            buf = ipnet_sysctl_if_add_addrs_one(buf, netif, IP_AF_INET6, addr6, &len);
        }
    }
#endif /* IPCOM_USE_INET6 */

    return (Ip_u16)len;
}
IP_STATIC void
ipnet_cmd_init_addrs_rtp(void *msg, Ip_u32 addrs, struct Ip_sockaddr **sas)
{
    int       i;
    Ip_size_t offset = 0;

    for (i = 0; i < IPNET_RTAX_MAX; i++)
    {
        if (IP_BIT_ISSET(addrs, 1 << i))
        {
            sas[i] = (struct Ip_sockaddr *) &((Ip_u8 *) msg)[offset];
            offset += IPCOM_SA_LEN_GET(sas[i]);
        }
        else
            sas[i] = IP_NULL;
    }
}
Esempio n. 11
0
/*
 *===========================================================================
 *                    ipcom_sysvar_unset
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 */
IP_PUBLIC Ip_err
ipcom_sysvar_unset(const char *name)
{
    Ipcom_sysvar_entry *sysvar;
    Ip_err              retval;
    Ip_size_t           namelen;
    Ipcom_sysvar_tree   *tree;

    retval = ipcom_once(&ipcom_sysvar_once, ipcom_sysvar_init, IP_NULL);
    if (retval != IPCOM_SUCCESS)
        return retval;

    namelen = ipcom_strlen(name);
    if (name[namelen-1] == '*')
        return ipcom_sysvar_for_each(name, ipcom_sysvar_unset_cb, IP_NULL);

    IPCOM_CODE_LOCK();

    tree = ipcom_sysvar_tree_get(-1);
    if (tree == IP_NULL)
    {
        retval = IPCOM_ERR_NO_MEMORY;
        goto leave;
    }

    retval = IPCOM_ERR_NOT_FOUND;
    sysvar = ipcom_hash_get(tree->sysvars, name);
    if (sysvar)
    {
        if(IP_BIT_ISSET(sysvar->flags, IPCOM_SYSVAR_FLAG_READONLY))
            retval = IPCOM_ERR_READONLY;
        else
        {
            ipcom_sysvar_release(tree, sysvar);
            retval = IPCOM_SUCCESS;
        }
    }

 leave:
    ipcom_sysvar_tree_done(tree);
    IPCOM_CODE_UNLOCK();
    return retval;
}
/*
 *===========================================================================
 *                    ipnet_loopback_input
 *===========================================================================
 * Description: Handles loopback packets from the input daemon.
 * Parameters:  netif - A loopback interface.
 *              pkt - The incoming packet.
 * Returns:     0 = success, <0 = error code.
 *
 */
IP_STATIC int
ipnet_loopback_input(Ipnet_netif *netif, Ipcom_pkt *pkt)
{
    Ipnet_loopback_trailer_t *tr;

    ip_assert(IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_ALLOC));

    tr = (Ipnet_loopback_trailer_t *) &pkt->data[pkt->end];
    pkt->ifindex = IP_GET_32ON8(&tr->scope_id);

    /* Verify that the indicated netif exists */
    if (IP_UNLIKELY(ipnet_if_indextonetif(pkt->vr_index, pkt->ifindex) == IP_NULL))
    {
        ipcom_pkt_free(pkt);
        return -IP_ERRNO_EINVAL;
    }

#ifndef IP_PORT_LKM
    IPCOM_PKT_ADD_REF(pkt);
    (void)ipcom_pkt_output_done(&netif->ipcom, pkt, IP_FLAG_FC_STACKCONTEXT);
#endif

    switch (pkt->data[pkt->start] & 0xf0)
    {
#ifdef IPCOM_USE_INET
    case 0x40:
        return ipnet_ip4_input(netif, pkt);
#endif
#ifdef IPCOM_USE_INET6
    case 0x60:
        return ipnet_ip6_input(netif, pkt);
#endif
    default:
        IP_PANIC2();
        ipcom_pkt_free(pkt);
        return -IP_ERRNO_EINVAL;
    }
}
Esempio n. 13
0
/*
 *===========================================================================
 *                    ipnet_sock_tcp_connect
 *===========================================================================
 * Description: The UDP transport layer connect.
 * Parameters:  sock - The socket to connect.
 *              to - The address to connect to.
 *              tolen - The size of the 'to' buffer.
 * Returns:     0 = success, <0 = error code
 *
 */
IP_STATIC int
ipnet_sock_tcp_connect(Ipnet_socket *sock, IP_CONST struct Ip_sockaddr *to, Ip_socklen_t tolen)
{
    Ipnet_sock_tcp_ops *ops = (Ipnet_sock_tcp_ops *) sock->ops;
    int                 ret;

    ret = ops->network_connect(sock, to, tolen);
    if (ret < 0)
        return ret;

    if (sock->dport == 0)
        /* Invalid port */
        return -IP_ERRNO_EINVAL;

    /* The socket is a TCP socket, do the TCP connect */
    if (IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_CONNECTING))
        /* Asynchronous connect is still not finished */
        return -IP_ERRNO_EALREADY;

    if ((ret = ipnet_sock_set_reachable(sock)) < 0)
        return ret;

    return iptcp_connect(sock);
}
Esempio n. 14
0
/*
 *===========================================================================
 *                      ipnet_if_mib_handler_ifTable
 *===========================================================================
 * Description: MIB handler for variables in ifTable
 * Parameters: See file 'ipsnmp.h'
 * Returns: IPSNMP_ERROR_XXX
 *
 */
IP_STATIC Ip_s32
ipnet_if_mib_handler_ifTable(Ip_s32 cmd,
                             char *id,
                             Ipsnmp_varbind *vb,
                             Ip_s32 magic,
                             struct Ipsnmp_node_object *nodeobj)
{
    Ip_s32          lid, ret = -1;
    Ipnet_netif    *best_netif;
    Ip_s32          ifAdminStatus = 0;
    char           *iid;
    char           *buf = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID);
    char           *best = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID);
    struct Ip_ifreq ifreq;
    Ip_fd           fd;

    if (buf == IP_NULL || best == IP_NULL)
    {
        ret = IPSNMP_ERROR_GENERROR;
        goto exit;
    }

    lid = ipsnmp_util_last_subid(nodeobj->id);
    ip_assert(lid >= 1 && lid <= 20);
    ip_assert(lid != 12 && lid != 18);
    best_netif = ipnet_if_mib_table_search_ifTable(id, buf, best, cmd, &ret);
    if (best_netif == IP_NULL)
        goto exit;

    if (cmd == IPSNMP_MIB_COMMAND_GET || cmd == IPSNMP_MIB_COMMAND_NEXT)
    {
        iid = ipsnmp_create_iid_direct(nodeobj->id, best);
        if (iid == IP_NULL)
        {
            ret = IPSNMP_ERROR_GENERROR;
            goto exit;
        }

        switch(lid)
        {
            case 1: /* ifIndex */
                ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.ifindex);
                break;
            case 2: /* ifDescr */
                ret = ipsnmp_util_put_octetstring(magic, iid, (Ip_u8 *)best_netif->ipcom.name, ipcom_strlen(best_netif->ipcom.name));
                break;
            case 3: /* ifType */
                ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.type);
                break;
            case 4: /* ifMtu */
                ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.mtu);
                break;
            case 5: /* ifSpeed */
                if (best_netif->ipcom.type == IP_IFT_PPP)
                    ret = ipsnmp_util_put_gauge32(magic, iid, IPCOM_DRV_PPP_BAUDRATE);
                else
                    ret = ipsnmp_util_put_gauge32(magic, iid, 100000000);
                break;
            case 6: /* ifPhysAddr */
                ret = ipsnmp_util_put_octetstring(magic, iid, best_netif->ipcom.link_addr, best_netif->ipcom.link_addr_size);
                break;
            case 7: /* ifAdminStatus */
                if (IP_BIT_ISSET(best_netif->ipcom.flags, IP_IFF_UP))
                    ret = ipsnmp_util_put_integer(magic, iid, 1);
                else
                    ret = ipsnmp_util_put_integer(magic, iid, 2);
                break;
            case 8: /* ifOperStatus */
                if (IP_BIT_ISSET(best_netif->ipcom.flags, IP_IFF_UP))
                    ret = ipsnmp_util_put_integer(magic, iid, 1);
                else
                    ret = ipsnmp_util_put_integer(magic, iid, 2);
                break;
            case 9: /* ifLastChange */
                ret = ipsnmp_util_put_timeticks(magic, iid, best_netif->ipcom.mib2.ifLastChange);
                break;
            case 10: /* ifInOctets */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInOctets);
                break;
            case 11: /* ifInUcastPkts */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInUcastPkts);
                break;
            case 13: /* ifInDiscards */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInDiscards);
                break;
            case 14: /* ifInErrors */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInErrors);
                break;
            case 15: /* ifInUnknownProtos */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInUnknownProtos);
                break;
            case 16: /* ifOutOctets */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutOctets);
                break;
            case 17: /* ifOutUcastPkts */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutUcastPkts);
                break;
            case 19: /* ifOutDiscards */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutDiscards);
                break;
            case 20: /* ifOutErrors */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutErrors);
                break;
            default:
                IP_PANIC();
                ret = IPSNMP_ERROR_GENERROR;
                break;
        }

        ipcom_free(iid);
    }

    if (cmd == IPSNMP_MIB_COMMAND_TEST || cmd == IPSNMP_MIB_COMMAND_SET)
    {
        switch(lid)
        {
            case 7: /* ifAdminStatus */
                ret = ipsnmp_util_get_integer(vb, &ifAdminStatus);
                if (ret == IPSNMP_ERROR_NOERROR)
                {
                    if (ifAdminStatus != 1 && ifAdminStatus != 2)
                    {
                        ret = IPSNMP_ERROR_WRONGVALUE;
                    }
                }

                if (ret == IPSNMP_ERROR_NOERROR && cmd == IPSNMP_MIB_COMMAND_SET)
                {
                    fd = ipnet_do_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP, IP_FALSE);
                    if(fd != IP_INVALID_SOCKET)
                    {
                        /* Change interface status */
                        ipcom_memset(&ifreq, 0, sizeof(struct Ip_ifreq));
                        ipcom_strcpy(ifreq.ifr_name, best_netif->ipcom.name);
                        if (ipnet_sys_socketioctl(fd, IP_SIOCGIFFLAGS, &ifreq) < 0)
                        {
                            IPCOM_LOG1(ERR, "Failed to get interface flags: %s", ipcom_strerror(ipcom_errno));
                            ret = IPSNMP_ERROR_GENERROR;
                        }
                        if (ifAdminStatus == 1)
                            IP_BIT_SET(ifreq.ip_ifr_flags, IP_IFF_UP);
                        else
                            IP_BIT_CLR(ifreq.ip_ifr_flags, IP_IFF_UP);
                        if (ipnet_sys_socketioctl(fd, IP_SIOCSIFFLAGS, &ifreq) < 0)
                        {
                            IPCOM_LOG1(ERR, "Failed to set interface flags: %s", ipcom_strerror(ipcom_errno));
                            ret = IPSNMP_ERROR_GENERROR;
                        }
                        ipnet_sys_socketclose(fd);
                    }
                    else
                    {
                        IPCOM_LOG0(ERR, "Failed to create socket for ioctl call");
                        ret = IPSNMP_ERROR_GENERROR;
                    }
                }
                break;
            default:
                IP_PANIC();
                ret = IPSNMP_ERROR_GENERROR;
                break;
        }
    }

exit:
    if (buf != IP_NULL)
        ipcom_free(buf);
    if (best != IP_NULL)
        ipcom_free(best);
    return ret;
}
/*
 *===========================================================================
 *                    ipnet_sysctl_route_dump_cb
 *===========================================================================
 * Description: Checks if this entry should be added and adds it if it should.
 * Parameters:  rt - the route entry to add
 *              data - callback data.
 * Returns:     IP_FALSE (the entry should never be deleted).
 *
 */
IP_STATIC Ip_bool
ipnet_sysctl_route_dump_cb(Ipnet_route_entry *rt, Ipnet_sysctl_route_data *data)
{
    struct Ipnet_rt_msghdr *rt_msg;
    Ip_u16                  len;

    if (rt->next)
        (void)ipnet_sysctl_route_dump_cb(rt->next, data);

    if (rt->narrow)
        (void) ipnet_sysctl_route_dump_cb(rt->narrow, data);

    if ((rt->hdr.flags & data->flags) != data->flags)
        return IP_FALSE;

    /* Do not list the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */
    if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN))
          return IP_FALSE;

    len = ipnet_sysctl_route_dump_elem_len(rt);
    data->bytes_written += len;

    if (data->bytes_written > data->buf_len)
    {
        /* Buffer to small */
        if (data->buf != IP_NULL)
            data->soerrno = -IP_ERRNO_ENOMEM;
        return IP_FALSE;
    }

    rt_msg = (struct Ipnet_rt_msghdr *) data->buf;
    data->buf = (Ip_u8 *) data->buf + sizeof(struct Ipnet_rt_msghdr);

    ipcom_memset(rt_msg, 0, sizeof(struct Ipnet_rt_msghdr));
    rt_msg->rtm_msglen  = len;
    rt_msg->rtm_version = IPNET_RTM_VERSION;
    rt_msg->rtm_type    = IPNET_RTM_GET;
    rt_msg->rtm_index   = rt->netif ? rt->netif->ipcom.ifindex : 0;
    rt_msg->rtm_table   = data->table;
    rt_msg->rtm_flags   = rt->hdr.flags;
    rt_msg->rtm_use     = rt->use;
    rt_msg->rtm_rmx     = rt->metrics;

    /* add destination address */
    IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_DST);
    data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.key);

    if (rt->gateway)
    {
        IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY);
        ipcom_memcpy(data->buf, rt->gateway, IPCOM_SA_LEN_GET(rt->gateway));
        data->buf = (Ip_u8 *) data->buf + IPCOM_SA_LEN_GET(rt->gateway);
    }
    else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING))
    {
        struct Ip_sockaddr_dl  *dl = data->buf;
        IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY);
        ipcom_memset(data->buf, 0, sizeof(struct Ip_sockaddr_dl));
        IPCOM_SA_LEN_SET(dl, sizeof(struct Ip_sockaddr_dl));
        dl->sdl_family = IP_AF_LINK;
        ip_assert(rt->netif != IP_NULL);
        if (rt->netif != IP_NULL)
        {
            dl->sdl_index  = (Ip_u16)rt->netif->ipcom.ifindex;
            dl->sdl_type   = (Ip_u8)rt->netif->ipcom.type;
        }
        data->buf = (Ip_u8 *) data->buf + sizeof(struct Ip_sockaddr_dl);
    }

    if (rt->hdr.mask)
    {
        /* add destination mask */
        IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_NETMASK);
        data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.mask);
    }

    ip_assert((Ip_u16)((Ip_ptrdiff_t) data->buf - (Ip_ptrdiff_t) rt_msg) == len);

    return IP_FALSE;
}
/*
 *===========================================================================
 *                    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);
}
Esempio n. 17
0
/*
 *===========================================================================
 *                    ipcom_sysvar_set_internal
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 */
IP_GLOBAL Ip_err
ipcom_sysvar_set_tree(const char *name, const char *value, int flags, Ipcom_sysvar_tree *tree)
{
    Ip_size_t           name_length;
    Ip_size_t           value_length;
    Ipcom_sysvar_entry  *sysvar;
    Ip_err              retval = IPCOM_SUCCESS;

    /* Check for duplicate. */
    sysvar = ipcom_hash_get(tree->sysvars, name);
    if (sysvar)
    {
        if (IP_BIT_ISSET(sysvar->flags, IPCOM_SYSVAR_FLAG_READONLY))
        {
            retval = IPCOM_ERR_READONLY;
            goto leave;
        }
        else if (IP_BIT_ISFALSE(flags, IPCOM_SYSVAR_FLAG_OVERWRITE))
        {
            retval = IPCOM_ERR_DUPLICATE;
            goto leave;
        }
        else
        {
            flags |= sysvar->flags & IPCOM_SYSVAR_FLAG_KERNEL;
            ipcom_hash_remove(tree->sysvars, sysvar);
            ipcom_free(sysvar);
            goto set;
        }
    }

    /* No current entry found and not allowed to create a new entry. */
    if(IP_BIT_ISSET(flags, IPCOM_SYSVAR_FLAG_NOCREATE))
    {
        retval = IPCOM_ERR_FAILED;
        goto leave;
    }

    /* Add the new sysvar. */
 set:
     name_length = ipcom_strlen(name) + 1;
     value_length = ipcom_strlen(value) + 1;
     sysvar = ipcom_malloc(sizeof(Ipcom_sysvar_entry) + name_length + value_length);

     if(sysvar == IP_NULL)
     {
         retval = IPCOM_ERR_NO_MEMORY;
         goto leave;
     }

     sysvar->refcount = 1;
     sysvar->flags    = flags;
     if (IP_BIT_ISFALSE(flags, IPCOM_SYSVAR_FLAG_INIT))
     {
         tree->modified = IP_TRUE;
         sysvar->flags |= IPCOM_SYSVAR_FLAG_MODIFIED;
     }
     sysvar->name     = (const char *)sysvar + sizeof(Ipcom_sysvar_entry);
     ipcom_memcpy((void *)sysvar->name, name, name_length);
     sysvar->value    = sysvar->name + name_length;
     ipcom_memcpy((void *)sysvar->value, value, value_length);

     retval = ipcom_hash_add(tree->sysvars, sysvar);

 leave:
    return retval; /*lint !e429 Custodial pointer 'sysvar' has not been freed or returned */
}
/*
 *===========================================================================
 *                      ipnet_ip_mib_cb_ipCidrRouteTable
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC Ip_bool
ipnet_ip_mib_cb_ipCidrRouteTable(Ipnet_route_entry *rt, Ipsnmp_route_walk *rwp)
{
    Ip_s32 tmp, lex, len = 0;

    /* Early exit if exact match was found previously */
    if(rwp->bestrt != IP_NULL &&
        (rwp->cmd == IPSNMP_MIB_COMMAND_GET
        || rwp->cmd == IPSNMP_MIB_COMMAND_TEST
        || rwp->cmd == IPSNMP_MIB_COMMAND_SET))
        goto exit;

    if(rt->netif == IP_NULL)
        goto exit;

    /* Do not use hidden entries */
    if(IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_HIDDEN))
        goto exit;

    /* Route must be usable */
    if(IP_BIT_ISFALSE(rt->hdr.flags, IPNET_RTF_UP))
        goto exit;

    /* Do not use link layer entries */
    if(IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_LLINFO))
        goto exit;

    /* Do not use loopback entries */
    if (IP_BIT_ISSET(rt->netif->ipcom.flags, IP_IFF_LOOPBACK))
        goto exit;

    ip_assert(rt->hdr.key != IP_NULL);

    /* Do not use multicast entries */
    if(IP_IN_CLASSD(*(Ip_u32 *)rt->hdr.key))
        goto exit;

    /* Do not use broadcast entries */
    if(ip_ntohl(*(Ip_u32 *)rt->hdr.key) == IP_INADDR_BROADCAST)
        goto exit;

    if(rwp->count_only == IP_TRUE)
    {
        count++;
        goto exit;
    }

    rwp->buf[0] = '\0';
    /* ipCidrRouteDest */
    if(ipcom_inet_ntop(IP_AF_INET, rt->hdr.key, &rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len) == IP_NULL)
        goto exit;
    len = ipcom_strlen(rwp->buf);
    if(ipcom_snprintf(&rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, ".") < 0)
        goto exit;
    len = ipcom_strlen(rwp->buf);

    /* ipCidrRouteMask */
    if(rt->hdr.mask == IP_NULL)
    {
        if(ipcom_snprintf(&rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, "255.255.255.255") < 0)
            goto exit;
    }
    else
    {
        if(ipcom_inet_ntop(IP_AF_INET, rt->hdr.mask, &rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len) == IP_NULL)
            goto exit;
    }
    len = ipcom_strlen(rwp->buf);
    if(ipcom_snprintf(&rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, ".") < 0)
        goto exit;
    len = ipcom_strlen(rwp->buf);

    /* ipCidrRouteTos */
    tmp = 0;
    if(ipcom_snprintf(&rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, "%d.", (int)tmp) < 0)
        goto exit;
    len = ipcom_strlen(rwp->buf);

    /* ipCidrRouteNextHop */
    if(IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_GATEWAY))
    {
        struct Ip_sockaddr_in *sa;

        ip_assert(rt->gateway != IP_NULL);
        sa = (struct Ip_sockaddr_in *)rt->gateway;
        if(ipcom_inet_ntop(IP_AF_INET, &sa->sin_addr.s_addr, &rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID - len) == IP_NULL)
            goto exit;
    }
    else
    {
        if(ipcom_snprintf(&rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, "0.0.0.0") < 0)
            goto exit;
    }
    len = ipcom_strlen(rwp->buf);
    if(ipcom_snprintf(&rwp->buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, ".") < 0)
        goto exit;
    len = ipcom_strlen(rwp->buf);
    if(len)
        rwp->buf[len-1] = '\0';

    lex = ipsnmp_util_lexcmp_oid(rwp->buf, rwp->id);
    if(rwp->cmd == IPSNMP_MIB_COMMAND_NEXT)
    {
        if(lex > 0)
        {
            if(rwp->bestrt == IP_NULL || ipsnmp_util_lexcmp_oid(rwp->buf, rwp->best) < 0)
            {
                ipcom_strcpy(rwp->best, rwp->buf);
                rwp->bestrt = rt;
            }
        }
    }
    else
    {
        if(lex == 0)
        {
            ipcom_strcpy(rwp->best, rwp->buf);
            rwp->bestrt = rt;
        }
    }

exit:
    /* Do not delete the entry */
    return IP_FALSE;
}
/*
 *===========================================================================
 *                    ipnet_cmd_sysctl_do
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:     0 on success, -1 on syntax error. > 0 unknown key
 *
 */
IP_STATIC int
ipnet_cmd_sysctl_do(Ip_bool         set,
                    const char      *var)
{
    char                    *dupval = ipcom_strdup(var);
    char                    *tok;
    char                    *ntok;
    char                    *last;
    char                    *value      = IP_NULL;
    char                    *names[12];
    int                     nameslen    = 0;
    int                     name[12];
    int                     namelen     = 0;
    const Ipnet_cmd_sysctl  *current    = ipnet_sysctl_base_table;
    const Ipnet_cmd_sysctl  *ctl        = IP_NULL;
    int                     err         = -1;
    const char              *netif      = IP_NULL;
    int                     argbit      = IPNET_CMD_SYSCTL_NETIF_NO;

    if (set)
    {
        tok = ipcom_strtok_r(dupval, "=", &last);
        if (tok == IP_NULL)
            goto done;
        value = ipcom_strtok_r(IP_NULL, "=", &last);
        if (value == IP_NULL)
            goto done;
    }

    err = 1;
    tok = ipcom_strtok_r(dupval, ".", &last);
    while (tok != IP_NULL)
    {
        ntok = ipcom_strtok_r(IP_NULL, ".", &last);
        ctl = current;

        /* */
        while (ctl->comp != IP_NULL)
        {
            if (IP_BIT_ISSET(ctl->argument, argbit))
            {
                if (ipnet_cmd_sysctl_strcmp(ctl, tok, name, &namelen, names, &nameslen) == IP_TRUE)
                {
                    if (ctl->type == IPNET_CMD_SYSCTL_TYPE_TRUNK)
                    {
                        current = ctl->ntable;
                        break;
                    }
                    else
                    {
                        /* EOL */
                        if (ntok)
                            goto done;

                        /* Check any cached netif's */
                        if (netif)
                        {
                            name[namelen++] = ipcom_if_nametoindex(netif);
                            netif = IP_NULL;
                        }

                        /* We're done */
                        if (ipnet_cmd_sysctl_exec(ctl, set, name, namelen, names, nameslen, value))
                            err = 0;

                        /**/
                        goto done;
                    }
                }
            }

            ctl++;
        }

        /* We've failed */
        if (ctl->comp == IP_NULL)
        {
            /* Check interface */
            if (argbit == IPNET_CMD_SYSCTL_NETIF_NO && ipcom_if_nametoindex(tok) != 0)
            {
                netif               = tok;
                names[nameslen++]   = tok;
                argbit = IPNET_CMD_SYSCTL_NETIF_YES;
            }
            else
            {
                ipcom_printf("sysctl: Failed to parse subkey %s"IP_LF, tok);
                goto done;
            }
        }
        else
        {
            argbit  = IPNET_CMD_SYSCTL_NETIF_NO;
            netif   = IP_NULL;
        }

        /* Store next */
        tok     = ntok;
    }

    /* Do dump */
    if (set == IP_FALSE)
    {
        ipnet_cmd_sysctl_print_ctl(current,
                                   name,
                                   namelen,
                                   names,
                                   nameslen,
                                   IP_NULL);
        err = 0;
    }

done:
    ipcom_free(dupval);
    return err;
}
/*
 *===========================================================================
 *                    ipnet_cmd_sysctl_print_ctl
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC void
ipnet_cmd_sysctl_print_ctl(const Ipnet_cmd_sysctl  *ctl,
                           int                     *name,
                           int                     namelen,
                           char                    **names,
                           int                     nameslen,
                           const Ipnet_cmd_sysctl  *skip)
{
    int cnamelen  = namelen;
    int cnameslen = nameslen;

    (void) skip;
    while (ctl->comp != IP_NULL)
    {
        if (IP_BIT_ISSET(ctl->argument, IPNET_CMD_SYSCTL_NETIF_NO))
        {
            /* Resolve this particular node */
            if (ipnet_cmd_sysctl_strcmp(ctl, ctl->comp, name, &cnamelen, names, &cnameslen))
            {
                if (ctl->type == IPNET_CMD_SYSCTL_TYPE_TRUNK)
                {
                    /* Go to the next table */
                    ipnet_cmd_sysctl_print_ctl(ctl->ntable, name, cnamelen, names, cnameslen, IP_NULL);
                }
                else
                {
                    if (ipnet_cmd_sysctl_exec(ctl, IP_FALSE, name, cnamelen, names, cnameslen, IP_NULL) == IP_FALSE)
                    {
                        ipcom_printf("failed to get: ");
                        ipnet_cmd_sysctl_print_key(names, cnameslen);
                        ipcom_printf(IP_LF);
                    }
                }
            }
        }

        /* Do the netifs */
        if (IP_BIT_ISSET(ctl->argument, IPNET_CMD_SYSCTL_NETIF_YES))
        {
            /* Dump the arguments */
            char **argv = ipnet_cmd_sysctl_dump_netif();

            if (argv)
            {
                int  i;

                for (i = 0; argv[i] != IP_NULL; i++)
                {
                    cnamelen    = namelen;
                    cnameslen   = nameslen;

                    names[cnameslen++] = argv[i];
                    if (ipnet_cmd_sysctl_strcmp(ctl, ctl->comp, name, &cnamelen, names, &cnameslen))
                    {
                        name[cnamelen++] = ipcom_if_nametoindex(argv[i]);

                        if (ctl->type == IPNET_CMD_SYSCTL_TYPE_TRUNK)
                        {
                            /* Go to the next table */
                            ipnet_cmd_sysctl_print_ctl(ctl->ntable, name, cnamelen, names, cnameslen, IP_NULL);
                        }
                        else
                        {
                            if (ipnet_cmd_sysctl_exec(ctl, IP_FALSE, name, cnamelen, names, cnameslen, IP_NULL) == IP_FALSE)
                            {
                                ipcom_printf("failed to get: ");
                                ipnet_cmd_sysctl_print_key(names, cnameslen);
                                ipcom_printf(IP_LF);
                            }
                        }
                    }

                    ipcom_free(argv[i]);
                }

                ipcom_free(argv);
            }
        }

        ctl++;
        cnamelen    = namelen;
        cnameslen   = nameslen;
    }
}
/*
 *===========================================================================
 *                      ipnet_ip_forward_mib_handler_ipCidrRouteTable
 *===========================================================================
 * Description: MIB handler for ipCidrRouteDest
 * Parameters: See file 'ipsnmp.h'
 * Returns: IPSNMP_ERROR_XXX
 *
 */
IP_STATIC Ip_s32
ipnet_ip_forward_mib_handler_ipCidrRouteTable(Ip_s32 cmd,
                                              char *id,
                                              Ipsnmp_varbind *vb,
                                              Ip_s32 magic,
                                              struct Ipsnmp_node_object *nodeobj)
{
    Ip_s32 lid, bestindex, ret = -1;
    char *iid;
    char *buf = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID);
    char *best = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID);

    if(buf == IP_NULL || best == IP_NULL)
    {
        ret = IPSNMP_ERROR_GENERROR;
        goto exit;
    }

    lid = ipsnmp_util_last_subid(nodeobj->id);
    ip_assert(lid >= 1 && lid <= 16);
    bestindex = ipnet_ip_forward_mib_table_search_ipCidrRouteTable(id, buf, best, cmd);
    if(bestindex == -2)
    {
        ret = IPSNMP_ERROR_GENERROR;
        goto exit;
    }
    else if(bestindex == -1)
    {
        ret = IPSNMP_ERROR_NOSUCHNAME;
        goto exit;
    }

    if(cmd == IPSNMP_MIB_COMMAND_GET || cmd == IPSNMP_MIB_COMMAND_NEXT)
    {
        iid = ipsnmp_create_iid_direct(nodeobj->id, best);
        if(iid == IP_NULL)
        {
            ret = IPSNMP_ERROR_GENERROR;
            goto exit;
        }

        ip_assert(routewalk.bestrt != IP_NULL);
        switch(lid)
        {
            case 1: /* ipCidrRouteDest */
                ret = ipsnmp_util_put_ipaddress(magic, iid, ip_ntohl(*(Ip_u32 *)routewalk.bestrt->hdr.key));
                break;
            case 2: /* ipCidrRouteMask */
                if(routewalk.bestrt->hdr.mask != IP_NULL)
                    ret = ipsnmp_util_put_ipaddress(magic, iid, ip_ntohl(*(Ip_u32 *)routewalk.bestrt->hdr.mask));
                else
                    ret = ipsnmp_util_put_ipaddress(magic, iid, 0xffffffff);
                break;
            case 3: /* ipCidrRouteTos */
                ret = ipsnmp_util_put_integer(magic, iid, 0);
                break;
            case 4: /* ipCidrRouteNextHop */
                if(IP_BIT_ISSET(routewalk.bestrt->hdr.flags, IPNET_RTF_GATEWAY))
                {
                    struct Ip_sockaddr_in *sa = (struct Ip_sockaddr_in *)routewalk.bestrt->gateway;
                    ret = ipsnmp_util_put_ipaddress(magic, iid, ip_ntohl(sa->sin_addr.s_addr));
                }
                else
                    ret = ipsnmp_util_put_ipaddress(magic, iid, 0);
                break;
            case 5: /* ipCidrRouteIfIndex */
                ret = ipsnmp_util_put_integer(magic, iid, routewalk.bestrt->netif->ipcom.ifindex);
                break;
            case 6: /* ipCidrRouteType */
                if(IP_BIT_ISSET(routewalk.bestrt->hdr.flags, IPNET_RTF_GATEWAY))
                    ret = ipsnmp_util_put_integer(magic, iid, 4);   /* remote */
                else
                    ret = ipsnmp_util_put_integer(magic, iid, 3);   /* local */
                break;
            case 7: /* ipCidrRouteProto */
                ret = ipsnmp_util_put_integer(magic, iid, 2);   /* local */
                break;
            case 8: /* ipCidrRouteAge */
                ret = ipsnmp_util_put_integer(magic, iid, 0);
                break;
            case 9: /* ipCidrRouteInfo */
                ret = ipsnmp_util_put_oid(magic, iid, "0.0");
                break;
            case 10: /* ipCidrRouteNextHopAS */
                ret = ipsnmp_util_put_integer(magic, iid, 0);
                break;
            case 11: /* ipCidrRouteMetric1 */
                ret = ipsnmp_util_put_integer(magic, iid, -1);
                break;
            case 12: /* ipCidrRouteMetric2 */
                ret = ipsnmp_util_put_integer(magic, iid, -1);
                break;
            case 13: /* ipCidrRouteMetric3 */
                ret = ipsnmp_util_put_integer(magic, iid, -1);
                break;
            case 14: /* ipCidrRouteMetric4 */
                ret = ipsnmp_util_put_integer(magic, iid, -1);
                break;
            case 15: /* ipCidrRouteMetric5 */
                ret = ipsnmp_util_put_integer(magic, iid, -1);
                break;
            case 16: /* ipCidrRouteStatus */
                ret = ipsnmp_util_put_integer(magic, iid, 1);   /* active */
                break;
            default:
                IP_PANIC();
                ret = IPSNMP_ERROR_GENERROR;
                break;
        }

        ipcom_free(iid);
    }

    if(cmd == IPSNMP_MIB_COMMAND_TEST || cmd == IPSNMP_MIB_COMMAND_SET)
    {
        (void)vb;
        switch(lid)
        {
            case 5: /* ipCidrRouteIfIndex */
            case 6: /* ipCidrRouteType */
            case 9: /* ipCidrRouteInfo */
            case 10: /* ipCidrRouteNextHopAS */
            case 11: /* ipCidrRouteMetric1 */
            case 12: /* ipCidrRouteMetric2 */
            case 13: /* ipCidrRouteMetric3 */
            case 14: /* ipCidrRouteMetric4 */
            case 15: /* ipCidrRouteMetric5 */
            case 16: /* ipCidrRouteStatus */
                ret = IPSNMP_ERROR_NOSUCHNAME;
                break;
            default:
                IP_PANIC();
                ret = IPSNMP_ERROR_GENERROR;
                break;
        }
    }

exit:
    if(buf != IP_NULL)
        ipcom_free(buf);
    if(best != IP_NULL)
        ipcom_free(best);
    return ret;
}
Esempio n. 22
0
/*
 *===========================================================================
 *                    ipnet_udp_input
 *===========================================================================
 * Description: Input handler for packet to UDP sockets. This function will
 *              NOT free the packet if the operation fails.
 * Parameters:  pkt - The received packet, must be freed by the called if
 *              this function fails.
 *              is_multicast - Set to IP_TRUE if the packet was sent to a
 *              multicast address.
 *              proto - The protocol number.
 *              src_addr - The address (Ipv4 or IPv6) of the sender.
 *              dst_addr - The address (Ipv4 or IPv6) of the receiver (this system).
 *              socklookup - A pointer to a function that can return the socket
 *              that is associated with this packet.
 *              nat_t   - NAT traversal; if used.
 * Returns:     0 >= number of matching sockets, <0 = error code
 *
 */
IP_GLOBAL int
ipnet_udp_input(Ipcom_pkt *pkt, Ip_bool is_multicast,
                IP_CONST void* src_addr, IP_CONST void* dst_addr,
                Ipnet_sock_lookup_f socklookup,
                int   *nat_t)
{
    Ipnet_pkt_udp *udp_hdr;
    int            retval;
    int            ulen_h;
    Ipnet_socket  *sock;
    Ip_u16         src_port;
    Ip_u16         dst_port;
    Ip_bool        pkt_no_rx_cache;


    IPCOM_WV_MARKER_1 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_VERBOSE, 1, 3, IPCOM_WV_NETDEVENT_START,
                       ipnet_udp_input, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
    IPNET_STATS(udp_input++);
    IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_UDP_INPUT);

    if (IP_UNLIKELY(pkt->end - pkt->start < IPNET_UDP_HDR_SIZE))
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                          1, 4, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_BADHLEN,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_hdr_trunc++);
        IPCOM_MIB2(udpInErrors++);
        return -IP_ERRNO_EINVAL;
    }

    udp_hdr = (Ipnet_pkt_udp*) &pkt->data[pkt->start];
    ulen_h = ip_ntohs(udp_hdr->ulen);
    src_port = ip_ntohs(udp_hdr->sport);
    dst_port = ip_ntohs(udp_hdr->dport);

    if (IP_UNLIKELY(pkt->end - pkt->start < ulen_h))
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                          1, 5, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_BADLEN,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_hdr_trunc++);
        IPCOM_MIB2(udpInErrors++);
        return -IP_ERRNO_EINVAL;
    }
    pkt->end = pkt->start + ulen_h;

    if (udp_hdr->sum != 0 && IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK))
    {
        Ip_u16 chksum;
        /* Only check packets that was not created locally */
#ifdef IPCOM_USE_HW_CHECKSUM_RX
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_HW_CHECKSUM))
            chksum = 0;
        else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_TL_CHECKSUM))
            chksum = ipcom_in_checksum_finish(pkt->chk);
        else
#endif /* IPCOM_USE_HW_CHECKSUM_RX */
        {
            pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->start], (Ip_size_t) ulen_h);
            chksum = ipcom_in_checksum_finish(pkt->chk);
        }

        if (IP_UNLIKELY(chksum != 0))
        {
            /* Wrong checksum */
            IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                              1, 6, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                              ipnet_udp_input, IPCOM_WV_NETD_BADSUM,
                              IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
            IPNET_STATS(udp_input_badchksum++);
            IPCOM_MIB2(udpInErrors++);
            return -IP_ERRNO_EINVAL;
        }
    }

    /* Move the start to beginning of application data */
    pkt->start += IPNET_UDP_HDR_SIZE;

    if (is_multicast)
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO,
                          1, 7, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_multicast++);
        retval = ipnet_raw_input(pkt, IP_FALSE, IP_IPPROTO_UDP,
                                 src_addr, src_port,
                                 dst_addr, dst_port,
                                 socklookup);
        if (retval >= 0)
        {
            /* The packet must be freed unlesss an error occured */
            ipcom_pkt_free(pkt);
            IPCOM_MIB2(udpInDatagrams++);
            IPCOM_MIB2_U64_INC(udpHCInDatagrams);
        }
        else
        {
            IPCOM_MIB2(udpInErrors++);
        }
        return retval;
    }

    sock = socklookup(pkt->vr_index,
                      IP_IPPROTO_UDP,
                      dst_addr,
                      dst_port,
                      src_addr,
                      src_port);
    if (sock == IP_NULL)
        /* No matching socket, try the wildcard group */
        sock = socklookup(IPCOM_VR_ANY,
                          IP_IPPROTO_UDP,
                          dst_addr,
                          dst_port,
                          src_addr,
                          src_port);

    if (sock != IP_NULL)
    {
        Ipcom_socket_eventcb event_cb = sock->ipcom.event_cb;

        /* Verify NAT traversal */
        if (IP_UNLIKELY(ipnet_udp_encapsulation(sock, pkt, nat_t)))
        {
            ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_ENCAP_UDP, sizeof(*udp_hdr), udp_hdr);
            pkt->start -= IPNET_UDP_HDR_SIZE;
            return 0;
        }

        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO,
                          1, 8, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_sock_match++);
        pkt->fd = sock->ipcom.fd;
        pkt_no_rx_cache = IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_NO_RX_CACHE);

        retval = ipnet_queue_received_packet(pkt, sock);
        if (retval < 0)
        {
            IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                              1, 9, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                              ipnet_udp_input, IPCOM_WV_NETD_INFO_QUEUE_FULL,
                              IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
            IPNET_STATS(udp_input_queue_pkt_err++);
            IPCOM_MIB2(udpInErrors++);
            return retval;
        }

        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO,
                          1, 10, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_queue_pkt_ok++);

        if (event_cb != IP_NULL)
            event_cb(&sock->ipcom, pkt, IP_SOEVENT_CB_INPKT);

        IPCOM_MIB2(udpInDatagrams++);
        IPCOM_MIB2_U64_INC(udpHCInDatagrams);

        if (IP_BIT_ISFALSE(sock->flags, IPNET_SOCKET_FLAG_RX_CACHED)
            && !pkt_no_rx_cache)
            ipnet_sock_add_to_rx_cache(sock,
                                       src_addr,
                                       src_port,
                                       dst_addr,
                                       dst_port,
                                       ipnet_udp_fast_deliver_data);

        return 1;
    }
    else
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                          1, 13, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_NOPORT,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_sock_nomatch++);
        IPCOM_MIB2(udpNoPorts++);
    }

    IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                      1, 14, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                      ipnet_udp_input, IPCOM_WV_NETD_NOPORT,
                      IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
    IPNET_STATS(udp_input_econnrefused++);
    return -IP_ERRNO_ECONNREFUSED;
}
/*
 *===========================================================================
 *                    ipcom_drv_ppp_ioctl
 *===========================================================================
 * Description: IO control.
 * Parameters:  netif - A network interface.
 *              command - The control task to perform.
 *              data - Data associated with the specified command.
 * Returns:     0 = success, <0 = error code
 *
 */
IP_STATIC int
ipcom_drv_ppp_ioctl(Ipcom_netif *netif, Ip_u32 command, void *data)
{
    Ipcom_pdrv_ppp      *pdrv;
    Ipcom_drv_ppp_link  *plink;
    struct Ip_pppreq    *pppreq;
    int ret;

    pdrv  = (Ipcom_pdrv_ppp *)netif->pdrv;
    plink = &pdrv->plink[netif->link_index];
    pppreq = data;

    switch (command)
    {
    case IP_SIOCXOPEN:
    case IP_SIOCXPPPSDRVUP:
        /* Create the driver. */
        ret = ipcom_drv_ppp_init(plink);
        if (ret != 0)
            return ret;

        /* Signal link up immediately. */
        netif->link_ioevent(netif, IP_EIOXUP, IP_NULL, 0);
        break;

    case IP_SIOCXCLOSE:
    case IP_SIOCXPPPSDRVDOWN:
        /* Kill the driver. */
        if (ipcom_drv_ppp_exit(plink) != 0)
            return -IP_ERRNO_EINVAL;

        /* Signal link down immediately. */
        netif->link_ioevent(netif, IP_EIOXDOWN, IP_NULL, 0);
        break;

    case IP_SIOCIFDESTROY:
        if (IP_BIT_ISSET(netif->flags, IP_IFF_RUNNING))
            return -IP_ERRNO_EBUSY;
        ret = ipcom_if_detach(netif);
        if (ret != 0)
            return 0;
        if (plink->devname)
            ipcom_free(plink->devname);
        if (pdrv != IP_NULL)
            ipcom_free(pdrv);
        return ipcom_if_free(netif);

    case IP_SIOCXPPPGDRVCONF:
        pppreq->pppru.drvconf.drv_flags = 0; /* See ipcom_netif.h for IP_DRVPPP_FLAG_xxx options. */
        pppreq->pppru.drvconf.baudrate = plink->baudrate;
        pppreq->pppru.drvconf.rcv_accm = 0xffffffff;
        pppreq->pppru.drvconf.snd_accm = 0xffffffff;
        pppreq->pppru.drvconf.mru = 1500;
        pppreq->pppru.drvconf.mtu = 1500;
        break;

    case IP_SIOCXPPPSDRVBAUDRATE:
        /* Running, change the baudrate. */
        if (plink->fd != -1)
            if (ioctl(plink->fd, FIOBAUDRATE, pppreq->pppru.drv_baudrate) != OK)
                return -IP_ERRNO_EINVAL;

        /* Baudrate changed. */
        plink->baudrate = pppreq->pppru.drv_baudrate;
        break;

    case IP_SIOCXPPPSDRVWINCOMPAT:
        plink->wincompat = pppreq->pppru.drv_wincompat;
        break;

    case IP_SIOCXPROMISC:
        if (*(Ip_bool *) data)
            IP_BIT_SET(netif->flags, IP_IFF_PROMISC);
        else
            IP_BIT_CLR(netif->flags, IP_IFF_PROMISC);
        break;

    default:
        return -IP_ERRNO_EINVAL;
    }

    return 0;
}
/*
 *===========================================================================
 *                    ipnet_gre_output_append
 *===========================================================================
 * Description: Handler for packets to send.
 * Parameters:  pkt - Packet to send and append GRE header to.
 * Returns:     0 = success, <0 = error code.
 *
 */
IP_GLOBAL int
ipnet_gre_output_append(Ipnet_netif *netif, struct Ip_ip_tunnel_param *tunnel_param, Ipcom_pkt *pkt)
{
    Ipnet_pkt_gre          *gre_hdr;
    Ipnet_pkt_gre_opt_csum *csum_opt = IP_NULL;
#ifdef IPNET_USE_RFC2890
    Ip_u32                 *key_opt = IP_NULL;
    Ip_u32                 *key_opt_info;
    Ip_u32                 *seqnum_opt = IP_NULL;
    Ipnet_gre_t            *gre = netif->ipcom.pdrv;
#endif

    ip_assert(pkt->start >= (IPNET_GRE_MAX_HDR_SIZE + IPNET_IP_HDR_SIZE));

#ifdef IPNET_USE_RFC2890
    if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_LINK1))
    {
        pkt->start -= IPNET_GRE_OPT_SEQNUM_SIZE;
        seqnum_opt = (Ip_u32 *) &pkt->data[pkt->start];
        IP_SET_HTONL(seqnum_opt, gre->send_seqnum);
        ++gre->send_seqnum;
    }

    if ((key_opt_info = ipcom_pkt_get_info(pkt, IPNET_PKT_INFO_GRE_KEY_OUTPUT)) != IP_NULL)
    {
        pkt->start -= IPNET_GRE_OPT_KEY_SIZE;
        key_opt = (Ip_u32 *) &pkt->data[pkt->start];
        IP_SET_HTONL(key_opt, *key_opt_info);
    }
#endif /* IPNET_USE_RFC2890 */

    if (IP_BIT_ISTRUE(tunnel_param->o_flags, IPCOM_TUNNEL_FLAG_GRE_CHECKSUM)
        || IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_LINK2))
    {
        /* GRE output checksum enabled. */
        pkt->start -= IPNET_GRE_OPT_CSUM_SIZE;
        csum_opt = (Ipnet_pkt_gre_opt_csum *) &pkt->data[pkt->start];
        csum_opt->checksum  = 0;
        csum_opt->reserved1 = 0;
    }

    /* Add GRE header. */
    pkt->start -= IPNET_GRE_HDR_SIZE;
    gre_hdr = (Ipnet_pkt_gre *)&pkt->data[pkt->start];
    gre_hdr->flags_reserved0_ver = 0;
    switch (pkt->data[pkt->ipstart] & 0xf0)
    {
#ifdef IPCOM_USE_INET
    case 0x40:
        gre_hdr->protocol_type = IPNET_GRE_PROTOCOL_TYPE_IPV4;
        break;
#endif
#ifdef IPCOM_USE_INET6
    case 0x60:
        gre_hdr->protocol_type = IPNET_GRE_PROTOCOL_TYPE_IPV6;
        break;
#endif
    default:
        return -IP_ERRNO_EPROTONOSUPPORT;
    }

#ifdef IPNET_USE_RFC2890
    if (key_opt != IP_NULL)
        IP_BIT_SET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_KEY);

    if (seqnum_opt != IP_NULL)
        IP_BIT_SET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_SEQNUM);
#endif /* IPNET_USE_RFC2890 */

    if (csum_opt != IP_NULL)
    {
        /* The whole GRE header is written, time to calculate the checksum */
        IP_BIT_SET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_CHECKSUM);
        csum_opt->checksum = ipcom_in_checksum(gre_hdr, pkt->end - pkt->start);
    }

    return 0;
}
/*
 *===========================================================================
 *                    ipnet_gre_input
 *===========================================================================
 * Description: Handler for received GRE packets.
 * Parameters:  pkt - Received GRE packet.
 * Returns:     0 = success, <0 = error code.
 *
 */
IP_GLOBAL int
ipnet_gre_input(Ipnet_netif *netif, Ipcom_pkt *pkt)
{
    Ipnet_pkt_gre *gre_hdr;
    int            gre_hdr_start = pkt->start;

    IP_BIT_CLR(pkt->flags, IPCOM_PKT_FLAG_IPV4 | IPCOM_PKT_FLAG_IPV6);
    gre_hdr = (Ipnet_pkt_gre *)&pkt->data[pkt->start];
    pkt->start += IPNET_GRE_HDR_SIZE;

    /* First 16-bits non-null, verify bits and version. */
    if (gre_hdr->flags_reserved0_ver)
    {
        /* RFC 2784: 2.3. Reserved0 (bits 1-12)
           A receiver MUST discard a packet where any of bits 1-5 are non-zero,
           unless that receiver implements RFC 1701. Bits 6-12 are reserved for
           future use. These bits MUST be sent as zero and MUST be ignored on
           receipt.

           RFC 2890: 2. Extensions to GRE Header
           Key present (bit 2)
           Sequence Number Present (bit 3)
        */
        if (IP_BIT_ISSET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_MUSTBE0))
            goto cleanup;

        /* RFC 2784: 2.3.1. Version Number (bits 13-15)
           The Version Number field MUST contain the value zero.
        */
        if (IP_BIT_ISSET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_VERSION))
            goto cleanup;

        /* RFC 2784: 2.5. Checksum (2 octets)
           The Checksum field contains the IP (one's complement) checksum sum of
           the all the 16 bit words in the GRE header and the payload packet.
           For purposes of computing the checksum, the value of the checksum
           field is zero. This field is present only if the Checksum Present bit
           is set to one.
        */
        if (IPNET_GRE_CHECKSUM_PRESENT(gre_hdr))
        {
            pkt->start += IPNET_GRE_OPT_CSUM_SIZE;

            /* IP checksum must be ok. */
            if (ipcom_in_checksum(&gre_hdr->flags_reserved0_ver, pkt->end - gre_hdr_start) != 0)
                goto cleanup;
        }

#ifdef IPNET_USE_RFC2890
        /* RFC 2890: 2.1. Key Field (4 octets)
           The Key field contains a four octet number which was inserted by the
           encapsulator. The actual method by which this Key is obtained is
           beyond the scope of the document. The Key field is intended to be
           used for identifying an individual traffic flow within a tunnel. For
           example, packets may need to be routed based on context information
           not present in the encapsulated data.  The Key field provides this
           context and defines a logical traffic flow between encapsulator and
           decapsulator.  Packets belonging to a traffic flow are encapsulated
           using the same Key value and the decapsulating tunnel endpoint
           identifies packets belonging to a traffic flow based on the Key Field
           value.
        */
        if (IPNET_GRE_KEY_PRESENT(gre_hdr))
        {
            Ip_u32 key;

            key = IP_GET_NTOHL(&pkt->data[pkt->start]);
            IPNET_GRE_PKT_SET_KEY(pkt, key);
            pkt->start += IPNET_GRE_OPT_KEY_SIZE;
        }

        /* RFC 2890: 2.2. Sequence Number (4 octets)
           The Sequence Number field is a four byte field and is inserted by the
           encapsulator when Sequence Number Present Bit is set. The Sequence
           Number MUST be used by the receiver to establish the order in which
           packets have been transmitted from the encapsulator to the receiver.
           The intended use of the Sequence Field is to provide unreliable but
           in-order delivery. If the Key present bit (bit 2) is set, the
           sequence number is specific to the traffic flow identified by the Key
           field. Note that packets without the sequence bit set can be
           interleaved with packets with the sequence bit set.
        */
        if (IPNET_GRE_SEQNUM_PRESENT(gre_hdr))
        {
            Ipnet_gre_t *gre = netif->ipcom.pdrv;
            Ip_u32       seqnum;

            seqnum = IP_GET_NTOHL(&pkt->data[pkt->start]);
            if (seqnum == gre->recv_seqnum)
                /* In order segment */
                ++gre->recv_seqnum;
            else if (IPCOM_IS_LT(seqnum, gre->recv_seqnum))
                /* Out of order */
                goto cleanup;
            else
            {
                Ip_u32 outoforder_timer;
                int max_perflow_buffer;

                max_perflow_buffer = ipcom_sysvar_get_as_int0("ipnet.gre.MAX_PERFLOW_BUFFER", 3);
                outoforder_timer = ipcom_sysvar_get_as_int0("ipnet.gre.OUTOFORDER_TIMER", 1000);

                if (max_perflow_buffer <= 0)
                    /* No buffering allowed */
                    goto cleanup;

                while (ipcom_pqueue_size(gre->reassembly_queue) >= max_perflow_buffer)
                {
                    ipnet_timeout_cancel(gre->reassembly_tmo);
                    /* Call the timeout handler to force the oldest packet(s)
                       to be inputted to the stack and the receive sequence
                       number to advanced */
                    ipnet_gre_seq_tmo(netif);
                }

                if (gre_hdr->protocol_type == ip_htons(0x0800))
                    IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_IPV4);
                else if (gre_hdr->protocol_type == ip_htons(0x86DD))
                    IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_IPV6);

                IPNET_PKT_SET_TIMEOUT_ABS(pkt, ipnet->msec_now + outoforder_timer);
                if (gre->reassembly_tmo == IP_NULL)
                    if (ipnet_timeout_schedule(outoforder_timer,
                                               (Ipnet_timeout_handler) ipnet_gre_seq_tmo,
                                               netif,
                                               &gre->reassembly_tmo) < 0)
                        goto cleanup;
                if (ipcom_pqueue_insert(gre->reassembly_queue, pkt) != IPCOM_SUCCESS)
                {
                    ipnet_timeout_cancel(gre->reassembly_tmo);
                    goto cleanup;
                }
                return 0;
            }
            pkt->start += IPNET_GRE_OPT_SEQNUM_SIZE;
        }
#endif /* IPNET_USE_RFC2890 */
    }

    /**/
    if (netif->ipcom.link_tap)
        /* start is PAYLOAD == the inner IP header; ipstart points to the PREVIOUS
         * IP header */
        netif->ipcom.link_tap(&netif->ipcom, pkt, IP_PACKET_HOST, gre_hdr->protocol_type, pkt->start, pkt->start);

#ifdef IPCOM_USE_INET
    /* IPv4 in GRE. */
    if (gre_hdr->protocol_type == ip_htons(0x0800))
        return ipnet_ip4_input(netif, pkt);
#endif

#ifdef IPCOM_USE_INET6
    /* IPv6 in GRE. */
    if (gre_hdr->protocol_type == ip_htons(0x86DD))
        return ipnet_ip6_input(netif, pkt);
#endif

    /* Unsupported Protocol Type, drop. */

 cleanup:
    ipcom_pkt_free(pkt);
    return -IP_ERRNO_EINVAL;
}
/*
 *===========================================================================
 *                    ipnet_pkt_check
 *===========================================================================
 * Description: Check that an active packet is not in free list or in inputq
 * Parameters:  pkt - The packet to check.
 * Returns:
 *
 */
IP_GLOBAL void
ipnet_pkt_check(Ipcom_pkt *pkt)
{
#ifndef IPNET_PKT_CHECK_DISABLED
    Ipcom_pkt            *tmp_pkt;
    int                   num;
    int                   key;
#ifdef IPNET_USE_PACKET_POOL
    Ipnet_pkt_pool_entry *ppe;
    Ipnet_pkt_pool_entry *prev_ppe;
    int                   i;
    Ip_bool               found;
#endif /* IPNET_USE_PACKET_POOL */

    ip_assert(pkt->id != IPCOM_PKT_ID_FREEQ);
    if (IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt) == IP_FALSE)
        ip_assert(pkt->id != IPCOM_PKT_ID_INQ);


#ifdef IPNET_USE_PACKET_POOL
    /*
     * VxWorks note - one shouldn't really call ip_assert() with the
     * packet pool lock still held, since in case of assertion failure,
     * ip_assert() will do things that shouldn't be done with a spinlock
     * held.
     */
    IPNET_DATA_LOCK(ipnet->pkt_pool_lock);

    /* Check that the packet is in the list of allocated packets */
    found = IP_FALSE;
    for (tmp_pkt = ipnet->allocated_pkt_list; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next_alloc)
    {
        if (tmp_pkt == pkt)
        {
            found = IP_TRUE;
            break;
        }
    }
    ip_assert(found);

    /* Check that pkt is not in the free list. */
    for (tmp_pkt = ipnet->pkt_hdr_list; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next)
    {
        ip_assert(tmp_pkt->id == IPCOM_PKT_ID_FREEQ);
        ip_assert(pkt != tmp_pkt);
    }

    /* Check that the pool is sane */
    for (i = 0; i < ipnet->pkt_pool_elem; i++)
    {
        num = 0;
        for (prev_ppe = IP_NULL, ppe = ipnet->pkt_pool[i].free_list;
                ppe != IP_NULL;
                prev_ppe = ppe, ppe = ppe->next)
        {
            num++;
            (void)prev_ppe;
        }
        ip_assert(ipnet->pkt_pool[i].total >= num);
    }

    IPNET_DATA_UNLOCK(ipnet->pkt_pool_lock);
#endif /* IPNET_USE_PACKET_POOL */

    /* Check that pkt is not in the inqueue as well. */
    IPNET_MIN_LOCK(ipnet->inq.lock, key);

    num = 0;
    for (tmp_pkt = ipnet->inq.head; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next)
    {
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK))
            /* This assert can fail for loopbacked packets under normal operation */
            ip_assert(tmp_pkt->id == IPCOM_PKT_ID_INQ);
        if (IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt) == IP_FALSE)
            ip_assert(pkt != tmp_pkt);
        num++;
    }
    ip_assert(ipnet->inq.count == num);

    IPNET_MIN_UNLOCK(ipnet->inq.lock, key);

    if (IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt) == IP_FALSE)
    {
        ip_assert(pkt->id != IPCOM_PKT_ID_OUTQ);
        ip_assert(pkt->id != IPCOM_PKT_ID_NETIF_OUTQ);
    }

#else /* IPNET_PKT_CHECK_DISABLED */
    (void) pkt;
#endif /* IPNET_PKT_CHECK_DISABLED */
}
Esempio n. 27
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);
}
Esempio n. 28
0
/*
 *===========================================================================
 *                      ipnet_if_mib_handler_ifXTable
 *===========================================================================
 * Description: MIB handler for variables in ifXTable
 * Parameters: See file 'ipsnmp.h'
 * Returns: IPSNMP_ERROR_XXX
 *
 */
IP_STATIC Ip_s32
ipnet_if_mib_handler_ifXTable(Ip_s32 cmd,
                              char *id,
                              Ipsnmp_varbind *vb,
                              Ip_s32 magic,
                              struct Ipsnmp_node_object *nodeobj)
{
    Ip_s32       lid, ret = -1;
    Ip_s32       ifLinkUpDownTrapEnable = 0;
    char        *iid;
    char        *buf = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID);
    char        *best = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID);
    Ipnet_netif *best_netif;

    if (buf == IP_NULL || best == IP_NULL)
    {
        ret = IPSNMP_ERROR_GENERROR;
        goto exit;
    }

    lid = ipsnmp_util_last_subid(nodeobj->id);
    ip_assert((lid >= 1 && lid <= 5) || (lid >= 14 && lid <= 19));
    best_netif = ipnet_if_mib_table_search_ifTable(id, buf, best, cmd, &ret);
    if (best_netif == IP_NULL)
        goto exit;

    if (cmd == IPSNMP_MIB_COMMAND_GET || cmd == IPSNMP_MIB_COMMAND_NEXT)
    {
        iid = ipsnmp_create_iid_direct(nodeobj->id, best);
        if (iid == IP_NULL)
        {
            ret = IPSNMP_ERROR_GENERROR;
            goto exit;
        }

        switch(lid)
        {
            case 1: /* ifName */
                ret = ipsnmp_util_put_octetstring(magic, iid, (Ip_u8 *)best_netif->ipcom.name, ipcom_strlen(best_netif->ipcom.name));
                break;
            case 2: /* ifInMulticastPkts */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInMulticastPkts);
                break;
            case 3: /* ifInBroadcastPkts */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInBroadcastPkts);
                break;
            case 4: /* ifOutMulticastPkts */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutMulticastPkts);
                break;
            case 5: /* ifOutBroadcastPkts */
                ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutBroadcastPkts);
                break;
            case 14: /* ifLinkUpDownTrapEnable */
                if (best_netif->ipcom.mib2.ifLinkUpDownTrapEnable == 0)
                    best_netif->ipcom.mib2.ifLinkUpDownTrapEnable = 1;
                ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.mib2.ifLinkUpDownTrapEnable);
                break;
            case 15: /* ifHighSpeed */
                if (best_netif->ipcom.type == IP_IFT_PPP)
                    ret = ipsnmp_util_put_gauge32(magic, iid, 0);
                else
                    ret = ipsnmp_util_put_gauge32(magic, iid, 100);
                break;
            case 16: /* ifPromiscuousMode */
                if (IP_BIT_ISSET(best_netif->ipcom.flags, IP_IFF_PROMISC))
                    ret = ipsnmp_util_put_integer(magic, iid, 1);
                else
                    ret = ipsnmp_util_put_integer(magic, iid, 2);
                break;
            case 17: /* ifConnectorPresent */
                ret = ipsnmp_util_put_integer(magic, iid, 2);
                break;
            case 18: /* ifAlias */
                ret = ipsnmp_util_put_octetstring(magic, iid, IP_NULL, 0);
                break;
            case 19: /* ifCounterDiscontinuityTime */
                ret = ipsnmp_util_put_timeticks(magic, iid, 0);
                break;
            default:
                IP_PANIC();
                ret = IPSNMP_ERROR_GENERROR;
                break;
        }

        ipcom_free(iid);
    }

    if (cmd == IPSNMP_MIB_COMMAND_TEST || cmd == IPSNMP_MIB_COMMAND_SET)
    {
        switch(lid)
        {
            case 14: /* ifLinkUpDownTrapEnable */
                ret = ipsnmp_util_get_integer(vb, &ifLinkUpDownTrapEnable);
                if (ret == IPSNMP_ERROR_NOERROR)
                {
                    if (ifLinkUpDownTrapEnable != 1 && ifLinkUpDownTrapEnable != 2)
                    {
                        ret = IPSNMP_ERROR_WRONGVALUE;
                    }
                }

                if (ret == IPSNMP_ERROR_NOERROR && cmd == IPSNMP_MIB_COMMAND_SET)
                {
                    best_netif->ipcom.mib2.ifLinkUpDownTrapEnable = ifLinkUpDownTrapEnable;
                }
                break;
            case 16: /* ifPromiscuousMode */
            case 18: /* ifAlias */
                ret = IPSNMP_ERROR_NOSUCHNAME;
                break;
            default:
                IP_PANIC();
                ret = IPSNMP_ERROR_GENERROR;
                break;
        }
    }

exit:
    if (buf != IP_NULL)
        ipcom_free(buf);
    if (best != IP_NULL)
        ipcom_free(best);
    return ret;
}
Esempio n. 29
0
/*
 *===========================================================================
 *                    ipcom_cmd_ipd
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 */
IP_PUBLIC int
ipcom_cmd_ipd(int argc, char **argv)
{
    Ipcom_getopt   opt;
    int            i, c, msgtype;
    Ip_err         err = IPCOM_SUCCESS;
#if IPCOM_VR_MAX > 1
    int            vr = ipcom_proc_vr_get();
    int            vr_new = vr;
#endif

    if (argc < 2)
    {
usage:
        ipcom_fprintf(ip_stderr,
                      "Interpeak daemon (IPD) command, version 1.2"IP_LF
                      "usage:  "IP_LF
                      "   ipd [-V <vr>] list"IP_LF
                      "   ipd [-V <vr>] start <service>"IP_LF
                      "   ipd [-V <vr>] kill <service>"IP_LF
                      "   ipd [-V <vr>] reconfigure <service>"IP_LF
                      "   ipd [-V <vr>] <#> <service>"IP_LF
                      IP_LF);
        return 0;
    }

    ipcom_getopt_clear_r(&opt);
    while ((c = ipcom_getopt_r(argc, argv, "V:", &opt)) != -1)
    {
        switch(c)
        {
        case 'V':
#if IPCOM_VR_MAX > 1
            vr_new = ipcom_atoi(opt.optarg);
#endif
            break;
        default:
            ipcom_printf("ipd: unknown option %c"IP_LF, (char)c);
            return -1;
        }
    }

    if (opt.optind >= argc)
    {
        ipcom_printf("ipd: missing <command> argument"IP_LF);
        goto usage;
    }


    if(ipcom_strcmp(argv[opt.optind], "list") == 0)
    {
#if IPCOM_VR_MAX > 1
        if (vr != vr_new)
            ipcom_proc_vr_set(vr_new);
#endif
        ipcom_printf("Services:"IP_LF);
        for (i = 0; ipcom_ipd_products[i].name != IP_NULL; i++)
        {
            if ((argc - (opt.optind + 1)) > 0)
            {
                int p;
                for (p = opt.optind + 1; p < argc; p++)
                {
                    if (ipcom_strcasecmp(ipcom_ipd_products[i].name, argv[p]) == 0)
                        goto print_service;
                }
                continue;
            }

print_service:
            if (IP_BIT_ISSET(ipcom_ipd_products[i].flags, IPCOM_IPD_FLAG_IPD_START))
            {
#ifdef IP_PORT_OSE5
                if (ipcom_ipd_products[i].start == IP_NULL
                    && ipcom_ipd_isinstalled_ose5(ipcom_ipd_products[i].name) != IPCOM_SUCCESS)
                    continue;
#endif
                err = ipcom_ipd_send(ipcom_ipd_products[i].name, IPCOM_IPD_MSGTYPE_PING);
                ipcom_printf("%-20s %-s"IP_LF,
                             ipcom_ipd_products[i].name,
                             err == IPCOM_SUCCESS ? "started" : "killed");
            }
            else if (ipcom_ipd_products[i].start)
                ipcom_printf("%-20s %-s"IP_LF,
                             ipcom_ipd_products[i].name, "started");

        }
        ipcom_printf(IP_LF);
#if IPCOM_VR_MAX > 1
        if (vr != vr_new)
            ipcom_proc_vr_set(vr);
#endif
        return 0;
    }

    if ((argc - opt.optind) < 2)
    {
        ipcom_printf("ipd: missing <service> argument"IP_LF);
        return -1;
    }

    for (i = 0; ipcom_cmd_ipd_messages[i].name; i++)
        if (ipcom_strcmp(argv[opt.optind], ipcom_cmd_ipd_messages[i].name) == 0)
        {
            msgtype = ipcom_cmd_ipd_messages[i].msgtype;
            goto sendmsg;
        }

    if (*argv[opt.optind] == '-' && ipcom_isdigit(argv[opt.optind][1]))
    {
        /* "UNIX" signal support (using negative numbers) */
        msgtype = -ipcom_atoi(argv[opt.optind] + 1);
        goto sendmsg;
    }

    if (ipcom_isdigit(argv[opt.optind][0]))
    {
        /* positive numbers */
        msgtype = ipcom_atoi(argv[1]);
        goto sendmsg;
    }

    /* unknown command. */
    ipcom_printf ("ipd: unknown command '%s'"IP_LF, argv[opt.optind]);
    return -1;

    /* send msg */
 sendmsg:
#if IPCOM_VR_MAX > 1
    if (vr != vr_new)
        ipcom_proc_vr_set(vr_new);
#endif


    if ((argc - opt.optind) < 3)
        err = ipcom_ipd_send(argv[opt.optind+1], msgtype);
    else
    {
        Ipcom_ipd_msg   *msg;
        int             sz  = ipcom_strlen(argv[opt.optind + 2]) + 1;

        msg = ipcom_calloc(1, sz + sizeof(*msg));
        if (msg != IP_NULL)
        {
            msg->msgtype = msgtype;
            ipcom_memcpy(msg + 1, argv[opt.optind + 2], sz);
            err = ipcom_ipd_sendmsg(argv[opt.optind+1], msg, sz + sizeof(*msg));
            ipcom_free(msg);
        }
    }

    if(err == IPCOM_SUCCESS)
        ipcom_printf("ipd: %s %s ok"IP_LF, argv[opt.optind], argv[opt.optind+1]);
    else
        ipcom_printf("ipd: %s %s failed: %s"IP_LF, argv[opt.optind], argv[opt.optind+1], ipcom_err_string(err));

#if IPCOM_VR_MAX > 1
    if (vr != vr_new)
        ipcom_proc_vr_set(vr);
#endif
    return 0;
}
/*
 *===========================================================================
 *                    ipnet_rtnetlink_neigh_newneigh_family
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_GLOBAL int
ipnet_rtnetlink_neigh_newneigh_family(Ipnet_netlink_mem_t  *mem,
                                      struct Ip_nlmsghdr   *nlmsg,
                                      struct Ip_rtattr     **rta,
                                      int                  family)
{
    Ipnet_netif                  *netif;
    Ipnet_route_entry            *rt;
    int                          nd_state;
    int                          ret = -IP_ERRNO_EAFNOSUPPORT;
    Ip_u16                       vr;
    Ip_u32                       table = IPCOM_ROUTE_TABLE_DEFAULT;
    struct Ip_sockaddr_dl        dl;
    struct Ip_ndmsg              *ndm = IP_NLMSG_DATA(nlmsg);
    void                         *link_addr = IP_NULL;
    Ipnet_rtnetlink_key_t        ukey;

     /* Destination address required */
    if (rta[IP_NDA_DST-1] == IP_NULL)
        return -IP_ERRNO_EINVAL;

#ifdef IPNET_USE_ROUTE_TABLE_NAMES
    if (rta[IP_NDA_TABLE_NAME -1])
    {
        /* Extract router and table from name */
        if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_NDA_TABLE_NAME - 1]),
                                               &vr,
                                               &table) < 0)
            return -IP_ERRNO_ESRCH;
    }
    else
#endif /* IPNET_USE_ROUTE_TABLE_NAMES */
    {
        if (mem->vr == IPCOM_VR_ANY)
            return -IP_ERRNO_EINVAL;

        vr = ipnet_rtnetlink_vr(rta[IP_NDA_VR - 1], mem->vr);

        if (rta[IP_NDA_TABLE - 1])
            table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_NDA_TABLE - 1]));
    }

    netif = ipnet_if_indextonetif(vr, ndm->ndm_ifindex);

    if (netif && (netif->vr_index != vr))
         return -IP_ERRNO_EINVAL;

    if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, IP_NULL, -1, rta[IP_NDA_DST-1])) < 0)
        return ret;

    if (rta[IP_NDA_LLADDR-1])
        /* Neighbors link layer address */
        link_addr = IP_RTA_DATA(rta[IP_NDA_LLADDR-1]);
    else if (IP_BIT_ISSET(ndm->ndm_flags, IP_NTF_PROXY))
    {
        /* Proxy ARP entry. Use Link layer address of local netif */
        if (netif == IP_NULL)
            return -IP_ERRNO_EINVAL;

        link_addr = netif->ipcom.link_addr;
    }

    /* Check if neighbor route exists */
    ret = ipnet_route_lookup(family,
                             vr,
                             table,
                             IPNET_RTL_FLAG_LINK_LOCAL | IPNET_RTL_FLAG_DONTCLONE,
                             &ukey,
                             netif ? netif->ipcom.ifindex : 0,
                             netif ? netif->ipcom.ifindex : 0,
                             &rt);

    if ((ret == IPNET_ROUTE_PERFECT_MATCH)
        && (rt->netif == netif)
        && IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_HOST)
        && IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_LLINFO))
    {
        if (rt->data == IP_NULL)
            return -IP_ERRNO_EINVAL;

        /* Get the neighbour state */
        nd_state = *(Ipnet_nd_state_t *)rt->data;

        if (((ndm->ndm_state == IP_NUD_INCOMPLETE)
             && (nd_state != IPNET_ND_UNINITIALIZED)
             && (nd_state != IPNET_ND_INCOMPLETE))
            || ((ndm->ndm_state == IP_NUD_DELAY)
                && (nd_state != IPNET_ND_STALE)))
        {
            return -IP_ERRNO_EINVAL;
        }
    }
    else
    {
        struct Ipnet_rt_metrics      metrics;
        struct Ipnet_route_add_param param;

        /* Create new neighbor entry */
        if (ndm->ndm_state == IP_NUD_DELAY)
            ndm->ndm_state = IP_NUD_INCOMPLETE;

        ipcom_memset(&param, 0, sizeof(struct Ipnet_route_add_param));
        ipcom_memset(&dl, 0, sizeof(struct Ip_sockaddr_dl));

        param.domain     = family;
        param.vr         = vr;
        param.table      = table;
        param.key        = &ukey;
        param.netif      = netif;
        param.flags      = IPNET_RTF_UP | IPNET_RTF_HOST | IPNET_RTF_LLINFO | IPNET_RTF_DONE;
        param.gateway    = (struct Ip_sockaddr*) &dl;

        if (ndm->ndm_state != IP_NUD_PERMANENT)
        {
            ipcom_memset(&metrics, 0, sizeof(metrics));
            /* The correct timeout will be set when the ND state is set,
               but must be != infinite for now */
            metrics.rmx_expire = 1;
            param.metrics = &metrics;
        }

        IPCOM_SA_LEN_SET(&dl, sizeof(struct Ip_sockaddr_dl));
        dl.sdl_family    = IP_AF_LINK;
        dl.sdl_index     = (Ip_u16)(netif ? netif->ipcom.ifindex : 0);
        dl.sdl_alen      = 6;
        dl.sdl_type      = IP_IFT_ETHER;

        if (link_addr)
            ipcom_memcpy(&dl.sdl_data[0], link_addr,dl.sdl_alen);

        if (netif)
            IPNET_IF_LOCK(netif);

        /* Add new neighbor */
        ret = ipnet_route_add(&param);

        if (netif)
            IPNET_IF_UNLOCK(netif);

        if (ret < 0)
            return ret;

        /* Get the new neighbor route entry */
        ret = ipnet_route_lookup(family,
                                 vr,
                                 table,
                                 IPNET_RTL_FLAG_LINK_LOCAL | IPNET_RTL_FLAG_DONTCLONE,
                                 &ukey,
                                 netif ? netif->ipcom.ifindex : 0,
                                 netif ? netif->ipcom.ifindex : 0,
                                 &rt);
        if (ret < 0)
            return ret;
    }

#ifdef IPNET_COMPENSATE_UNRELIABLE_NETLINK
    /* Set neighbor acknowledge bit */
    IP_BIT_SET(rt->hdr.flags, IPNET_RTF_X_NEIGH_ACK);
#endif

    if (IP_BIT_ISSET(ndm->ndm_flags,IP_NTF_PROXY))
        /* Proxy ARP entry */
        IP_BIT_SET(rt->hdr.flags, IPNET_RTF_PROTO2);

    if (IP_BIT_ISSET(ndm->ndm_state, IP_NUD_PERMANENT))
        ipnet_route_set_lifetime(rt, IPCOM_ADDR_INFINITE);

    nd_state = ipnet_rtnetlink_neigh_nud2nc(ndm->ndm_state);

#ifdef IPCOM_USE_INET
    if (family == IP_AF_INET)
        ret = ipnet_rtnetlink_ip4_neigh_setup(&ukey, ndm, rt, nd_state, link_addr, rta);
    else
#endif
#ifdef IPCOM_USE_INET6
    if (family == IP_AF_INET6)
        ret = ipnet_rtnetlink_ip6_neigh_setup(&ukey, ndm, rt, nd_state, link_addr, rta);
    else
#endif
        return -IP_ERRNO_EAFNOSUPPORT;

    return ret;
}