/*************************************************************************/ #ifdef PLUS VOID NU_EventsDispatcher(UNSIGNED argc, VOID *argv) #else /* !PLUS */ VOID NU_EventsDispatcher(VOID) #endif /* !PLUS */ { struct uport *uprt; struct port *prt; struct sock_struct *sock_ptr = NU_NULL; /* Socket pointer. */ #ifdef PLUS STATUS status; UNSIGNED waittime; #else /* !PLUS */ int16 status, waittime; #endif /* !PLUS */ int16 tmoflag; UNSIGNED event = 0, dat = 0; tqe_t *duptqe, *tqe_wait; /* Timer queue entry */ #ifdef NU_PPP DV_DEVICE_ENTRY *dev_ptr; #endif /******************************************************************* Receive_Message points to a single occurence in the event queue. The index 3 signals that the structure is 3 words (or 6 bytes) long and is formatted as follows: struct { 8 bits: the msg_class 8 bits: the event 16 bits: pointer to the next event on the queue 16 bits: the data field } *******************************************************************/ #ifdef PLUS UNSIGNED Receive_Message[3] = {0, 0, 0}; UNSIGNED actual_size; #else /* !PLUS */ unsigned int Receive_Message[3]; #endif /* !PLUS */ tqe_wait = (tqe_t *)0; #ifdef PLUS /* Remove compilation warnings for unused parameters. */ status = (STATUS) argc + (STATUS) argv; #endif while (1) { /* Retrieve a message from the event queue. Note that if the source queue is empty this task suspends until something becomes available. */ #ifdef PLUS NU_Obtain_Semaphore(&TCP_Resource, NU_SUSPEND); #else /* !PLUS */ NU_Request_Resource(TCP_Resource, NU_WAIT_FOREVER); #endif /* !PLUS */ /* If someone is waiting on the timer list, then we need to calculate the next hit time for that timer. */ if (!tqe_wait) tqe_wait = tcp_timerlist.flink; if (tqe_wait) { #ifdef PLUS if (tqe_wait->duetime > NU_Retrieve_Clock()) waittime = ((UNSIGNED) tqe_wait->duetime - NU_Retrieve_Clock()); else waittime = NU_NO_SUSPEND; #else /* !PLUS */ waittime = (tqe_wait->duetime - NU_Read_Time()); if (waittime <= 0) waittime = (-1); #endif /* !PLUS */ } else { tqe_wait = (tqe_t *)0; #ifdef PLUS waittime = NU_SUSPEND; #else /* !PLUS */ waittime = NU_WAIT_FOREVER; #endif /* !PLUS */ } #ifdef PLUS /* If waittime is not NU_SUSPEND then there is a timeout value. */ if (waittime != NU_NO_SUSPEND) { NU_Release_Semaphore(&TCP_Resource); #else /* !PLUS */ if (waittime >= 0) { NU_Release_Resource(TCP_Resource); #endif /* !PLUS */ #ifdef PLUS status = NU_Receive_From_Queue(&eQueue, &Receive_Message[0], (UNSIGNED)3, &actual_size, waittime); NU_Obtain_Semaphore(&TCP_Resource, NU_SUSPEND); #else /* !PLUS */ status = NU_Retrieve_Item(eQueue, Receive_Message, waittime); NU_Request_Resource(TCP_Resource, NU_WAIT_FOREVER); #endif /* !PLUS */ } else #ifdef PLUS status = NU_TIMEOUT; #else /* !PLUS */ status = NU_QUEUE_TIMEOUT; #endif /* !PLUS */ #ifndef INTERRUPT netsleep(0); #endif /* !INTERRUPT */ /* Determine if the message was received successfully. */ #ifdef PLUS if (status == NU_TIMEOUT) #else /* !PLUS */ if (status == NU_QUEUE_TIMEOUT) #endif /* !PLUS */ { if (tqe_wait == tcp_timerlist.flink) { /* Take off the head of the list. */ dll_dequeue((tqe_t *) &tcp_timerlist); /* Place any duplicate entries on to the timer list. */ duptqe = (tqe_t *)dll_dequeue(&tqe_wait->duplist); while (duptqe) { tqpost((tqe_t *) &tcp_timerlist, duptqe); duptqe = (tqe_t *)dll_dequeue(&tqe_wait->duplist); } /* Place the dequeued entry on the free list. */ dll_enqueue(&tcptimer_freelist, tqe_wait); tmoflag = 1; /* Take care of event TCPRETRANS here...other events are handled by the CASE statement below... */ if (tqe_wait->tqe_event == TCPRETRANS) { /* Get a pointer to the porlist entry. */ prt = portlist[tqe_wait->tqe_data]; /* If there is still data to be transmitted and we still have a connection, update the retransmission timeout value. */ if ((prt->out.num_packets > 0) || (prt->state > SEST)) { /* If a retransmission timeout occurs, exponential * back-off. This number returns toward the correct * value by the RTT measurement code in ackcheck. */ if (prt->rto < MAXRTO) prt->rto <<= 1; /* double it */ } tcp_retransmit (prt, tqe_wait->tqe_ext_data); tqe_wait = (tqe_t *)0; #ifdef PLUS NU_Release_Semaphore(&TCP_Resource); #else /* !PLUS */ NU_Release_Resource(TCP_Resource); #endif /* !PLUS */ continue; } else { event = tqe_wait->tqe_event; dat = tqe_wait->tqe_data; status = NU_SUCCESS; } } else { tqe_wait = (tqe_t *)0; #ifdef PLUS NU_Release_Semaphore(&TCP_Resource); #else /* !PLUS */ NU_Release_Resource(TCP_Resource); #endif /* !PLUS */ continue; } } else { tmoflag = 0; tqe_wait = (tqe_t *)NU_NULL; } /* Determine if the message was received successfully. */ if (status == NU_SUCCESS) { if (!tmoflag) { event = (int16)Receive_Message[0]; dat = (uint16)Receive_Message[2]; } /* switch on the msg_class/event combination */ switch (event) { default: break; case CONNULL: break; /*********** CONNECTION CLASS **********************/ case CONFAIL: /* connection attempt failed */ case CONOPEN: /* successful connect attempt */ /* Make sure the socket is not NULL, this is possible if a TCP connection is made and immediately RESET by the foreign host. */ if ((sock_ptr = socket_list[dat]) != NU_NULL) { /* return control to the waiting task */ #ifdef PLUS if (sock_ptr->s_TXTask != NU_NULL) NU_Resume_Task(sock_ptr->s_TXTask); #else /* !PLUS */ if (sock_ptr->s_TXTask != -1) NU_Start(sock_ptr->s_TXTask); #endif /* !PLUS */ } break; case TCPACK: /* An ack needs to be sent. */ /* Get a pointer to the port. */ prt = portlist[dat]; /* Clear the ACK timer flag in the port. */ prt->portFlags &= (~ACK_TIMER_SET); /* Send the ack. */ tcp_sendack (prt); break; case CONTX: /* get a pointer into the port list table at the entry pointed to by dat in the event queue */ prt = portlist[dat]; if ( (prt->xmitFlag == NU_SET) && (prt->out.nextPacket != NU_NULL) ) { prt->tcpout.flags |= TPUSH; tcp_xmit(prt, prt->out.nextPacket); prt->out.nextPacket = (NET_BUFFER *)prt->out.nextPacket->next; prt->xmitFlag = NU_CLEAR; } break; case WINPROBE: /* Get a pointer to the socket. */ if ((sock_ptr = socket_list[dat]) != NU_NULL) { /* restart the waiting task */ #ifdef PLUS if (sock_ptr->s_TXTask != NU_NULL) NU_Resume_Task(sock_ptr->s_TXTask); #else if (sock_ptr->s_TXTask != -1) NU_Start(sock_ptr->s_TXTask); #endif } break; case SELECT: NU_Resume_Task((NU_TASK *)dat); break; case ARPRESOLVE: case RARP_REQUEST: ARP_Event((uint16)dat); break; case CONRX: NET_Demux(); break; /********************** USER CLASS *************************/ case UDPDATA: /* get a pointer into the port list table at the entry pointed to by dat in the event queue */ uprt = uportlist[dat]; if (uprt != NU_NULL) { /* return control to the waiting task */ #ifdef PLUS if (uprt->RXTask != NU_NULL) NU_Resume_Task(uprt->RXTask); #else /* !PLUS */ if (uprt->RXTask != -1) NU_Start(uprt->RXTask); #endif /* !PLUS */ } break; #if INCLUDE_IP_MULTICASTING case EV_IGMP_REPORT : /* Send an IGMP multicast group membership report. */ IGMP_REPORT_EVENT(dat); break; #endif /* INCLUDE_IP_MULTICASTING */ case EV_IP_REASSEMBLY : /* Clear the fragment list. The whole datagram has not yet been received. */ IP_Reassembly_Event((IP_QUEUE_ELEMENT *)dat); break; /*********************** PPP CLASS ************************/ #ifdef NU_PPP case LCP_RESEND: /* Remove the PPP header that was added the first time this packet was sent. */ lcp_state.negotiation_pkt->data_ptr += sizeof (PPP_HEADER); lcp_state.negotiation_pkt->data_len -= sizeof (PPP_HEADER); lcp_state.negotiation_pkt->mem_total_data_len -= sizeof (PPP_HEADER); /* Send the packet again. */ PPP_TX_Packet (lcp_state.negotiation_pkt->mem_buf_device, lcp_state.negotiation_pkt); break; case LCP_SEND_CONFIG: /* Send a new configure request packet */ LCP_Send_Config_Req (); break; case HANGUP_MDM: MDM_Hangup(); break; case LCP_ECHO_REQ: /* Send a echo request packet */ LCP_Send_Echo_Req ((DV_DEVICE_ENTRY *) dat); break; case NCP_RESEND: /* Remove the PPP header that was added the first time this packet was sent. */ ncp_state.negotiation_pkt->data_ptr += sizeof (PPP_HEADER); ncp_state.negotiation_pkt->data_len -= sizeof (PPP_HEADER); ncp_state.negotiation_pkt->mem_total_data_len -= sizeof (PPP_HEADER); /* Send the packet again. */ PPP_TX_Packet (ncp_state.negotiation_pkt->mem_buf_device, ncp_state.negotiation_pkt); break; case NCP_SEND_CONFIG: /* Get a pointer to the device structure for this device so that the IP address of this device can be found. */ dev_ptr = (DV_DEVICE_ENTRY *)dat; /* Send it to the host */ NCP_IP_Send_Config_Req (dev_ptr->dev_addr.dev_ip_addr); break; case LCP_CLOSE_LINK: /* Get a pointer to the device structure for this device so that the IP address of this device can be found. */ dev_ptr = (DV_DEVICE_ENTRY *)dat; /* Close the network down. */ PPP_Kill_All_Open_Sockets(dev_ptr); /* Detach the IP address from this device. */ DEV_Detach_IP_From_Device (dev_ptr->dev_net_if_name); /* Send a terminate request */ LCP_Send_Terminate_Req(); /* Start the timer */ NU_Reset_Timer (&LCP_Restart_Timer, LCP_Timer_Expire, LCP_TIMEOUT_VALUE, LCP_TIMEOUT_VALUE, NU_ENABLE_TIMER); break; case PAP_SEND_AUTH: /* Retransmit the authentication pkt */ PAP_Send_Authentication(); break; case CHAP_RESEND: /* Remove the PPP header that was added the first time this packet was sent. */ lcp_state.negotiation_pkt->data_ptr += sizeof (PPP_HEADER); lcp_state.negotiation_pkt->data_len -= sizeof (PPP_HEADER); lcp_state.negotiation_pkt->mem_total_data_len -= sizeof (PPP_HEADER); /* Resend the last sent chap packet */ PPP_TX_Packet (lcp_state.negotiation_pkt->mem_buf_device, lcp_state.negotiation_pkt); break; case CHAP_CHALL: /* Send the CHAP challenge */ CHAP_Send_Challenge(); break; #endif /* NU_PPP */ } /* end switch on msg_class/event combination */ } /* end if status is NU_SUCCESS */ /* added 11/3/92 - during ATI mods */ #ifdef PLUS NU_Release_Semaphore(&TCP_Resource); #else /* !PLUS */ NU_Release_Resource(TCP_Resource); #endif /* !PLUS */ } /* end while */ } /* end NU_EventDispatcher */
int main ( void ) { char* line; time_t* led_flash_timer; time_t* reboot_timer; socket_t* socket = socket0_g; int reboot_stage = 0; /* Turn off all LEDs as a starting point */ led_clear(); /* this must be first, because all the other init functions call malloc */ init_malloc(); /* Initialize current time and some timers */ init_current_time(); led_flash_timer = init_timer(); set_timer(led_flash_timer, 500); reboot_timer = init_timer(); /* receive packet buffer */ rx_packet_g = malloc(sizeof(packet_t)); /* socket init */ socket0_g = init_socket(0); socket1_g = init_socket(1); /* open ethernet port and wait for connection requests keep trying forever */ while (!open_link()); /* infinite loop. Everything is timer, interrupt and queue driven from here on down */ while (1) { /* Flash a heartbeat LED */ if (timer_expired(led_flash_timer)) { led_flip(0); set_timer(led_flash_timer, 500); } /* Check for newly downloaded tftp file. Add to all tx buffers */ /* Has a file been uploaded via tftp ? */ if (udp_file_g != NULL) { /* Notify telnet clients that file has been received */ if (udp_file_g->ready) { udp_file_g->ready = 0; telnet_broadcast("Received file %s, %d bytes, linux %d\r\n", udp_file_g->filename, udp_file_g->total_bytes, udp_file_g->linux_boot); if (process_file(socket0_g) == 0) /* Disconnect in 1 second */ set_timer(reboot_timer, 1000); else telnet_broadcast("Not an elf file\r\n"); } } /* reboot timer expired */ if (timer_expired(reboot_timer)) { /* First stage of reboot sequence is to nicely disconnect */ if (reboot_stage == 0) { set_timer(reboot_timer, 1000); reboot_stage = 1; socket0_g->tcp_disconnect = 1; socket1_g->tcp_disconnect = 1; } else { /* Second stage of reboot sequence is to turn off ethmac and then jump to restart vector */ close_link(); reboot(); } } /* Poll both sockets in turn for activity */ if (socket == socket0_g) socket = socket1_g; else socket = socket0_g; /* Check if any tcp packets need to be re-transmitted */ tcp_retransmit(socket); /* Handle exit command */ if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) { tcp_disconnect(socket); } /* Reset connection */ if (socket->tcp_reset) { socket->tcp_connection_state = TCP_CLOSED; socket->telnet_connection_state = TELNET_CLOSED; socket->telnet_options_sent = 0; tcp_reply(socket, NULL, 0); socket->tcp_reset = 0; } /* Send telnet options */ if (socket->tcp_connection_state == TCP_OPEN && !socket->telnet_options_sent){ telnet_options(socket); socket->telnet_options_sent = 1; } /* telnet connection open Communicate with client */ else if (socket->telnet_connection_state == TELNET_OPEN) { /* Send telnet greeting */ if (!socket->telnet_sent_opening_message){ put_line (socket->telnet_txbuf, "Amber Processor Boot Loader\r\n> "); socket->telnet_sent_opening_message = 1; } /* Parse telnet rx buffer */ if (get_line(socket->telnet_rxbuf, &line)) parse_command (socket, line); /* Transmit text from telnet tx buffer */ telnet_tx(socket, socket->telnet_txbuf); } } }