/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcpc6_shell.c,v $ $Revision: 1.13.18.1 $ * $Source: /home/interpeak/CVSRoot/ipdhcpc6/src/ipdhcpc6_shell.c,v $ * $Author: ulf $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipdhcpc6_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include "ipdhcpc6.h" #include "ipdhcpc6_h.h" #include "ipdhcpc6_msg.h" #include "ipdhcpc6_if.h" #include "ipdhcpc6_ia.h" #include "ipdhcpc6_shell.h" #include "ipdhcpc6_attr.h" #include "ipdhcpc6_rtadv.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipdhcpc6_shell_args { Ipdhcpc6_context_t *context; Ipdhcpc6_tagcomm_buffer_t *buf; Ipdhcpc6_if_t *ifp; Ipdhcpc6_ia_t *ia; Ip_u32 cmd; } Ipdhcpc6_shell_args_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC int ipdhcpc6_shell_parse_ia_command(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag); IP_STATIC int ipdhcpc6_shell_parse_ia_command_attributes(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag); IP_STATIC int ipdhcpc6_shell_parse_ia_ifobj_attributes(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag); /* **************************************************************************** * 8 DATA **************************************************************************** */ static Ipdhcpc6_tagcomm_parser_t ipdhcpc6_shell_commands[] = { { IPDHCPC6_CMD_IA_INFO, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { IPDHCPC6_CMD_IA_REFRESH, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { IPDHCPC6_CMD_IA_RELEASE, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { IPDHCPC6_CMD_IA_HISTORY_FLUSH, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { IPDHCPC6_CMD_IA_RTSOL, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { IPDHCPC6_CMD_IA_BOUND_ADD, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { IPDHCPC6_CMD_IA_BOUND_DEL, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command }, { 0, IP_NULL } }; static Ipdhcpc6_tagcomm_parser_t ipdhcpc6_shell_ia_command_attributes[] = { { IPDHCPC6_IA_OBJECT_IF, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command_attributes }, { IPDHCPC6_IA_IDENT_DUID, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_command_attributes }, { 0, IP_NULL } }; static Ipdhcpc6_tagcomm_parser_t ipdhcpc6_shell_ia_ifobj_attributes[] = { { IPDHCPC6_IA_OBJECT_IF_AUTOMATIC, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_ifobj_attributes }, { IPDHCPC6_IA_OBJECT_IF_CONFIG, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_ifobj_attributes }, { IPDHCPC6_IA_OBJECT_IA, (Ipdhcpc6_tagcomm_parse_object_t) ipdhcpc6_shell_parse_ia_ifobj_attributes }, { 0, IP_NULL } }; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipdhcpc6_shell_context_client_free *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipdhcpc6_shell_context_client_free(Ipdhcpc6_shell_client_t *cfd) { ipcom_list_remove(&cfd->next); ipdhcpc6_util_free(&cfd->rbuf.buffer); if (cfd->fd != IP_INVALID_SOCKET) ipcom_socketclose(cfd->fd); ipdhcpc6_util_free(&cfd); } /* *=========================================================================== * ipdhcpc6_shell_parse_errout *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipdhcpc6_shell_parse_errout(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag) { ipdhcpc6_tagcomm_failure(args->buf, tag, IPDHCPC6_TAGCOMM_STATUS_UNKNOWN_TAG); return 0; } /* *=========================================================================== * ipdhcpc6_shell_parse_ia_ifobj_attributes *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipdhcpc6_shell_parse_ia_ifobj_attributes(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag) { Ipdhcpc6_attr_ia_t *iaobj; switch (tag->tag) { case IPDHCPC6_IA_OBJECT_IF_CONFIG: if (args->cmd == IPDHCPC6_CMD_IA_INFO) { ipdhcpc6_tagcomm_enter_tag(args->buf, IPDHCPC6_IA_OBJECT_IF_CONFIG, IPDHCPC6_TAGCOMM_STATUS_OK); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_RAPID_COMMIT, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.rapid_commit, sizeof(args->ifp->conf.rapid_commit)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_INFO_ONLY, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.information_only, sizeof(args->ifp->conf.information_only)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_DNS, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.dns, sizeof(args->ifp->conf.dns)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_SNTP, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.sntp, sizeof(args->ifp->conf.sntp)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_INFO_REFRESH, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.information_only, sizeof(args->ifp->conf.information_only)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_SIP, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.sip, sizeof(args->ifp->conf.sip)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_CONFIG_FQDN, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->conf.fqdn.fqdn, sizeof(args->ifp->conf.fqdn.fqdn)); ipdhcpc6_tagcomm_leave_tag(args->buf); } break; case IPDHCPC6_IA_OBJECT_IF_AUTOMATIC: if (args->cmd == IPDHCPC6_CMD_IA_INFO) { if (args->ifp->mode == IPDHCPC6_MODE_AUTOMATIC) { ipdhcpc6_tagcomm_enter_tag(args->buf, IPDHCPC6_IA_OBJECT_IF_AUTOMATIC, IPDHCPC6_TAGCOMM_STATUS_OK); if (IP_IN6_ARE_ADDR_EQUAL(&args->ifp->automatic.rtr, &ip_in6addr_any) == IP_FALSE) { ipdhcpc6_tagcomm_enter_tag(args->buf, IPDHCPC6_IA_OBJECT_SERVER, IPDHCPC6_TAGCOMM_STATUS_OK); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_ADDRESS, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->automatic.rtr, sizeof(args->ifp->automatic.rtr)); ipdhcpc6_tagcomm_leave_tag(args->buf); } ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_AUTOMATIC_MANAGED, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->automatic.runtime.managed, sizeof(args->ifp->automatic.runtime.managed)); ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_ATTR_IF_AUTOMATIC_OTHER, IPDHCPC6_TAGCOMM_STATUS_OK, &args->ifp->automatic.runtime.other, sizeof(args->ifp->automatic.runtime.other)); ipdhcpc6_tagcomm_leave_tag(args->buf); } } break; case IPDHCPC6_IA_OBJECT_IA: iaobj = ipdhcpc6_attr_ia_parse(tag, IPDHCPC6_TAGCOMM_TAG_IDENTITY); if (iaobj) { if (iaobj->iatype >= IPDHCPC6_IA_TYPE_MAX) { ipdhcpc6_tagcomm_failure(args->buf, tag, IPDHCPC6_ATTR_TAG_STATUS_UNKNOWN_IA); } else { /* Not specified */ if (iaobj->ianame == IP_NULL && iaobj->iaid == 0) { args->ia = IPCOM_LIST_FIRST(&args->ifp->ia_head[iaobj->iatype]); while (args->ia != IP_NULL) { args->ia->table->attributes(args->cmd, args->ia, tag, args->buf); /* Next IA */ args->ia = IPCOM_LIST_NEXT(&args->ia->next); } } else { args->ia = ipdhcpc6_ia_lookup_by_iaobj(args->ifp, iaobj); if (args->ia == IP_NULL) { ipdhcpc6_tagcomm_failure(args->buf, tag, IPDHCPC6_ATTR_TAG_STATUS_UNKNOWN_IA); } else { args->ia->table->attributes(args->cmd, args->ia, tag, args->buf); } } } ipdhcpc6_attr_ia_free(&iaobj); } else { ipdhcpc6_tagcomm_failure(args->buf, tag, IPDHCPC6_TAGCOMM_STATUS_PARSE_FAILED); } break; } return 0; } /* *=========================================================================== * ipdhcpc6_shell_parse_ia_command_attributes *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipdhcpc6_shell_parse_ia_command_attributes(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag) { int result = 0; Ipdhcpc6_attr_if_t *ifobj; /* Store base command */ switch (tag->tag) { case IPDHCPC6_IA_OBJECT_IF: ifobj = ipdhcpc6_attr_if_parse(tag, IPDHCPC6_TAGCOMM_TAG_IDENTITY); if (ifobj) { if (ifobj->ifname == IP_NULL) { /* Wild card match */ args->ifp = IPCOM_LIST_FIRST(&args->context->ifctx->ifp_head); while (args->ifp != IP_NULL) { ipdhcpc6_tagcomm_enter_tag(args->buf, tag->tag, IPDHCPC6_TAGCOMM_STATUS_OK); ipdhcpc6_if_attr_header(args->ifp, args->buf); switch (args->cmd) { case IPDHCPC6_CMD_IA_RTSOL: ipdhcpc6_rtadv_up(args->ifp->context->context, args->ifp); break; default: result = ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_ia_ifobj_attributes, (Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout, tag, args); break; } ipdhcpc6_tagcomm_leave_tag(args->buf); if (result != 0) break; /* Next interface */ args->ifp = IPCOM_LIST_NEXT(&args->ifp->next); } } else { args->ifp = ipdhcpc6_if_lookup_by_ifobj(args->context, ifobj); if (args->ifp == IP_NULL) { ipdhcpc6_tagcomm_failure(args->buf, tag, IPDHCPC6_ATTR_TAG_STATUS_UNKNOWN_INTERFACE); } else { ipdhcpc6_tagcomm_enter_tag(args->buf, tag->tag, IPDHCPC6_TAGCOMM_STATUS_OK); ipdhcpc6_if_attr_header(args->ifp, args->buf); switch (args->cmd) { case IPDHCPC6_CMD_IA_RTSOL: ipdhcpc6_rtadv_up(args->ifp->context->context, args->ifp); break; default: result = ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_ia_ifobj_attributes, (Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout, tag, args); break; } ipdhcpc6_tagcomm_leave_tag(args->buf); } } ipdhcpc6_attr_if_free(&ifobj); } else { ipdhcpc6_tagcomm_failure(args->buf, tag, IPDHCPC6_TAGCOMM_STATUS_PARSE_FAILED); } break; } return result; } /* *=========================================================================== * ipdhcpc6_shell_parse_ia_command *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipdhcpc6_shell_parse_ia_command(Ipdhcpc6_shell_args_t *args, Ipdhcpc6_tagcomm_tag_t *tag) { int result; /* Store base command */ args->cmd = tag->tag; ipdhcpc6_tagcomm_enter_tag(args->buf, tag->tag, IPDHCPC6_TAGCOMM_STATUS_OK); /* Add the DUID */ ipdhcpc6_tagcomm_add_tag(args->buf, IPDHCPC6_IA_IDENT_DUID, IPDHCPC6_TAGCOMM_STATUS_OK, args->context->ifctx->duid.head, args->context->ifctx->duid.offset); result = ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_ia_command_attributes, (Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout, tag, args); ipdhcpc6_tagcomm_leave_tag(args->buf); return result; } /* *=========================================================================== * ipdhcpc6_shell_command *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipdhcpc6_shell_parse_command(Ipdhcpc6_context_t *context, Ipdhcpc6_tagcomm_tag_t *tag, Ipdhcpc6_tagcomm_buffer_t *response) { Ipdhcpc6_shell_args_t args; ipcom_memset(&args, 0, sizeof(args)); args.context = context; args.buf = response; return ipdhcpc6_tagcomm_parse(ipdhcpc6_shell_commands, (Ipdhcpc6_tagcomm_parse_object_t)ipdhcpc6_shell_parse_errout, tag, &args); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipdhcpc6_shell_context_alloc *=========================================================================== * Description: Allocate an shell context * Parameters: context - The DHCPC6 context. * Returns: An shell context. * */ IP_GLOBAL Ipdhcpc6_shell_context_t * ipdhcpc6_shell_context_alloc(struct Ipdhcpc6_context *context) { Ipdhcpc6_shell_context_t *shellctx = ipcom_calloc(1, sizeof(*shellctx)); if (shellctx) { struct Ip_sockaddr_in6 sin6; int opt; shellctx->context = context; /* Create the client head */ ipcom_list_init(&shellctx->head); /* Create the FD */ shellctx->client_fd = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, IP_IPPROTO_TCP); if (shellctx->client_fd == IP_INVALID_SOCKET) goto errout; ipcom_memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = IP_AF_INET6; sin6.sin6_len = sizeof(sin6); sin6.sin6_port = ip_htons(IPDHCPC6_CLIENT_PORT); sin6.sin6_addr = ip_in6addr_loopback; opt = 1; if (ipcom_setsockopt(shellctx->client_fd, IP_SOL_SOCKET, IP_SO_REUSEPORT, (char *)&opt, sizeof(opt)) < 0) { IPCOM_LOG2(WARNING, "%s: Failed to set reuse port on client socket, errno = %d", context->name, ipcom_errno); } if (ipcom_bind(shellctx->client_fd, (struct Ip_sockaddr *) &sin6, sizeof(sin6)) < 0) { IPCOM_LOG2(ERR, "%s: Failed to bind client socket, errno = %d", context->name, ipcom_errno); goto errout; } if (ipcom_listen(shellctx->client_fd, 5) < 0) { IPCOM_LOG2(ERR, "%s: Failed to listen on client socket, errno = %d", context->name, ipcom_errno); goto errout; } } return shellctx; errout: if (shellctx->client_fd != IP_INVALID_SOCKET) ipcom_socketclose(shellctx->client_fd); ipdhcpc6_util_free(&shellctx); return IP_NULL; } /* *=========================================================================== * ipdhcpc6_shell_context_free *=========================================================================== * Description: Free an shell context * Parameters: shellctxp - Pointer to the DHCPC6 shellcontext. * Returns: * */ IP_GLOBAL void ipdhcpc6_shell_context_free(Ipdhcpc6_shell_context_t **shellctxp) { Ipdhcpc6_shell_context_t *shellctx = *shellctxp; if (shellctx) { Ipdhcpc6_shell_client_t *cfd; while ((cfd = IPCOM_LIST_FIRST(&shellctx->head)) != IP_NULL) ipdhcpc6_shell_context_client_free(cfd); ipcom_socketclose(shellctx->client_fd); ipdhcpc6_util_free(&shellctx); } *shellctxp = IP_NULL; } /* *=========================================================================== * ipdhcpc6_shell_context_fdset_init *=========================================================================== * Description: Initialize all file descriptors of this context * Parameters: shellctx - Attribute context * rset - Read set to initialize. * mfd - Maximum file descriptor. * Returns: * */ IP_GLOBAL void ipdhcpc6_shell_context_fdset_init(Ipdhcpc6_shell_context_t *shellctx, Ip_fd_set *rset, int *mfd) { int maxfd = *mfd; Ipdhcpc6_shell_client_t *cfd; /* Add the client socket */ IP_FD_SET(shellctx->client_fd, rset); maxfd = IP_MAX(shellctx->client_fd, maxfd); cfd = IPCOM_LIST_FIRST(&shellctx->head); while (cfd != IP_NULL) { IP_FD_SET(cfd->fd, rset); maxfd = IP_MAX(cfd->fd, maxfd); cfd = IPCOM_LIST_NEXT(&cfd->next); } *mfd = maxfd; } /* *=========================================================================== * ipdhcpc6_shell_context_fdset_process *=========================================================================== * Description: Process all file descriptors of this context * Parameters: shellctx - Attribute context * rset - Read set to initialize. * status - Incoming status * Returns: Outgoing status * */ IP_GLOBAL int ipdhcpc6_shell_context_fdset_process(Ipdhcpc6_shell_context_t *shellctx, Ip_fd_set *rset, int status) { Ipdhcpc6_shell_client_t *cfd, *ncfd; /* Check the clients */ cfd = IPCOM_LIST_FIRST(&shellctx->head); while (cfd != IP_NULL) { Ip_ssize_t ret; ncfd = IPCOM_LIST_NEXT(&cfd->next); /**/ if (IP_FD_ISSET(cfd->fd, rset)) { if (cfd->rbuf.buffer == IP_NULL) { if (ipdhcpc6_attr_recvhdr(cfd->fd, &cfd->rbuf) == IP_FALSE) { ipdhcpc6_shell_context_client_free(cfd); cfd = IP_NULL; } } if (cfd) { ret = ipdhcpc6_attr_read(cfd->fd, &cfd->rbuf, IP_FALSE); if (ret < 0) ipdhcpc6_shell_context_client_free(cfd); else if (ret == 0) { Ipdhcpc6_tagcomm_buffer_t *response = ipdhcpc6_tagcomm_buffer_alloc(); if (response) { /* We've got an entire command */ if (ipdhcpc6_shell_parse_command(shellctx->context, (void *)cfd->rbuf.buffer, response) == 0) { ipdhcpc6_attr_sendmsg(cfd->fd, response); } ipdhcpc6_tagcomm_buffer_free(&response); } /* Free the current buffer */ ipdhcpc6_util_free(&cfd->rbuf.buffer); } } } /* Do next */ cfd = ncfd; } /* Check the */ if (IP_FD_ISSET(shellctx->client_fd, rset)) { /* Do create a new client */ ncfd = ipcom_calloc(1, sizeof(*ncfd)); if (ncfd) { struct Ip_sockaddr_in6 sin6; Ip_socklen_t slen = sizeof(sin6); ipcom_list_insert_last(&shellctx->head, &ncfd->next); ncfd->fd = ipcom_accept(shellctx->client_fd, (struct Ip_sockaddr *)&sin6, &slen); if (ncfd->fd == IP_INVALID_SOCKET) ipdhcpc6_shell_context_client_free(ncfd); } } return status; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */