error_t dhcpv6RelayStop(Dhcpv6RelayCtx *context) { uint_t i; //Debug message TRACE_INFO("Stopping DHCPv6 relay agent...\r\n"); //Ensure the specified pointer is valid if(!context) return ERROR_INVALID_PARAMETER; //Check DHCPv6 relay agent state if(!context->running) return ERROR_WRONG_STATE; //Reset ACK event before sending the kill signal osEventReset(context->ackEvent); //Stop the DHCPv6 relay agent task context->stopRequest = TRUE; //Send a signal to the task in order to abort any blocking operation osEventSet(context->event); //Wait for the process to terminate... osEventWait(context->ackEvent, INFINITE_DELAY); //Leave the All_DHCP_Relay_Agents_and_Servers multicast group //for each client-facing interface dhcpv6RelayLeaveMulticastGroup(context); //Close the socket that carries traffic towards the DHCPv6 server socketClose(context->serverSocket); //Properly dispose the sockets that carry traffic towards the DHCPv6 clients for(i = 0; i < context->clientInterfaceCount; i++) socketClose(context->clientSocket[i]); //Close event objects osEventClose(context->event); osEventClose(context->ackEvent); //Successful processing return NO_ERROR; }
int_t select(int_t nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const timeval *timeout) { int_t i; int_t j; int_t n; int_t s; time_t time; uint_t eventMask; uint_t eventFlags; OsEvent *event; fd_set *fds; //Create an event object to get notified of socket events event = osEventCreate(FALSE, FALSE); //Any error to report? if(event == OS_INVALID_HANDLE) { socketError(NULL, ERROR_OUT_OF_RESOURCES); return SOCKET_ERROR; } //Parse all the descriptor sets for(i = 0; i < 3; i ++) { //Select the suitable descriptor set switch(i) { case 0: //Set of sockets to be checked for readability fds = readfds; eventMask = SOCKET_EVENT_RX_READY; break; case 1: //Set of sockets to be checked for writability fds = writefds; eventMask = SOCKET_EVENT_TX_READY; break; default: //Set of sockets to be checked for errors fds = exceptfds; eventMask = SOCKET_EVENT_CLOSED; break; } //Each descriptor is optional and may be omitted if(fds != NULL) { //Parse the current set of sockets for(j = 0; j < fds->fd_count; j++) { //Get the descriptor associated with the current entry s = fds->fd_array[j]; //Subscribe to the requested events socketRegisterEvents(&socketTable[s], event, eventMask); } } } //Retrieve timeout value if(timeout != NULL) time = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; else time = INFINITE_DELAY; //Block the current task until an event occurs osEventWait(event, time); //Count the number of events in the signaled state n = 0; //Parse all the descriptor sets for(i = 0; i < 3; i ++) { //Select the suitable descriptor set switch(i) { case 0: //Set of sockets to be checked for readability fds = readfds; eventMask = SOCKET_EVENT_RX_READY; break; case 1: //Set of sockets to be checked for writability fds = writefds; eventMask = SOCKET_EVENT_TX_READY; break; default: //Set of sockets to be checked for errors fds = exceptfds; eventMask = SOCKET_EVENT_CLOSED; break; } //Each descriptor is optional and may be omitted if(fds != NULL) { //Parse the current set of sockets for(j = 0; j < fds->fd_count; ) { //Get the descriptor associated with the current entry s = fds->fd_array[j]; //Retrieve event flags for the current socket socketGetEvents(&socketTable[s], &eventFlags); //Unsubscribe previously registered events socketUnregisterEvents(&socketTable[s]); //Event flag is set? if(eventFlags & eventMask) { //Track the number of events in the signaled state n++; //Jump to the next socket descriptor j++; } else { //Remove descriptor from the current set selectFdClr(fds, s); } } } } //Close event osEventClose(event); //Return the number of events in the signaled state return n; }
error_t tcpIpStackConfigInterface(NetInterface *interface) { error_t error; //IPv6 specific variables #if (IPV6_SUPPORT == ENABLED) Ipv6Addr solicitedNodeAddr; #endif //Disable Ethernet controller interrupts interface->nicDriver->disableIrq(interface); //Start of exception handling block do { //Receive notifications when the transmitter is ready to send interface->nicTxEvent = osEventCreate(FALSE, FALSE); //Out of resources? if(interface->nicTxEvent == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop immediately break; } //Receive notifications when a Ethernet frame has been received, //or the link status has changed interface->nicRxEvent = osEventCreate(FALSE, FALSE); //Out of resources? if(interface->nicRxEvent == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop immediately break; } //Create a mutex to prevent simultaneous access to the NIC driver interface->nicDriverMutex = osMutexCreate(FALSE); //Out of resources? if(interface->nicDriverMutex == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop immediately break; } //Ethernet controller configuration error = interface->nicDriver->init(interface); //Any error to report? if(error) break; //Ethernet related initialization error = ethInit(interface); //Any error to report? if(error) break; //IPv4 specific initialization #if (IPV4_SUPPORT == ENABLED) //Network layer initialization error = ipv4Init(interface); //Any error to report? if(error) break; //ARP cache initialization error = arpInit(interface); //Any error to report? if(error) break; #if (IGMP_SUPPORT == ENABLED) //IGMP related initialization error = igmpInit(interface); //Any error to report? if(error) break; //Join the all-systems group error = ipv4JoinMulticastGroup(interface, IGMP_ALL_SYSTEMS_ADDR); //Any error to report? if(error) break; #endif #endif //IPv6 specific initialization #if (IPV6_SUPPORT == ENABLED) //Network layer initialization error = ipv6Init(interface); //Any error to report? if(error) break; //Neighbor cache initialization error = ndpInit(interface); //Any error to report? if(error) break; #if (MLD_SUPPORT == ENABLED) ///MLD related initialization error = mldInit(interface); //Any error to report? if(error) break; #endif //Join the All-Nodes multicast address error = ipv6JoinMulticastGroup(interface, &IPV6_LINK_LOCAL_ALL_NODES_ADDR); //Any error to report? if(error) break; //Form the Solicited-Node address for the link-local address error = ipv6ComputeSolicitedNodeAddr(&interface->ipv6Config.linkLocalAddr, &solicitedNodeAddr); //Any error to report? if(error) break; //Join the Solicited-Node multicast group for each assigned address error = ipv6JoinMulticastGroup(interface, &solicitedNodeAddr); //Any error to report? if(error) break; #endif //Create a task to process incoming frames interface->rxTask = osTaskCreate("TCP/IP Stack (RX)", tcpIpStackRxTask, interface, TCP_IP_RX_STACK_SIZE, TCP_IP_RX_PRIORITY); //Unable to create the task? if(interface->rxTask == OS_INVALID_HANDLE) error = ERROR_OUT_OF_RESOURCES; //End of exception handling block } while(0); //Check whether the interface is fully configured if(!error) { //Successful interface configuration interface->configured = TRUE; //Interrupts can be safely enabled interface->nicDriver->enableIrq(interface); } else { //Clean up side effects before returning osEventClose(interface->nicTxEvent); osEventClose(interface->nicRxEvent); osMutexClose(interface->nicDriverMutex); } //Return status code return error; }
error_t dhcpv6RelayStart(Dhcpv6RelayCtx *context, const Dhcpv6RelaySettings *settings) { error_t error; uint_t i; OsTask *task; //Debug message TRACE_INFO("Starting DHCPv6 relay agent...\r\n"); //Ensure the parameters are valid if(!context || !settings) return ERROR_INVALID_PARAMETER; //The pointer to the network-facing interface shall be valid if(!settings->serverInterface) return ERROR_INVALID_INTERFACE; //Check the number of client-facing interfaces if(!settings->clientInterfaceCount) return ERROR_INVALID_PARAMETER; if(settings->clientInterfaceCount >= DHCPV6_RELAY_MAX_CLIENT_IF) return ERROR_INVALID_PARAMETER; //Loop through the client-facing interfaces for(i = 0; i < settings->clientInterfaceCount; i++) { //A valid pointer is required for each interface if(!settings->clientInterface[i]) return ERROR_INVALID_INTERFACE; } //Check the address to be used when forwarding messages to the server if(ipv6CompAddr(&settings->serverAddress, &IPV6_UNSPECIFIED_ADDR)) return ERROR_INVALID_ADDRESS; //Clear the DHCPv6 relay agent context memset(context, 0, sizeof(Dhcpv6RelayCtx)); //Save the network-facing interface context->serverInterface = settings->serverInterface; //Save the number of client-facing interfaces context->clientInterfaceCount = settings->clientInterfaceCount; //Save all the client-facing interfaces for(i = 0; i < context->clientInterfaceCount; i++) context->clientInterface[i] = settings->clientInterface[i]; //Save the address to be used when relaying client messages to the server context->serverAddress = settings->serverAddress; //Join the All_DHCP_Relay_Agents_and_Servers multicast group //for each client-facing interface error = dhcpv6RelayJoinMulticastGroup(context); //Any error to report? if(error) return error; //Start of exception handling block do { //Open a UDP socket to handle the network-facing interface context->serverSocket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); //Failed to open socket? if(!context->serverSocket) { //Report an error error = ERROR_OPEN_FAILED; //Stop processing break; } //Explicitly associate the socket with the relevant interface error = socketBindToInterface(context->serverSocket, context->serverInterface); //Unable to bind the socket to the desired interface? if(error) break; //Relay agents listen for DHCPv6 messages on UDP port 547 error = socketBind(context->serverSocket, &IP_ADDR_ANY, DHCPV6_SERVER_PORT); //Unable to bind the socket to the desired port? if(error) break; //Only accept datagrams with source port number 547 error = socketConnect(context->serverSocket, &IP_ADDR_ANY, DHCPV6_SERVER_PORT); //Any error to report? if(error) break; //If the relay agent relays messages to the All_DHCP_Servers address //or other multicast addresses, it sets the Hop Limit field to 32 //Loop through the client-facing interfaces for(i = 0; i < context->clientInterfaceCount; i++) { //Open a UDP socket to handle the current interface context->clientSocket[i] = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); //Failed to open socket? if(!context->clientSocket[i]) { //Report an error error = ERROR_OPEN_FAILED; //Stop processing break; } //Explicitly associate the socket with the relevant interface error = socketBindToInterface(context->clientSocket[i], context->clientInterface[i]); //Unable to bind the socket to the desired interface? if(error) break; //Relay agents listen for DHCPv6 messages on UDP port 547 error = socketBind(context->clientSocket[i], &IP_ADDR_ANY, DHCPV6_SERVER_PORT); //Unable to bind the socket to the desired port? if(error) break; //Only accept datagrams with source port number 546 error = socketConnect(context->clientSocket[i], &IP_ADDR_ANY, DHCPV6_CLIENT_PORT); //Any error to report? if(error) break; } //Propagate exception if necessary... if(error) break; //Create event objects context->event = osEventCreate(FALSE); context->ackEvent = osEventCreate(FALSE); //Out of resources? if(context->event == OS_INVALID_HANDLE || context->ackEvent == OS_INVALID_HANDLE) { //Report an error error = ERROR_OUT_OF_RESOURCES; //Stop processing break; } //The DHCPv6 relay agent is now running context->running = TRUE; //Start the DHCPv6 relay agent service task = osTaskCreate("DHCPv6 Relay", dhcpv6RelayTask, context, DHCPV6_RELAY_STACK_SIZE, DHCPV6_RELAY_PRIORITY); //Unable to create the task? if(task == OS_INVALID_HANDLE) error = ERROR_OUT_OF_RESOURCES; //End of exception handling block } while(0); //Did we encounter an error? if(error) { //Close the socket associated with the network-facing interface socketClose(context->serverSocket); //Close the socket associated with each client-facing interface for(i = 0; i < context->clientInterfaceCount; i++) socketClose(context->clientSocket[i]); //Leave the All_DHCP_Relay_Agents_and_Servers multicast group //for each client-facing interface dhcpv6RelayLeaveMulticastGroup(context); //Close event objects osEventClose(context->event); osEventClose(context->ackEvent); } //Return status code return error; }
error_t icecastClientStart(IcecastClientContext *context, const IcecastClientSettings *settings) { error_t error; OsTask *task; //Debug message TRACE_INFO("Starting Icecast client...\r\n"); //Ensure the parameters are valid if(!context || !settings) return ERROR_INVALID_PARAMETER; //Clear the Icecast client context memset(context, 0, sizeof(IcecastClientContext)); //Save user settings context->settings = *settings; //Get the size of the circular buffer context->bufferSize = settings->bufferSize; //Start of exception handling block do { //Allocate a memory block to hold the circular buffer context->streamBuffer = osMemAlloc(context->bufferSize); //Failed to allocate memory? if(!context->streamBuffer) { //Report an error to the calling function error = ERROR_OUT_OF_MEMORY; break; } //Create mutex object to protect critical sections context->mutex = osMutexCreate(FALSE); //Failed to create mutex object? if(context->mutex == OS_INVALID_HANDLE) { //Report an error to the calling function error = ERROR_OUT_OF_RESOURCES; break; } //Create events to get notified when the buffer is writable/readable context->writeEvent = osEventCreate(FALSE, TRUE); context->readEvent = osEventCreate(FALSE, FALSE); //Failed to create event object? if(context->writeEvent == OS_INVALID_HANDLE || context->readEvent == OS_INVALID_HANDLE) { //Report an error to the calling function error = ERROR_OUT_OF_RESOURCES; break; } //Create the Icecast client task task = osTaskCreate("Icecast client", icecastClientTask, context, ICECAST_CLIENT_STACK_SIZE, ICECAST_CLIENT_PRIORITY); //Unable to create the task? if(task == OS_INVALID_HANDLE) { //Report an error to the calling function error = ERROR_OUT_OF_RESOURCES; break; } //Successful initialization error = NO_ERROR; //End of exception handling block } while(0); //Check whether an error occurred if(error) { //Clean up side effects... osMemFree(context->streamBuffer); osMutexClose(context->mutex); osEventClose(context->writeEvent); osEventClose(context->readEvent); } //Return status code return error; }