diff options
Diffstat (limited to 'cfe/cfe/net/net_nmrp.c')
-rwxr-xr-x | cfe/cfe/net/net_nmrp.c | 656 |
1 files changed, 656 insertions, 0 deletions
diff --git a/cfe/cfe/net/net_nmrp.c b/cfe/cfe/net/net_nmrp.c new file mode 100755 index 0000000..696d04d --- /dev/null +++ b/cfe/cfe/net/net_nmrp.c @@ -0,0 +1,656 @@ +#include "bsp_config.h" + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe_timer.h" + +#include "net_ip.h" +#include "net_ip_internal.h" +#include "net_api.h" + +#include "env_subr.h" + +#if CFG_TCP +#include "net_tcp.h" +#endif + +#include "ui_command.h" + +typedef struct net_ctx_s { + /* Global info */ + int64_t timer; + + /* device name */ + char *devname; + + /* Run-time info for IP interface */ + ip_info_t *ipinfo; + + /* Info for Ethernet interface */ + ether_info_t *ethinfo; + + /* Info specific to UDP */ + udp_info_t *udpinfo; + + /* Info specific to ICMP */ + icmp_info_t *icmpinfo; + +#if CFG_TCP + /* Info specific to TCP */ + tcp_info_t *tcpinfo; +#endif +} net_ctx_t; + + +#pragma pack(1) + +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; + +/* NMRP timeouts */ +enum _nmrp_timeouts_ { + NMRP_TIMEOUT_REQ = 1/2, /* 0.5 sec */ + NMRP_TIMEOUT_LISTEN = 3, /* 3 sec */ + NMRP_TIMEOUT_ACTIVE = 60000, /* 1 minute */ + NMRP_TIMEOUT_CLOSE = 6000, /* 6 sec */ + NMRP_TIMEOUT_ADVERTISE = 500 /* 0.5 sec */ +}; + +enum _nmrp_errors_ { + NMRP_ERR_NONE = 0, + NMRP_ERR_MSG_INVALID_LEN, + NMRP_ERR_MSG_TOO_LONG, + NMRP_ERR_MSG_TOO_MANY_OPT, + NMRP_ERR_MSG_UNKNOWN_OPT, + NMRP_ERR_MSG_INVALID_OPT, + NMRP_ERR_NO_BUF, + NMRP_ERR_GENERAL +}; + +/* NMRP codes */ +enum _nmrp_codes_ { + NMRP_CODE_ADVERTISE = 0x01, + NMRP_CODE_CONF_REQ = 0x02, + NMRP_CODE_CONF_ACK = 0x03, + NMRP_CODE_CLOSE_REQ = 0x04, + NMRP_CODE_CLOSE_ACK = 0x05, + NMRP_CODE_KEEP_ALIVE_REQ = 0x06, + NMRP_CODE_KEEP_ALIVE_ACK = 0x07, + NMRP_CODE_TFTP_UL_REQ = 0x10 +}; + +/* NMRP option types */ +enum _nmrp_option_types_ { + NMRP_OPT_MAGIC_NO = 0x0001, + NMRP_OPT_DEV_IP = 0x0002, + NMRP_OPT_FW_UP = 0x0101 +}; + +typedef enum { + NMRPC_L2_NO_ERROR = 0, + NMRPC_L2_TX_PKT_TOO_LONG, + NMRPC_L2_TX_ETHER_PREPEND_FAIL, + NMRPC_L2_TX_ERROR, + NMRPC_L2_GEN_ERR +} NMRPC_L2_RET_CODE; + +/* NMRP REQ max retries */ +enum _nmrp_req_max_retries_ { + NMRP_MAX_RETRY_CONF = 5, + NMRP_MAX_RETRY_CLOSE = 9999, + NMRP_MAX_RETRY_TFTP_UL = 4 +}; + + +enum _nmrp_state_ { + NMRP_STATE_LISTEN = 0, + NMRP_STATE_CONFIGURE, + NMRP_STATE_TRANSFER, + NMRP_STATE_CLOSE +}; + +#define NMRP_MAX_OPT_PER_MSG (6) +#define ETHER_NMRP (0x0912) + +#define NMRP_HDR_LEN (sizeof(NMRP_MSG) - sizeof(NMRP_OPT)) +#define NMRP_MIN_OPT_LEN (sizeof(NMRP_OPT) - 1) + +#define NMRP_MAGIC_NO "\x4E\x54\x47\x52" +#define NMRP_MAGIC_NO_LEN (sizeof(NMRP_MAGIC_NO) - 1) + +typedef struct { + uint8_t destMAC[6]; + uint8_t srcMAC[6]; + uint16_t etherType; +} ETHER_HDR; + +typedef struct { + uint16_t type; + uint16_t len; + uint8_t value; +} NMRP_OPT; + +typedef struct { + uint16_t reserved; + uint8_t code; + uint8_t id; + uint16_t length; + + NMRP_OPT opt; +} NMRP_MSG; + +typedef struct { + ETHER_HDR etherHdr; + NMRP_MSG nmrpMsg; +} ETHER_NMRP_PKT; + +typedef struct { + uint16_t type; + uint16_t len; + + union { + uint8_t byteVal; + uint16_t wordVal; + uint32_t dwordVal; + const uint8_t *streamVal; + } value; +} NMRP_PARSED_OPT; + +typedef struct { + uint8_t code; + uint8_t id; + uint16_t length; + + int numOptions; + NMRP_PARSED_OPT options[NMRP_MAX_OPT_PER_MSG]; +} NMRP_PARSED_MSG; + +typedef struct { + int reqCode; + const char reqName[32], respName[32]; + + int (* RespParser) (const void *pkt, int pktLen, const BYTE *serverMac, void *userData); +} NMRP_REQ_CUSTOM; + +typedef struct { + + BYTE peerMac[6]; + BYTE myMac[6]; + + DWORD peerIp; + DWORD myIp; + WORD ipId; + + WORD peerPort; + WORD myPort; +} NET_INFO; + +#pragma pack() + +#define MIN_ETHER_NMRP_LEN (sizeof(ETHER_HDR) + NMRP_HDR_LEN) + +#if 0 +#define HTONCS(constWord) ((((constWord) & 0xff00) >> 8) | (((constWord) & 0xff) << 8)) +#define NTOHCS(constWord) HTONCS(constWord) +#define HTONCL(constDword) ((((constDword) & 0xff000000) >> 24) | (((constDword) & 0xff0000) >> 8) | (((constDword) & 0xff00) << 8) | (((constDword) & 0xff) << 24)) +#define NTOHCL(constDword) HTONCL(constDword) +#endif + +#define HTONCS(constWord) constWord +#define NTOHCS(constWord) constWord +#define HTONCL(constDword) constDword +#define NTOHCL(constDword) constDword +/* +#define IS_NMRP_PKT(etherNmrpPkt, pktLen, parsedNmrpMsg, sourceMAC) \ + ((pktLen) > MIN_ETHER_NMRP_LEN && (etherNmrpPkt)->etherHdr.etherType == HTONCS(ETHER_NMRP) && \ + ((sourceMAC) == NULL || memcmp((sourceMAC), (etherNmrpPkt)->etherHdr.srcMAC, 6) == 0) && \ + NMRP_MsgParsing(&(etherNmrpPkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), (parsedNmrpMsg)) == NMRP_ERR_NONE) +*/ + +#define IS_NMRP_PKT(etherNmrpPkt, pktLen, parsedNmrpMsg, sourceMAC) \ + ((pktLen) > MIN_ETHER_NMRP_LEN && (etherNmrpPkt)->etherHdr.etherType == HTONCS(ETHER_NMRP) && \ + ((sourceMAC) == NULL || memcmp((sourceMAC), (etherNmrpPkt)->etherHdr.srcMAC, 6) == 0)) + +static int nmrp_rx_callback(ebuf_t *buf,void *ref); +int NMRP_MsgParsing(const NMRP_MSG *pkt, int pktLen, NMRP_PARSED_MSG *msg); +NMRP_PARSED_OPT *NMRP_MsgGetOpt(NMRP_PARSED_MSG *msg, uint16_t optType); +//int NMRPRequest( const BYTE *serverMac, const BYTE *clientMac, NMRP_REQ_CUSTOM *custom, void *userData); +static int NMRPConfiguring( const BYTE *serverMac, const BYTE *clientMac, DWORD *ipAddr, DWORD *ipSubnetMask, int *fwUpgrade); +static int NMRPConfAckParser(const void *pkt, int pktLen, const BYTE *serverMac, void *userData); +//int NMRPTFTPWaiting(const NET_INFO *netInfo, DWORD *peerIp, WORD *peerPort, WORD *ipId); +int NMRPTFTPWaiting(void); +int NMRPKeepAlive(void); +static int NMRPClosing(void); +static int NMRPSend(NMRP_REQ_CUSTOM *custom); + +int nmrp_server_detected; +int g_nmrp_config_acked; +int g_nmrp_close_acked; +//int g_Listening; +int g_NMRP_State; +extern net_ctx_t *netctx; + +NET_INFO g_NetInfo; +//ebuf_t *g_nmrp_txbuf = NULL; +int g_portal_number; +NMRP_PARSED_MSG g_nmrpMsg; +int g_tftp_upgrade_success; +int g_nmrp_keepalive;//jenny add for fixed NMRP server timeout issue +unsigned char g_received_packet[1600]; + +int gpio_control(int gpio, int value); +extern int32_t _getticks(void); /* return value of CP0 COUNT */ +static unsigned long seed = 1; + +void srand(unsigned long local_seed); +unsigned long rand(void); +int _start_nmrp(void); + +void srand(unsigned long local_seed) +{ + seed = local_seed; +} + +unsigned long rand(void) +{ + + long x, hi, lo, t; + + x = seed; + hi = x / 127773; + lo = x % 127773; + t = 16807 * lo - 2836 * hi; + if (t <= 0) t += 0x7fffffff; + seed = t; + return t; +} + +int _start_nmrp (void) +{ + uint8_t nmrpproto[2]; + + int ret = 0; + int ui_cmd_status; + int fwUpgrade; + int64_t timer; + DWORD ipSubnetMask; + char buf[512]; + unsigned char *pIP, *pMask; + + srand( (unsigned long)_getticks()); + + //net_init("eth0"); + nmrpproto[0] = (PROTOSPACE_NMRP >> 8) & 0xFF; + nmrpproto[1] = (PROTOSPACE_NMRP & 0xFF); + g_tftp_upgrade_success = 0; + g_nmrp_keepalive = 0;//jenny add for timeout + + g_portal_number = eth_open(netctx->ethinfo, ETH_PTYPE_DIX, (char*)nmrpproto, nmrp_rx_callback, NULL); + if(g_portal_number < 0) + { + ret = -1; + goto _clean_and_exit; + } + + eth_gethwaddr(netctx->ethinfo, g_NetInfo.myMac); +//_retry: + g_NMRP_State = NMRP_STATE_LISTEN; + nmrp_server_detected = 0; + TIMER_SET(timer, NMRP_TIMEOUT_LISTEN*CFE_HZ); + while (!TIMER_EXPIRED(timer)) + { + POLL(); + if(nmrp_server_detected) + { + xprintf ("find server.\n"); + break; + } + } + + if(!nmrp_server_detected) + { + ret = -1; + goto _clean_and_exit; + } + + g_nmrp_config_acked = 0; + + if (NMRPConfiguring( g_NetInfo.peerMac, g_NetInfo.myMac, &g_NetInfo.myIp, &ipSubnetMask, &fwUpgrade) == -1) + { + ret = -1; + goto _clean_and_exit; + } + + pIP = (unsigned char *)&g_NetInfo.myIp; + pMask = (unsigned char *)&ipSubnetMask; + + sprintf(buf, "ifconfig eth0 -addr=%u.%u.%u.%u -mask=%u.%u.%u.%u", *(pIP), *(pIP+1), *(pIP+2), *(pIP+3), + *(pMask), *(pMask+1), *(pMask+2), *(pMask+3) ); + ui_docommand(buf); + + +_retry_tftp: + + NMRPTFTPWaiting(); + //eth_close(netctx->ethinfo, g_portal_number); + //g_portal_number = 0; + //net_init("eth0"); + ui_cmd_status = ui_docommand("tftpd nmrp"); + + + sprintf(buf, "ifconfig eth0 -addr=%u.%u.%u.%u -mask=%u.%u.%u.%u", *(pIP), *(pIP+1), *(pIP+2), *(pIP+3), + *(pMask), *(pMask+1), *(pMask+2), *(pMask+3) ); + + ui_docommand(buf); + + //net_init("eth0"); + g_portal_number = eth_open(netctx->ethinfo, ETH_PTYPE_DIX, (char*)nmrpproto, nmrp_rx_callback, NULL); + + if(ui_cmd_status != 0) + { + goto _retry_tftp; + } + + g_nmrp_close_acked = 0; + /* Foxconn modified start, zacker,04/07/2008 */ + /* ui_docommand("nvram erase"); */ + // nvram_unset("restore_defaults"); + // nvram_commit(); + /* Foxconn modified end, zacker,04/07/2008 */ + + NMRPClosing(); + g_tftp_upgrade_success = 1; + // gpio_control(7, 1); //turn off power led + +_clean_and_exit: + + if(g_portal_number > 0) + eth_close(netctx->ethinfo, g_portal_number); + + return ret; +} + +extern void setPowerOnLedOn(void); +static int nmrp_rx_callback(ebuf_t *buf,void *ref) +{ + int pktLen = 0; + NMRP_PARSED_MSG nmrpMsg; + const ETHER_NMRP_PKT *pkt; + unsigned char *p; + + pkt = (const ETHER_NMRP_PKT *)buf->eb_data; + pktLen = buf->eb_length + sizeof(ETHER_HDR) - 4; + + p=(unsigned char *)pkt; + + if(g_NMRP_State == NMRP_STATE_LISTEN) + { + if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_ADVERTISE ) ) + { + if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE) + { + if(NMRP_MsgGetOpt(&nmrpMsg, NMRP_OPT_MAGIC_NO) != NULL) + { + memcpy(g_NetInfo.peerMac, buf->eb_data+6, 6); + g_NMRP_State = NMRP_STATE_CONFIGURE; + nmrp_server_detected = 1; + setPowerOnLedOn(); /* Foxconn added for U12H154, turn on TEST LED */ + } + } + } + } + else if(g_NMRP_State == NMRP_STATE_CONFIGURE) + { + if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_CONF_ACK ) ) + { + memcpy(g_received_packet, pkt, pktLen); + pkt = (const ETHER_NMRP_PKT *)g_received_packet; + if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE) + { + if(NMRPConfAckParser(pkt, pktLen, g_NetInfo.peerMac, &nmrpMsg)) + { + g_nmrpMsg = nmrpMsg; + g_nmrp_config_acked = 1; + g_NMRP_State = NMRP_STATE_TRANSFER; + } + } + } + } + else if(g_NMRP_State == NMRP_STATE_TRANSFER) + { + if (IS_NMRP_PKT(pkt, pktLen, &nmrpMsg, NULL) && (*(p+16) == NMRP_CODE_CLOSE_ACK ) ) + { + if (NMRP_MsgParsing(&(pkt)->nmrpMsg, (pktLen) - sizeof(ETHER_HDR), &nmrpMsg) == NMRP_ERR_NONE) + { + g_NMRP_State =NMRP_STATE_CLOSE; + g_nmrp_close_acked = 1; + } + } + } + + return ETH_DROP; +} + +static int NMRP_OptValParsing(NMRP_PARSED_OPT *optParsed, const uint8_t *value) +{ + int retVal = NMRP_ERR_NONE; + + switch (optParsed->type) { + case NMRP_OPT_MAGIC_NO: /* We require the lenght MUST be correct for the MAGIC-NO option */ + if (optParsed->len != (NMRP_MIN_OPT_LEN + NMRP_MAGIC_NO_LEN) || memcmp(value, NMRP_MAGIC_NO, NMRP_MAGIC_NO_LEN)) + { + retVal = NMRP_ERR_MSG_INVALID_OPT; + } + else + { + optParsed->value.streamVal = value; + } + break; + + case NMRP_OPT_DEV_IP: /* save the value of IP in the byte stream format, the actual IP is streamVal[0].streamVal[1].streamVal[2].streamVal[3]. */ + //if ( optParsed->len != (NMRP_MIN_OPT_LEN + 8) || !IsIPAddrValid(ntohl(*(DWORD *) value), ntohl(*(DWORD *) (value + 4))) ) + if ( optParsed->len != (NMRP_MIN_OPT_LEN + 8) ) + retVal = NMRP_ERR_MSG_INVALID_OPT; + else + optParsed->value.streamVal = value; + break; + + case NMRP_OPT_FW_UP: /* don't check the length of FW-UP option for future compatibility */ + break; + + default: + retVal = NMRP_ERR_MSG_UNKNOWN_OPT; + break; + } + + return retVal; +} + +int NMRP_MsgParsing(const NMRP_MSG *pkt, int pktLen, NMRP_PARSED_MSG *msg) +{ + if (pktLen < NMRP_HDR_LEN) + return NMRP_ERR_MSG_INVALID_LEN; + + msg->code = pkt->code; + msg->id = pkt->id; + + if ((msg->length = NTOHCS(pkt->length)) <= pktLen && msg->length >= NMRP_HDR_LEN) { + int retVal; + uint16_t optLen; + NMRP_OPT *opt; + NMRP_PARSED_OPT *optParsed; + + opt = (NMRP_OPT *)(((uint8_t *) pkt) + NMRP_HDR_LEN); + optParsed = msg->options; + msg->numOptions = 0; + + /* use the length indicated in the NMRP header */ + for (pktLen = msg->length - NMRP_HDR_LEN; pktLen >= NMRP_MIN_OPT_LEN; ) + { + optParsed->type = NTOHCS(opt->type); + optParsed->len = optLen = NTOHCS(opt->len); + + if (optParsed->len > pktLen) + return NMRP_ERR_MSG_INVALID_OPT; + + if ((retVal = NMRP_OptValParsing(optParsed, &opt->value)) == NMRP_ERR_NONE) + { + optParsed++; + + if (++msg->numOptions >= NMRP_MAX_OPT_PER_MSG) + return NMRP_ERR_MSG_TOO_MANY_OPT; + } + else if (retVal != NMRP_ERR_MSG_UNKNOWN_OPT) + { + return NMRP_ERR_MSG_INVALID_OPT; + } + + pktLen -= optLen; + opt = (NMRP_OPT *)(((uint8_t *) opt) + optLen); + } + } /* end if the msg->length is larger than the received packet length */ + + return pktLen == 0 ? NMRP_ERR_NONE : NMRP_ERR_MSG_INVALID_LEN; +} + +NMRP_PARSED_OPT *NMRP_MsgGetOpt(NMRP_PARSED_MSG *msg, uint16_t optType) +{ + NMRP_PARSED_OPT *opt, *optEnd; + + optEnd = &msg->options[msg->numOptions]; + + for (opt = msg->options; opt != optEnd; opt++) + if (opt->type == optType) + break; + + return msg->numOptions == 0 ? NULL : (opt == optEnd ? NULL : opt); +} + +static int NMRPClosing(void) +{ + int ret, retries=0; + static NMRP_REQ_CUSTOM reqClose = { NMRP_CODE_CLOSE_REQ, "CLOSE-REQ", "CLOSE-ACK", NULL }; + + do { + ret = NMRPSend(&reqClose); + if( !ret) + { + cfe_sleep(CFE_HZ/2); + if(g_nmrp_close_acked) + { + break; + } + } + } while(++retries <= NMRP_MAX_RETRY_CLOSE); + + return 0; +} + +int NMRPTFTPWaiting(void) +{ + static NMRP_REQ_CUSTOM reqTftpUl = { NMRP_CODE_TFTP_UL_REQ, "TFTP-UL-REQ", "TFTP-WRQ", NULL }; + + return NMRPSend(&reqTftpUl); +} + +/* Foxconn modify start by Jenny Zhao, 08/07/2008, for fixed timeout issue*/ +int NMRPKeepAlive(void) +{ + static NMRP_REQ_CUSTOM reqkeepalive = { NMRP_CODE_KEEP_ALIVE_REQ, "KEEPALIVE_REQ", "KEEPALIVE-ACK", NULL }; + + return NMRPSend(&reqkeepalive); +} +/* Foxconn modify end by Jenny Zhao, 08/07/2008*/ + +static int NMRPConfAckParser(const void *pkt, int pktLen, const BYTE *serverMac, void *userData) +{ + NMRP_PARSED_MSG *nmrpMsg = (NMRP_PARSED_MSG *) userData; + + return NMRP_MsgGetOpt(nmrpMsg, NMRP_OPT_DEV_IP) != NULL; + /* + return IS_NMRP_PKT((const ETHER_NMRP_PKT *)pkt, pktLen, nmrpMsg, serverMac) && + nmrpMsg->code == NMRP_CODE_CONF_ACK && + NMRP_MsgGetOpt(nmrpMsg, NMRP_OPT_DEV_IP) != NULL; + */ +} + + +static int NMRPConfiguring( const BYTE *serverMac, + const BYTE *clientMac, + DWORD *ipAddr, DWORD *ipSubnetMask, + int *fwUpgrade) +{ + //int ret, retries=0; + int ret; + NMRP_PARSED_OPT *devIp; + static NMRP_REQ_CUSTOM reqConf = { NMRP_CODE_CONF_REQ, "CONF-REQ", "CONF-ACK", NMRPConfAckParser }; + + do { + + ret = NMRPSend(&reqConf); + if( !ret) + { + cfe_sleep(CFE_HZ/2); + if(g_nmrp_config_acked) + { + break; + } + } + + //}while(++retries <= NMRP_MAX_RETRY_CLOSE); + } while(1); + + if(g_nmrp_config_acked) + { + devIp = NMRP_MsgGetOpt(&g_nmrpMsg, NMRP_OPT_DEV_IP); + *ipAddr = (* (DWORD *) devIp->value.streamVal); + *ipSubnetMask = (* (DWORD *) (devIp->value.streamVal + 4)); + *fwUpgrade = NMRP_MsgGetOpt(&g_nmrpMsg, NMRP_OPT_FW_UP) != NULL; + return 0; + } + return -1; +} + +static int NMRPSend(NMRP_REQ_CUSTOM *custom) +{ + ebuf_t *txbuf; + NMRP_MSG *msg; + unsigned long random_backoff; + + txbuf = eth_alloc(netctx->ethinfo, g_portal_number); + if (!txbuf) + { + return -1; + } + msg = (NMRP_MSG *)(txbuf->eb_data + 14); + msg->reserved = 0; + msg->code = custom->reqCode; + msg->id = 0; + msg->length = HTONCS(NMRP_HDR_LEN); /* header only, no option */ + txbuf->eb_length = NMRP_HDR_LEN; + + random_backoff = rand(); + random_backoff = random_backoff % 30; + xprintf("%s sent...Waiting for %s...\n", custom->reqName, custom->respName); + cfe_sleep(random_backoff); + eth_send(txbuf, (uint8_t *)g_NetInfo.peerMac); + eth_free(txbuf); + + return 0; +} + |