/* *=========================================================================== * ipnet_sysctl_route_add_addr *=========================================================================== * Description: Adds an address in route table format. * Parameters: buf - the buffer to where the address should be written. * domain - the domain this address is part of. * rt_addr - a address or mask from the route table. * Returns: The address to where the next data should be written in * the buffer. * */ IP_STATIC void * ipnet_sysctl_route_add_addr(void *buf, int domain, void *rt_addr) { union Ip_sockaddr_union *addr; addr = (union Ip_sockaddr_union *) buf; #ifdef IPCOM_USE_INET if (domain == IP_AF_INET) { struct Ipnet_ipv4_key *key = (struct Ipnet_ipv4_key *) rt_addr; ipcom_memset(addr, 0, sizeof(struct Ip_sockaddr_in)); addr->sin.sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(&addr->sin, sizeof(struct Ip_sockaddr_in)); ipcom_memcpy(&addr->sin.sin_addr, &key->addr, sizeof(addr->sin.sin_addr)); } #endif /* IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if (domain == IP_AF_INET6) { struct Ipnet_ipv6_key *key = (struct Ipnet_ipv6_key *) rt_addr; ipcom_memset(addr, 0, sizeof(struct Ip_sockaddr_in6)); addr->sin6.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&addr->sin6, sizeof(struct Ip_sockaddr_in6)); ipcom_memcpy(&addr->sin6.sin6_scope_id, &key->scope_id, sizeof(addr->sin6.sin6_scope_id)); ipcom_memcpy(&addr->sin6.sin6_addr, &key->addr, sizeof(addr->sin6.sin6_addr)); } #endif /* IPCOM_USE_INET6 */ return (Ip_u8 *) buf + IPCOM_SA_LEN_GET(&addr->sa); }
IP_STATIC void * ipnet_sysctl_if_add_ip4_addr(void *buf, Ip_u32 addr_n) { struct Ip_sockaddr_in *in = (struct Ip_sockaddr_in *) buf; ipcom_memset(in, 0, sizeof(struct Ip_sockaddr_in)); in->sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(in, sizeof(struct Ip_sockaddr_in)); ipcom_memcpy(&in->sin_addr, &addr_n, sizeof(in->sin_addr)); return in + 1; }
/* *=========================================================================== * ipnet_sysctl_if_add_ip6_addr *=========================================================================== * Description: Adds a IPv6 socket address to the buffer. * Parameters: buf - the buffer where the socket address should be written. * addr - the address in network byte order. * is_scoped - IP_TRUE if the address or mask is scoped. * scope_id - The scope_id to use if the mask/address is scoped. * Returns: Pointer to where next address should be written. * */ IP_STATIC void * ipnet_sysctl_if_add_ip6_addr(void *buf, IP_CONST struct Ip_in6_addr *addr, Ip_bool is_scoped, Ip_u32 scope_id) { struct Ip_sockaddr_in6 *in6 = (struct Ip_sockaddr_in6 *) buf; ipcom_memset(in6, 0, sizeof(struct Ip_sockaddr_in6)); in6->sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(in6, sizeof(struct Ip_sockaddr_in6)); in6->sin6_scope_id = (is_scoped ? scope_id : 0); IPNET_IP6_SET_ADDR(&in6->sin6_addr, addr); return in6 + 1; }
/* *=========================================================================== * ipnet_loopback_ioctl *=========================================================================== * Description: IO control. Accept join/leave from multicast groups. * Parameters: netif - The network interface on which to perform the operation. * command - The command to perform. * data - Data associated with the command. * Returns: 0 = success, 0< = error code. * */ IP_STATIC int ipnet_loopback_ioctl(Ipnet_netif *netif, Ip_u32 command, void *data) { struct Ip_ifreq *ifreq = data; int ret = 0; switch (command) { case IP_SIOCXOPEN: #ifdef IP_PORT_LKM /* Call linux loopback device */ ipnet_if_drv_ioctl(netif, IP_SIOCXOPEN, IP_NULL); #endif /* IP_PORT_LKM */ ipnet_kioevent(netif, IP_EIOXRUNNING, IP_NULL, IP_FLAG_FC_STACKCONTEXT); ipnet_kioevent(netif, IP_EIOXUP, IP_NULL, IP_FLAG_FC_STACKCONTEXT); break; case IP_SIOCXCLOSE: #ifdef IP_PORT_LKM /* Call linux loopback device */ ipnet_if_drv_ioctl(netif, IP_SIOCXCLOSE, IP_NULL); #endif /* IP_PORT_LKM */ ipnet_kioevent(netif, IP_EIOXDOWN, IP_NULL, IP_FLAG_FC_STACKCONTEXT); ipnet_kioevent(netif, IP_EIOXSTOP, IP_NULL, IP_FLAG_FC_STACKCONTEXT); break; case IP_SIOCGIFHWADDR: /* Switch to our if type */ ifreq->ip_ifr_addr.sa_family = netif->ipcom.type; /* Return */ break; case IP_SIOCGIFLLADDR: ifreq->ip_ifr_addr.sa_family = IP_AF_LINK; IPCOM_SA_LEN_SET(&ifreq->ip_ifr_addr, 0); break; case IP_SIOCIFDESTROY: if (ipcom_strcmp(netif->ipcom.name, IPNET_IF_LOOPBACK_NAME) == 0) ret = -IP_ERRNO_EPERM; else { ret = ipcom_if_detach(&netif->ipcom); if (ret >= 0) ret = ipcom_if_free(&netif->ipcom); } break; #ifdef IPCOM_USE_INET case IP_SIOCXADDMULTI_IN: case IP_SIOCXDELMULTI_IN: #endif #ifdef IPCOM_USE_INET6 case IP_SIOCXADDMULTI_IN6: case IP_SIOCXDELMULTI_IN6: #endif break; default: return -IP_ERRNO_EINVAL; } 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; }
/* *=========================================================================== * ipcom_cmd_ttcp *=========================================================================== */ int ipcom_cmd_ttcp(int argc, char **argv) { /* Uninitialized variables. */ union Ip_sockaddr_union addrme; char *host = IP_NULL; /* ptr to name of host */ int c; Ip_u32 msec0, msec1, msecd, bpermsec, kbpersec; Ip_fd sockfd = -1; char *buf; /* ptr to dynamic buffer */ char *orgbuf = 0; /* the buffer to free. */ struct Ipcom_cmd_ttcp_data context; /* misc initialized variables. */ #ifdef IPCOM_USE_TCP union Ip_sockaddr_union frominet; Ip_socklen_t fromlen; int one = 1; /* for 4.3 BSD style setsockopt() */ Ip_fd oldfd; /* fd of network socket */ #endif Ip_u32 nbytes = 0; /* bytes on net */ int trans = 1; /* 0=receive, !0=transmit mode. Default transmit! */ /* Configuration variables. */ #if defined(IP_SO_X_VR) int vr = 0; #endif int buflen = 8 * 1024; /* length of buffer */ int nbuf = 2 * 1024; /* number of buffers to send in sinkmode */ int bufoffset = 0; /* align buffer to this */ int bufalign = 16; /* modulo this */ int options = 0; /* socket options */ unsigned short port = DEFAULT_PORT; /* TCP port number */ unsigned short meport = 0; /* local port, default 0. */ int sinkmode = 1; /* 0=normal I/O, !0=sink/source mode */ int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc resource usage. */ int sockbufsize = -1; /* Default socket buffer size to use. */ #ifdef IP_TCP_NODELAY int nodelay = 0; /* set TCP_NODELAY socket option. */ #endif int enable = 1; #ifdef TCP_OSERFC2385 char *md5opt = IP_NULL; #endif #ifdef IP_SO_REUSEPORT int reuse_port = 0; #endif #ifdef IPCOM_TTCP_REENTRANT union Ip_sockaddr_union addrhim; #endif int sock_error; int mev = 0; /* Use event logging */ int nend = 5; /* Number of UDP end packets */ #ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API int zerocopy = 0; #endif int cpu = -1; #ifdef IPSCTP Ip_bool sctp_type_conflict = IP_FALSE; #endif /* Initialize some static data, default configuration. */ #ifdef IPCOM_USE_TCP int proto = IP_IPPROTO_TCP; int sock_type = IP_SOCK_STREAM; const char *proto_as_str = "TCP"; context.udp = 0; /* Default is TCP. */ #else int proto = IP_IPPROTO_UDP; int sock_type = IP_SOCK_DGRAM; const char *proto_as_str = "UDP"; context.udp = 1; /* Only UDP. */ #endif context.b_flag = 0; context.touchdata = 0; context.numCalls = 0; context.err_no = 0; #ifdef IPCOM_USE_INET context.family = IP_AF_INET; /* default IPv4 */ #else context.family = IP_AF_INET6; /* default IPv6 */ #endif context.addrsize = sizeof(struct Ip_sockaddr_in); (void)ipcom_proc_self(); /* when called from vxworks shell, this prevents a crash */ (void)options; /* Init some more. */ ipcom_memset(&addrhim, 0, sizeof (addrhim)); IPCOM_SA_LEN_SET(&addrhim.sin, sizeof(struct Ip_sockaddr_in)); addrhim.sin.sin_family = IP_AF_INET; ipcom_memset(&addrme, 0, sizeof(addrme)); IPCOM_SA_LEN_SET(&addrme.sin, sizeof(struct Ip_sockaddr_in)); addrme.sin.sin_family = IP_AF_INET; #ifdef IP_PORT_INTEGRITY ipcom_init_libsocket(); #endif if (argc < 2) goto usage; ipcom_getopt_clear(); while ((c = ipcom_getopt(argc, argv, "M:xdrstUuvBDTb:f:l:n:p:A:O:V:RP:me:a:cS")) != -1) { switch (c) { #ifdef TCP_OSERFC2385 case 'M': /* MD5 signature option */ md5opt = ip_optarg; break; #endif #ifdef IPCOM_USE_INET6 case 'x': context.family = IP_AF_INET6; break; #endif case 'm': mev = 1; break; case 'e': nend = ipcom_atoi(ip_optarg); break; case 'B': context.b_flag = 1; break; case 't': trans = 1; break; case 'r': trans = 0; break; #ifdef IP_SO_DEBUG case 'd': options |= IP_SO_DEBUG; break; #endif case 'D': #ifdef IP_TCP_NODELAY nodelay = 1; #else ipcom_fprintf(ip_stderr, "ttcp: -D option ignored: IP_TCP_NODELAY socket option not supported"IP_LF); #endif break; case 'n': nbuf = ipcom_atoi(ip_optarg); break; case 'l': buflen = ipcom_atoi(ip_optarg); break; case 's': #ifdef IPCOM_TTCP_USE_STDIOMODE sinkmode = !sinkmode; #endif break; case 'p': port = (unsigned short)ipcom_atoi(ip_optarg); break; case 'P': meport = (unsigned short)ipcom_atoi(ip_optarg); break; #ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API case 'U': zerocopy = 1; /* fall through */ #endif case 'u': proto = IP_IPPROTO_UDP; sock_type = IP_SOCK_DGRAM; proto_as_str = "UDP"; context.udp = 1; break; case 'v': verbose = 1; break; case 'A': bufalign = ipcom_atoi(ip_optarg); break; case 'O': bufoffset = ipcom_atoi(ip_optarg); break; case 'b': #if defined(IP_SO_SNDBUF) || defined(IP_SO_RCVBUF) sockbufsize = ipcom_atoi(ip_optarg); #else ipcom_fprintf(ip_stderr, "ttcp: -b option ignored: IP_SO_SNDBUF/IP_SO_RCVBUF socket options not supported"IP_LF); #endif break; #ifdef IP_SO_REUSEPORT case 'R': reuse_port = 1; break; #endif case 'T': context.touchdata = 1; break; #if defined(IP_SO_X_VR) case 'V': vr = ipcom_atoi(ip_optarg); break; #endif case 'a': cpu = ipcom_atoi(ip_optarg); break; #ifdef IPSCTP case 'c': proto = IP_IPPROTO_SCTP; sock_type = IP_SOCK_STREAM; proto_as_str = "SCTP"; if (IP_TRUE == sctp_type_conflict) { ipcom_fprintf(ip_stderr, "ttcp: c/S conflict in command."IP_LF); goto errorout; } sctp_type_conflict = IP_TRUE; break; case 'S': proto = IP_IPPROTO_SCTP; sock_type = IP_SOCK_SEQPACKET; proto_as_str = "SCTP"; if (IP_TRUE == sctp_type_conflict) { ipcom_fprintf(ip_stderr, "ttcp: c/S conflict in command."IP_LF); goto errorout; } sctp_type_conflict = IP_TRUE; break; #endif default: goto usage; } } #ifndef IP_PORT_LAS if (cpu >= 0) { Ip_cpu_set_t cpuset; if (cpu < 0 || cpu >= IP_CPU_SETSIZE) { ipcom_fprintf(ip_stderr, "ttcp: CPU must be between #0 and #%d"IP_LF, IP_CPU_SETSIZE-1); return -1; } IP_CPU_ZERO(&cpuset); IP_CPU_SET(cpu, &cpuset); if (ipcom_proc_cpu_affinity_set(0, &cpuset) != IPCOM_SUCCESS) { ipcom_fprintf(ip_stderr, "ttcp: Failed to set affinity to CPU #%d"IP_LF, cpu); return -1; } } #endif /* IP_PORT_LAS */ if(trans) { host = argv[ip_optind]; if (host == 0) goto usage; sock_error = ipcom_getsockaddrbyaddrname(context.family, IP_FALSE, host, (struct Ip_sockaddr *)&addrhim); if(sock_error != 0) { ipcom_fprintf(ip_stderr, "ttcp error: ipcom_getsockaddrbyaddrname failed, errno = %d."IP_LF, sock_error); ttcperror(&context, "unknown host"); } addrme.sin.sin_port = ip_htons(meport); addrhim.sin.sin_port = ip_htons(port); /* same port offset for IPv4 and IPv6 */ } else { /* rcvr */ addrme.sin.sin_port = ip_htons(port); } #ifdef IPCOM_USE_INET6 if(context.family == IP_AF_INET6) { context.addrsize = sizeof(struct Ip_sockaddr_in6); IPCOM_SA_LEN_SET(&addrme.sin6, sizeof(struct Ip_sockaddr_in6)); addrme.sin6.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&addrhim.sin6, sizeof(struct Ip_sockaddr_in6)); addrhim.sin6.sin6_family = IP_AF_INET6; } #endif /* Send more than the sentinel size - UDPMINLEN. */ if(context.udp && buflen <= UDPMINLEN) buflen = UDPMINLEN + 1; /* Align buffer. */ if ((buf = (char *) ipcom_malloc(buflen + bufalign)) == (char *) IP_NULL) ttcperror(&context, "malloc"); else orgbuf = buf; if (bufalign != 0) buf += (bufalign - ((Ip_ptrdiff_t) buf % bufalign) + bufoffset) % bufalign; /* Get a socket. */ if ((sockfd = ipcom_socket(context.family, sock_type, proto)) == ERR) ttcperror(&context,"socket"); if (trans) { if(sockbufsize < 0) { if(context.udp) sockbufsize = DEFAULT_UDP_SNDBUF; else sockbufsize = DEFAULT_TCP_SNDBUF; } ipcom_fprintf(ip_stdout, "ttcp-t: fd=%d, buflen=%d, nbuf=%d, align=%d/%d, port=%d", sockfd, buflen, nbuf, bufalign, bufoffset, (int)port); if (sockbufsize) ipcom_fprintf(ip_stdout, ", sockbufsize=%d", sockbufsize); ipcom_fprintf(ip_stdout, " %s -> %s"IP_LF, proto_as_str, host); } else { if(sockbufsize < 0) { if(context.udp) sockbufsize = DEFAULT_UDP_RCVBUF; else sockbufsize = DEFAULT_TCP_RCVBUF; } ipcom_fprintf(ip_stdout, "ttcp-r: fd=%d, buflen=%d, nbuf=%d, align=%d/%d, port=%d", sockfd, buflen, nbuf, bufalign, bufoffset, (int)port); if (sockbufsize) ipcom_fprintf(ip_stdout, ", sockbufsize=%d", sockbufsize); ipcom_fprintf(ip_stdout, " %s"IP_LF, proto_as_str); } /* Code to open socket is moved to before the printf to get 'sockfd' right. */ mes(trans, "socket"); /* Set REUSE addr */ if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_REUSEADDR, (char *)&enable, sizeof (int)) == ERR) ttcperror(&context, "setsockopt(IP_SO_REUSEADDR)"); else mes(trans, "setsockopt(IP_SO_REUSEADDR)"); #ifdef IP_SO_REUSEPORT /* Set REUSE port */ if(reuse_port) { if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&reuse_port, sizeof (int)) == ERR) ttcperror(&context, "setsockopt(IP_SO_REUSEPORT)"); else mes(trans, "setsockopt(IP_SO_REUSEPORT)"); } #endif #ifdef IPCOM_USE_TCP #ifdef TCP_OSERFC2385 if (!udp && md5opt) { if (ipcom_setsockopt(sockfd, IPPROTO_TCP, TCP_OSERFC2385, md5opt, strlen(md5opt)) == ERR) { ttcperror(&context, "setsockopt(IP_SO_REUSEADDR)"); } else { mes(trans, "setsockopt(IP_SO_REUSEADDR)"); } } #endif #endif /* Set routing table index in socket. */ #if defined(IP_SO_X_VR) if(vr != 0) { if (ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_X_VR, (char *)&vr, 4) == ERR) ttcperror(&context, "setsockopt: vr"); else mes(trans, "setsockopt(vr)"); } #endif /* Bind the socket. */ if(ipcom_bind(sockfd, (struct Ip_sockaddr *)&addrme, context.addrsize) == ERR) ttcperror(&context, "bind"); else #ifdef IPCOM_USE_INET6 ipcom_fprintf(ip_stderr, "ttcp%s: bind %s %d"IP_LF, trans ? "-t" : "-r", context.family == IP_AF_INET ? "IPv4" : "IPv6", (int)ip_ntohs(addrme.sin.sin_port)); #else { char tmpbuf[32]; ipcom_sprintf(tmpbuf, "bind %d", ip_ntohs(addrme.sin.sin_port)); mes(trans, tmpbuf); } #endif /* Adjust socker buffer size. */ #if defined(IP_SO_SNDBUF) || defined(IP_SO_RCVBUF) if(sockbufsize) { if (trans) { if (ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_SNDBUF, (char *)&sockbufsize, sizeof sockbufsize) == ERR) ttcperror(&context,"setsockopt: sndbuf"); else mes(trans, "setsockopt(sndbuf)"); } else { if (ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_RCVBUF, (char *)&sockbufsize, sizeof sockbufsize) == ERR) ttcperror(&context,"setsockopt: rcvbuf"); else mes(trans, "setsockopt(rcvbuf)"); } } #endif /* If TCP we need to connect else accept to remote side. */ #ifdef IPCOM_USE_TCP if (context.udp) { mes(trans, "opened"); } else { /* We are the client if transmitting */ if(trans) { if(options) { if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, options, (char *)&one, sizeof (one)) == ERR) ttcperror(&context,"setsockopt"); } #ifdef IP_TCP_NODELAY if(nodelay) { if(ipcom_setsockopt(sockfd, IP_IPPROTO_TCP, IP_TCP_NODELAY, (char *)&one, sizeof (one)) == ERR) ttcperror(&context,"setsockopt: nodelay"); mes(trans, "nodelay"); } #endif if(ipcom_connect(sockfd, (struct Ip_sockaddr *)&addrhim, context.addrsize) == ERR) ttcperror(&context,"connect"); else mes(trans, "connect"); } /* Otherwise, we are the TCP server and should listen for the connections. */ else { if(ipcom_listen(sockfd, 0) == ERR) ttcperror(&context,"listen"); else mes(trans, "listen"); if(options) { if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, options, (char *)&one, sizeof (one)) == ERR) ttcperror(&context,"setsockopt"); } fromlen = context.addrsize; oldfd = sockfd; #ifdef IPSCTP if ((IP_SOCK_SEQPACKET == sock_type) && (IP_IPPROTO_SCTP == proto)) { #define TTCP_SCTP_RCV_BUF_LEN 128 struct Ipsctp_event_subscribe events; union Ip_sockaddr_union local_addr; struct Ipsctp_sndrcvinfo sinfo; Ip_u32 len = 0; char pbuf[TTCP_SCTP_RCV_BUF_LEN]; int flags = 0; int ret = 0; /* set data I/O event flag */ ipcom_memset(&events, 0, sizeof(events)); events.Ipsctp_data_io_event = 1; ret = ipcom_setsockopt(sockfd, IP_IPPROTO_SCTP, IPSCTP_EVENTS, (void *)&events, sizeof(events)); if (ERR == ret) ttcperror(&context, "setsockopt events"); /* get the association identifier */ ipcom_memset(pbuf, 0, TTCP_SCTP_RCV_BUF_LEN); len = sizeof(local_addr); /* Wait for connections */ ret = ipsctp_recvmsg(sockfd, pbuf, TTCP_SCTP_RCV_BUF_LEN, &local_addr.sa, &len, &sinfo, &flags); sockfd = ipsctp_peeloff(sockfd, sinfo.sinfo_assoc_id); if (IP_SOCKERR == sockfd) ttcperror(&context,"peeloff"); } else #endif { if((sockfd = ipcom_accept(sockfd, (struct Ip_sockaddr *)&frominet, &fromlen)) == ERR) ttcperror(&context,"accept"); } { union Ip_sockaddr_union peer; Ip_socklen_t peerlen = context.addrsize; /* Close the mother socket. */ if(ipcom_socketclose(oldfd) == ERR) ttcperror(&context,"close of oldfd."); #if defined(IP_SO_RCVBUF) /* Had to add this code in addition to the above because some stacks don't inherit * the receive buffer size from the server socket. /Lennart Bang Enea Ose Systems 980116. */ if(sockbufsize) { if(ipcom_setsockopt(sockfd, IP_SOL_SOCKET, IP_SO_RCVBUF, (char *)&sockbufsize, sizeof sockbufsize) == ERR) ttcperror(&context,"setsockopt: rcvbuf"); else mes(trans, "setsockopt(rcvbuf)"); } #endif if(ipcom_getpeername(sockfd, (struct Ip_sockaddr *) &peer, &peerlen) == ERR) ttcperror(&context, "getpeername"); #ifdef IPCOM_USE_INET if(context.family == IP_AF_INET) { char addr[16]; ipcom_fprintf(ip_stderr, "ttcp-r: accept from %s"IP_LF, ipcom_inet_ntop(IP_AF_INET, &peer.sin.sin_addr, addr, sizeof(addr))); } #endif #ifdef IPCOM_USE_INET6 if(context.family == IP_AF_INET6) { char addr[40]; ipcom_fprintf(ip_stderr, "ttcp-r: accept from %s"IP_LF, ipcom_inet_ntop(IP_AF_INET6, &peer.sin6.sin6_addr, addr, sizeof(addr))); } #endif } } } #endif /* Begin the TTCP performance test. */ msec0 = get_millisec(); if (mev) { #if defined (IP_PORT_INTEGRITY) #include "ipcom_integrity.h" extern void EventLogOn(void); #if IP_VER < 500 extern void EventLogMask(unsigned int newmask); EventLogMask(~0); #endif EventLogOn(); #endif } if(sinkmode) { register int cnt; /* Transmit side. */ if(trans) { pattern(buf, buflen); if(context.udp) { (void) NWRITE(sockfd, buf, UDPMINLEN, &context); /* rcvr start */ ipcom_millisleep(500); /* arp time */ /* Renew the start time to not include the 500 msec sleep */ msec0 = get_millisec(); } #ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API if (zerocopy) { while (nbuf-- && ZERONWRITE(sockfd, buflen, &context) == buflen) nbytes += buflen; } else #endif { while (nbuf-- && NWRITE(sockfd, buf, buflen, &context) == buflen) nbytes += buflen; } if(context.udp) (void) NWRITE(sockfd, buf, UDPMINLEN, &context); /* rcvr end */ } /* Receive side. */ else { if(context.udp) { int going = 0; #ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API if (zerocopy) { while ((cnt = ZeroNread(sockfd, &context)) > 0) { if(cnt <= UDPMINLEN) { if(going) break; /* "EOF" */ going = 1; msec0 = get_millisec(); } else { nbytes += cnt; } } } else #endif { while ((cnt = Nread(sockfd, buf, buflen, &context)) > 0) { if(cnt <= UDPMINLEN) { if(going) break; /* "EOF" */ going = 1; msec0 = get_millisec(); } else { nbytes += cnt; } } } } #ifdef IPCOM_USE_TCP else { while ((cnt = Nread(sockfd, buf, buflen, &context)) > 0) { nbytes += cnt; } } #endif } } #ifdef IPCOM_TTCP_USE_STDIOMODE /* non sinkmode. */ else { register int cnt; if(trans) { /* Read from standard input and send to other side. */ while ((cnt = ipcom_fread(buf, buflen, 1, ip_stdin)) > 0 && NWRITE(sockfd, buf, cnt) == cnt) nbytes += cnt; } else { /* Read from network and print on stdout. */ while ((cnt = Nread(sockfd, buf, buflen, &context)) > 0) { ipcom_fwrite(buf, cnt, 1, ip_stdout); nbytes += cnt; } } } #endif if (mev) { #if defined (IP_PORT_INTEGRITY) extern void EventLogOff(void); EventLogOff(); #elif defined (IP_PORT_RTCORE) extern void ip_trace(char *what, char *file, int line, int id, void *data); extern void ip_tracedump(void); ip_trace("[ASSERT]", __FILE__, __LINE__, ipcom_getpid(), IP_NULL); ip_tracedump(); #endif } /* Read the final time and calculate some statistics. */ msec1 = get_millisec(); msecd = msec1 - msec0; if (msecd == 0) msecd = 1; bpermsec = nbytes / msecd; /* Bytes per millisecond. */ kbpersec = nbytes / 128; kbpersec = kbpersec * 125 / msecd; /* kilobyte per sec. */ /* End of test assemble statistice. */ if(context.err_no) { ipcom_fprintf(ip_stdout, "ttcp%s: socket errno: %d."IP_LF, trans ? "-t" : "-r", context.err_no); } if(context.udp && trans) { int j; for (j = 0; j < nend; j++) { ipcom_millisleep(100); /* Let the reading side catch up. */ (void) NWRITE(sockfd, buf, UDPMINLEN, &context); /* rcvr end */ } } /* Print the statistics. */ ipcom_fprintf(ip_stdout, "ttcp%s: %lu bytes in %lu milliseconds = %lu KB/sec, %lu B/msec +++"IP_LF, trans ? "-t" : "-r", nbytes, msecd, kbpersec, bpermsec); ipcom_fprintf(ip_stdout, "ttcp%s: %lu I/O calls, msec/call = %lu, calls/sec = %lu"IP_LF, trans ? "-t" : "-r", context.numCalls, msecd / context.numCalls, 1000 * context.numCalls / msecd); if (verbose) ipcom_fprintf(ip_stdout, "ttcp%s: buffer address %p"IP_LF, trans ? "-t" : "-r", buf); /* Test succeeded, goto errorout to cleanup. */ goto errorout; /* Usage. */ usage: ipcom_fprintf(ip_stderr, "Usage: ttcp -t [-options] host [ < in ]"IP_LF "ttcp -r [-options > out]"IP_LF "Common options:"IP_LF "-x use IPv6 instead of IPv4"IP_LF "-l ## length of bufs read from or written to network (default 8192)"IP_LF #ifdef IPCOM_CMD_TTCP_USE_ZEROCOPY_API "-U use UDP and interpeak zero copy API instead of TCP"IP_LF #endif "-u use UDP (default is TCP)"IP_LF #ifdef IPSCTP "-c use SCTP STREAM type(default is TCP)"IP_LF "-S use SCTP SEQPACKET type(default is TCP)"IP_LF #endif "-p ## port number to send to or listen at (default DEFAULT_PORT)"IP_LF); ipcom_fprintf(ip_stderr, "-s -t: source a pattern to network"IP_LF "-r sink (discard) all data from network"IP_LF "-e ## number of packets to end UDP transmission"IP_LF "-m use event logging (not supported on all platforms)"IP_LF "-A align the start of buffers to this modulus (default 16384)"IP_LF "-O start buffers at this offset from the modulus (default 0)"IP_LF "-v verbose: print more statistics"IP_LF "-d set SO_DEBUG socket option (if supported)"IP_LF); ipcom_fprintf(ip_stderr, "-b ## set socket buffer size (if supported)"IP_LF "Options specific to -t:"IP_LF "-n## number of source bufs written to network (default 2048)"IP_LF "-D don't buffer TCP writes (sets TCP_NODELAY socket option)"IP_LF "Options specific to -r:"IP_LF "-B for -s, only output full blocks as specified by -l (for TAR)"IP_LF "-T \"touch\": access each byte as it's read"IP_LF #if defined(IP_SO_X_VR) "-V virtual router index (if supported)"IP_LF); #endif /* fall through to cleanup...*/ /* Free buffer and close socket if any error. */ errorout: #ifndef IP_PORT_LAS if (cpu >= 0) ipcom_proc_cpu_affinity_clr(0); #endif /* IP_PORT_LAS */ if(orgbuf) ipcom_free(orgbuf); if(sockfd != -1) { if(ipcom_socketclose(sockfd) == ERR) ipcom_fprintf(ip_stderr, "ttcp error: close of sockfd. (line %d, errno %d)."IP_LF, __LINE__, ipcom_errno); } #ifdef IP_PORT_INTEGRITY ipcom_shutdown_libsocket(); #endif return 0; }
/* *=========================================================================== * ipnet_rtnetlink_route_delroute_family *=========================================================================== * Description: Delete a route via NETLINK. * Parameters: data - Message payload * len - Length of message. * nlh - NETLINK message header * arg - Reference to route attributes. * * Returns: 0 - Success * <0 - Failure * */ IP_GLOBAL int ipnet_rtnetlink_route_delroute_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { int ret = -1; Ip_u16 vr; Ip_u32 table; Ip_u32 ifindex = 0; Ip_bool is_multipath_route = IP_FALSE; Ip_size_t mpa_size = 0; struct Ip_rtnexthop *nh = IP_NULL; struct Ip_sockaddr *gw = IP_NULL; void *mask = IP_NULL; struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlh); union Ip_sockaddr_union ugw; Ipnet_rtnetlink_key_t ukey; #ifdef IPMPLS struct Ip_sockaddr_mpls gw_mpls; #endif /* IPMPLS */ table = IPCOM_ROUTE_TABLE_GET(rtm->rtm_table); #ifdef IPNET_USE_ROUTE_TABLE_NAMES if (rta[IP_RTA_TABLE_NAME -1]) { if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]), &vr, &table) < 0) return -IP_ERRNO_ESRCH; } else #endif { if (mem->vr == IPCOM_VR_ANY) return -IP_ERRNO_EINVAL; vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr); if (rta[IP_RTA_TABLE - 1]) table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1])); } if (rta[IP_RTA_OIF -1]) { if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1])); } if (rta[IP_RTA_MULTIPATH -1]) { is_multipath_route = IP_TRUE; nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]); mpa_size = IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]); if ((nh == IP_NULL) || (mpa_size == 0)) return -IP_ERRNO_EINVAL; } if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, ifindex, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0) return ret; if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0) return ret; if (rta[IP_RTA_GATEWAY-1]) gw = &ugw.sa; #ifdef IPMPLS if (rta[IP_RTA_NH_PROTO-1]) { Ip_u32 nh_type; /* IPNET MPLS pseudo-wire route */ if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32)); if (nh_type != IPNET_ETH_P_MPLS_UNICAST) return -IP_ERRNO_EINVAL; ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls)); gw_mpls.smpls_family = IP_AF_MPLS; IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls)); ipcom_memcpy(&gw_mpls.smpls_key, IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]), sizeof(Ip_u32)); gw = (struct Ip_sockaddr *)&gw_mpls; } #endif while(1) { if (is_multipath_route) { ifindex = nh->rtnh_ifindex; if (nh->rtnh_len > sizeof(struct Ip_rtnexthop)) { /* Multihop route has gateway */ if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, IP_RTNH_DATA(nh))) < 0) return ret; } } /* Delete the route */ ret = ipnet_route_delete2(family, vr, table, &ukey, mask, gw, ifindex, 0, 0, 0); if (is_multipath_route) { mpa_size -= IP_RTNH_ALIGN(nh->rtnh_len); gw = IP_NULL; if (mpa_size > 0) nh = IP_RTNH_NEXT(nh); else break; } else break; } return is_multipath_route ? 0 : ret; }
/* *=========================================================================== * ipnet_rtnetlink_route_newroute_family *=========================================================================== * Description: Add a new rotue via NETLINK. * Parameters: data - Message payload * len - Length of message. * nlh - NETLINK message header * arg - Reference to route attributes. * * Returns: 0 - Success * <0 - Failure * */ IP_GLOBAL int ipnet_rtnetlink_route_newroute_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { Ipnet_netif *netif = IP_NULL; Ipnet_ppp_peer *p = IP_NULL; int ret = -1; Ip_u16 vr; Ip_u32 table; Ip_bool is_multipath_route = IP_FALSE; Ip_ssize_t mpa_size = 0; struct Ip_rtnexthop *nh = IP_NULL; struct Ipnet_rt_metrics metrics; struct Ip_sockaddr *gw = IP_NULL; void *mask = IP_NULL; struct Ip_sockaddr_dl gw_dl; struct Ipnet_route_add_param param; struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlh); union Ip_sockaddr_union ugw; Ipnet_rtnetlink_key_t ukey; #ifdef IPMPLS struct Ip_sockaddr_mpls gw_mpls; #endif /* IPMPLS */ #ifdef IPNET_USE_ROUTE_COOKIES Ipnet_rt_cookie cookie; #endif /* IPNET_USE_ROUTE_COOKIES */ table = IPCOM_ROUTE_TABLE_GET(rtm->rtm_table); /* Prepare route parameters */ ipcom_memset(¶m, 0, sizeof(param)); ipcom_memset(&metrics,0,sizeof(metrics)); param.flags = IPNET_RTF_STATIC | IPNET_RTF_UP | IPNET_RTF_DONE; #ifdef IPNET_USE_ROUTE_TABLE_NAMES if (rta[IP_RTA_TABLE_NAME -1]) { if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]), &vr, &table) < 0) return -IP_ERRNO_ESRCH; } else #endif { if (mem->vr == IPCOM_VR_ANY) return -IP_ERRNO_EINVAL; vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr); if (rta[IP_RTA_TABLE - 1]) table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1])); } if (rta[IP_RTA_OIF -1]) { int ifindex = 0; if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(int))) return -IP_ERRNO_EINVAL; ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1])); netif = ipnet_if_indextonetif(vr, ifindex); if (netif) p = netif->private_data; } if (rta[IP_RTA_MULTIPATH -1]) { is_multipath_route = IP_TRUE; nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]); mpa_size = IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]); if ((nh == IP_NULL) || (mpa_size == 0)) return -IP_ERRNO_EINVAL; } if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0) return ret; if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0) return ret; #ifdef IPCOM_USE_INET if (family == IP_AF_INET) { if (gw != IP_NULL) { /* Check if it is a pure gateway or not */ if (p == IP_NULL || p->peer4.s_addr != ugw.sin.sin_addr.s_addr) param.flags |= IPNET_RTF_GATEWAY; } } else #endif #ifdef IPCOM_USE_INET6 if (family == IP_AF_INET6) { if (gw != IP_NULL) { /* Check if it is a pure gateway or not */ if (p == IP_NULL || !IP_IN6_ARE_ADDR_EQUAL(&ugw.sin6.sin6_addr, &p->peer6)) param.flags |= IPNET_RTF_GATEWAY; } } else #endif { return -IP_ERRNO_EAFNOSUPPORT; } if (!mask) param.flags |= IPNET_RTF_HOST; if (rtm->rtm_type == IP_RTN_PROXY) { /* This is a proxy arp network route */ IP_BIT_CLR(param.flags, IPNET_RTF_CLONING); IP_BIT_SET(param.flags, IPNET_RTF_PROTO2); if (rta[IP_RTA_PROXY_ARP_LLADDR - 1]) { /* This is a network proxy arp with specific lladdr */ if (netif == IP_NULL) return -IP_ERRNO_EINVAL; ipcom_memset(&gw_dl, 0, sizeof(struct Ip_sockaddr_dl)); IPCOM_SA_LEN_SET(&gw_dl, sizeof(struct Ip_sockaddr_dl)); gw_dl.sdl_family = IP_AF_LINK; gw_dl.sdl_index = (Ip_u16)netif->ipcom.ifindex; gw_dl.sdl_alen = (Ip_u8) netif->ipcom.link_addr_size; gw_dl.sdl_type = (Ip_u8) netif->ipcom.type; ipcom_memcpy(IP_SOCKADDR_DL_LLADDR(&gw_dl), IP_RTA_DATA(rta[IP_RTA_PROXY_ARP_LLADDR - 1]), IPNET_ETH_ADDR_SIZE); gw = (struct Ip_sockaddr *) &gw_dl; IP_BIT_SET(param.flags, IPNET_RTF_LLINFO); } } else if (rtm->rtm_type == IP_RTN_PROHIBIT) IP_BIT_SET(param.flags, IPNET_RTF_REJECT); else if (rtm->rtm_type == IP_RTN_THROW) IP_BIT_SET(param.flags, IPNET_RTF_SKIP); else if (rtm->rtm_type == IP_RTN_UNREACHABLE) { if (netif == IP_NULL) netif = ipnet_loopback_get_netif(vr); IP_BIT_CLR(param.flags, IPNET_RTF_UP); } else if (rtm->rtm_type == IP_RTN_CLONE) IP_BIT_SET(param.flags, IPNET_RTF_CLONING); else if (rtm->rtm_type == IP_RTN_BLACKHOLE) IP_BIT_SET(param.flags, IPNET_RTF_BLACKHOLE); #ifdef IPMPLS /* Check for IPNET MPLS pseudo-wire route */ if (rta[IP_RTA_NH_PROTO-1]) { Ip_u32 nh_type; if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32)); if (nh_type != IPNET_ETH_P_MPLS_UNICAST) return -IP_ERRNO_EINVAL; ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls)); gw_mpls.smpls_family = IP_AF_MPLS; IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls)); ipcom_memcpy(&gw_mpls.smpls_key, IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]), sizeof(Ip_u32)); IP_BIT_CLR(param.flags,IPNET_RTF_GATEWAY); gw = (struct Ip_sockaddr *)&gw_mpls; } else { /* Check if cloning flag shall be set */ if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_HOST | IPNET_RTF_GATEWAY | IPNET_RTF_REJECT | IPNET_RTF_BLACKHOLE)) IP_BIT_SET(param.flags, IPNET_RTF_CLONING); } #endif if (rta[IP_RTA_METRICS-1]) { int rlen = (int)IP_RTA_PAYLOAD(rta[IP_RTA_METRICS-1]); Ip_u32 dummy = 0; struct Ip_rtattr *rtax = (struct Ip_rtattr*)IP_RTA_DATA(rta[IP_RTA_METRICS-1]); metrics.rmx_expire = IPCOM_ADDR_INFINITE; param.metrics = &metrics; for(;rlen > 0; rlen -= (int)rtax->rta_len,rtax = IP_RTA_NEXT(rtax,dummy)) { switch (rtax->rta_type) { case IP_RTAX_MTU: ipcom_memcpy(&metrics.rmx_mtu, IP_RTA_DATA(rtax), sizeof(Ip_u32)); break; case IP_RTAX_RTT: ipcom_memcpy(&metrics.rmx_rtt, IP_RTA_DATA(rtax), sizeof(Ip_u32)); break; case IP_RTAX_RTTVAR: ipcom_memcpy(&metrics.rmx_rttvar, IP_RTA_DATA(rtax), sizeof(Ip_u32)); break; } } } #ifdef IPNET_USE_ROUTE_COOKIES if (rta[IP_RTA_COOKIE-1]) { if (IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1]) > sizeof(cookie)) return -IP_ERRNO_EINVAL; ipcom_memset(&cookie, 0, sizeof(cookie)); ipcom_memcpy(&cookie, IP_RTA_DATA(rta[IP_RTA_COOKIE-1]), IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1])); param.cookie = &cookie; } #endif /* IPNET_USE_ROUTE_COOKIES */ while (1) { if (is_multipath_route && (gw == IP_NULL)) { netif = ipnet_if_indextonetif(vr, nh->rtnh_ifindex); metrics.rmx_hopcount = nh->rtnh_hops; metrics.rmx_expire = IPCOM_ADDR_INFINITE; param.metrics = &metrics; if (nh->rtnh_len > sizeof(struct Ip_rtnexthop)) { /* Multihop route has gateway */ IP_BIT_CLR(param.flags, IPNET_RTF_CLONING); IP_BIT_SET(param.flags, IPNET_RTF_GATEWAY); if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, IP_RTNH_DATA(nh))) < 0) return ret; } mpa_size -= IP_RTNH_ALIGN(nh->rtnh_len); if (mpa_size > 0) nh = IP_RTNH_NEXT(nh); } param.domain = family; param.vr = vr; param.table = table; param.netif = netif; param.key = &ukey; param.netmask = mask; param.gateway = gw; param.pid = mem->pid; param.seq = nlh->nlmsg_seq; param.no_ref_count = IP_TRUE; /* Try to add the route */ if (netif) IPNET_IF_LOCK(netif); ret = ipnet_route_add(¶m); if (netif != IP_NULL) IPNET_IF_UNLOCK(netif); if (is_multipath_route) { gw = IP_NULL; if (ret < 0 && ret != -IP_ERRNO_EEXIST) goto rollback; if (mpa_size == 0) { ret = 0; break; } else if (mpa_size < 0) { /* Malformed packet */ ret = -IP_ERRNO_EINVAL; goto rollback; } } else break; } return ret; rollback: (void)ipnet_rtnetlink_route_delroute_family(mem, nlh, rta, family); return ret; }
/* *=========================================================================== * 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(¶m, 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(¶m); 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; }