in nshlib/nsh_routecmds.c [95:454]
int cmd_addroute(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
{
union
{
#ifdef CONFIG_NET_IPv4
struct sockaddr_in ipv4;
#endif
#ifdef CONFIG_NET_IPv6
struct sockaddr_in6 ipv6;
#endif
struct sockaddr_storage ipx;
} target;
union
{
#ifdef CONFIG_NET_IPv4
struct sockaddr_in ipv4;
#endif
#ifdef CONFIG_NET_IPv6
struct sockaddr_in6 ipv6;
#endif
struct sockaddr_storage ipx;
} netmask;
union
{
#ifdef CONFIG_NET_IPv4
struct sockaddr_in ipv4;
#endif
#ifdef CONFIG_NET_IPv6
struct sockaddr_in6 ipv6;
#endif
struct sockaddr_storage ipx;
} router;
union
{
#ifdef CONFIG_NET_IPv4
struct in_addr ipv4;
#endif
#ifdef CONFIG_NET_IPv6
struct in6_addr ipv6;
#endif
} inaddr;
sa_family_t family;
int rtrndx;
int shift;
int sockfd;
int ret;
FAR char *sptr;
/* First, check if we are setting the default route */
if (strcmp(argv[1], "default") == 0)
{
/* We are expecting an ip and an interface name to follow. */
if (argc < 4)
{
nsh_error(vtbl, g_fmtargrequired, argv[0]);
goto errout;
}
else if (argc > 4)
{
nsh_error(vtbl, g_fmttoomanyargs, argv[0]);
goto errout;
}
/* Convert the target IP address string into its binary form */
#ifdef CONFIG_NET_IPv4
family = PF_INET;
ret = inet_pton(AF_INET, argv[2], &inaddr.ipv4);
if (ret != 1)
#endif
{
#ifdef CONFIG_NET_IPv6
family = PF_INET6;
ret = inet_pton(AF_INET6, argv[2], &inaddr.ipv6);
if (ret != 1)
#endif
{
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
goto errout;
}
}
#ifdef CONFIG_NET_IPv4
if (family == PF_INET)
{
ret = netlib_set_dripv4addr(argv[3], &inaddr.ipv4);
if (ret != 0)
{
nsh_error(vtbl, g_fmtcmdfailed, argv[0]);
goto errout;
}
}
#endif
#ifdef CONFIG_NET_IPv6
if (family == PF_INET6)
{
ret = netlib_set_dripv6addr(argv[3], &inaddr.ipv6);
if (ret != 0)
{
nsh_error(vtbl, g_fmtcmdfailed, argv[0]);
goto errout;
}
}
#endif
return OK;
}
/* Check if slash notation is used with the target address */
shift = slash_notation(argv[1]);
/* There will be 2 or 3 arguments, depending on if slash notation is
* used.
*/
if (shift > 0 && argc != 3)
{
nsh_error(vtbl, g_fmttoomanyargs, argv[0]);
goto errout;
}
else if (shift < 0 && argc != 4)
{
nsh_error(vtbl, g_fmtargrequired, argv[0]);
goto errout;
}
/* We need to remove the slash notation before passing it to inet_pton */
if (shift > 0)
{
sptr = strchr(argv[1], '/');
if (sptr != NULL)
{
*sptr = '\0';
}
}
/* Convert the target IP address string into its binary form */
#ifdef CONFIG_NET_IPv4
family = PF_INET;
ret = inet_pton(AF_INET, argv[1], &inaddr.ipv4);
if (ret != 1)
#endif
{
#ifdef CONFIG_NET_IPv6
family = PF_INET6;
ret = inet_pton(AF_INET6, argv[1], &inaddr.ipv6);
if (ret != 1)
#endif
{
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
goto errout;
}
}
/* We need to have a socket (any socket) in order to perform the ioctl */
sockfd = socket(NET_SOCK_FAMILY, NET_SOCK_TYPE, NET_SOCK_PROTOCOL);
if (sockfd < 0)
{
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "socket", NSH_ERRNO);
goto errout;
}
/* Format the target sockaddr instance */
memset(&target, 0, sizeof(target));
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (family == PF_INET)
#endif
{
target.ipv4.sin_family = AF_INET;
target.ipv4.sin_addr = inaddr.ipv4;
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
target.ipv6.sin6_family = AF_INET6;
memcpy(&target.ipv6.sin6_addr, &inaddr.ipv6,
sizeof(struct in6_addr));
}
#endif
/* Convert the netmask IP address string into its binary form */
if (shift >= 0)
{
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (family == PF_INET)
#endif
{
/* /0 -> 0x00000000
* /8 -> 0xff000000
* /24 -> 0xffffff00
* /32 -> 0xffffffff
*/
if (shift > 32)
{
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
goto errout_with_sockfd;
}
inaddr.ipv4.s_addr = htonl(0xffffffff << (32 - shift));
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
int i;
/* /0 -> 0000:0000:0000:0000:0000:0000:0000:0000
* /16 -> ffff:0000:0000:0000:0000:0000:0000:0000
* /32 -> ffff:ffff:0000:0000:0000:0000:0000:0000
* ...
* /128 -> ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
*/
memset(&inaddr.ipv6, 0, sizeof(inaddr.ipv6));
for (i = 0; i < 8 && shift >= 16; i++, shift -= 16)
{
inaddr.ipv6.s6_addr16[i] = 0xffff;
}
if (shift > 16 || (shift > 0 && i >= 8))
{
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
goto errout_with_sockfd;
}
/* /0 -> 0x0000
* /1 -> 0x8000
* /2 -> 0xc000
* ...
* /16 -> 0xffff
*/
if (shift > 0)
{
inaddr.ipv6.s6_addr16[i] = htons(0xffff << (16 - shift));
}
}
#endif
rtrndx = 2;
}
else
{
/* Slash notation not used.. mask should follow the target address */
ret = inet_pton(family, argv[2], &inaddr);
if (ret != 1)
{
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
goto errout_with_sockfd;
}
rtrndx = 3;
}
/* Format the netmask sockaddr instance */
memset(&netmask, 0, sizeof(netmask));
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (family == PF_INET)
#endif
{
netmask.ipv4.sin_family = AF_INET;
netmask.ipv4.sin_addr = inaddr.ipv4;
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
netmask.ipv6.sin6_family = AF_INET6;
memcpy(&netmask.ipv6.sin6_addr, &inaddr.ipv6,
sizeof(struct in6_addr));
}
#endif
/* Convert the router IP address string into its binary form */
ret = inet_pton(family, argv[rtrndx], &inaddr);
if (ret != 1)
{
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
goto errout_with_sockfd;
}
/* Format the router sockaddr instance */
memset(&router, 0, sizeof(router));
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (family == PF_INET)
#endif
{
router.ipv4.sin_family = AF_INET;
router.ipv4.sin_addr = inaddr.ipv4;
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
router.ipv6.sin6_family = AF_INET6;
memcpy(&router.ipv6.sin6_addr, &inaddr.ipv6,
sizeof(struct in6_addr));
}
#endif
/* Then add the route */
ret = addroute(sockfd, &target.ipx, &netmask.ipx,
&router.ipx, sizeof(router));
if (ret < 0)
{
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "addroute", NSH_ERRNO);
goto errout_with_sockfd;
}
close(sockfd);
return OK;
errout_with_sockfd:
close(sockfd);
errout:
return ERROR;
}