📄 ethernet.c
字号:
}
for(i=0;protocols[i].pname;i++) {
if (icpy->ip_p == protocols[i].pnum) {
printf(" Protocol: %s\n",protocols[i].pname);
return(0);
}
}
printf(" <%02x>: unknown IP protocol\n", icpy->ip_p);
return (1);
}
/*
* printUdp(p)
*/
int
printUdp(struct Udphdr *p)
{
ushort dport, sport;
dport = ecs(p->uh_dport);
sport = ecs(p->uh_sport);
#if INCLUDE_DHCPBOOT
if ((dport == DhcpServerPort) || (dport == DhcpClientPort)) {
printDhcp(p);
return(0);
}
#endif
printf(" UDP: sport dport ulen sum\n");
printf(" %4d %4d %4d %4d\n",
sport, dport, ecs(p->uh_ulen),ecs(p->uh_sum));
return(0);
}
/*
* printIgmp(p)
*/
int
printIgmp(struct Igmphdr *p)
{
uchar buf[16];
printf(" IGMP: type mrt csum group\n");
printf(" x%02x x%02x x%04x %s\n",
p->type, p->mrt, p->csum, IpToString(p->group,buf));
return(0);
}
int
IpToBin(char *ascii,uchar *binary)
{
int i, digit;
char *acpy;
acpy = ascii;
for(i=0;i<4;i++) {
digit = (int)strtol(acpy,&acpy,10);
if (((i != 3) && (*acpy++ != '.')) ||
((i == 3) && (*acpy != 0)) ||
(digit < 0) || (digit > 255)) {
printf("Misformed IP addr: %s\n",ascii);
return(-1);
}
binary[i] = (uchar)digit;
}
return(0);
}
/* IpToString():
* Incoming ascii pointer is assumed to be pointing to at least 16
* characters of available space. Conversion from long to ascii is done
* and string is terminated with NULL. The ascii pointer is returned.
*/
char *
IpToString(ulong ipadd,char *ascii)
{
uchar *cp;
cp = (uchar *)&ipadd;
sprintf(ascii,"%d.%d.%d.%d",
(int)cp[0],(int)cp[1],(int)cp[2],(int)cp[3]);
return(ascii);
}
char *
EtherToString(uchar *etheradd,char *ascii)
{
sprintf(ascii,"%02x:%02x:%02x:%02x:%02x:%02x",(int)etheradd[0],
(int)etheradd[1],(int)etheradd[2],(int)etheradd[3],
(int)etheradd[4],(int)etheradd[5]);
return(ascii);
}
/* ipChksum():
* Compute the checksum of the incoming IP header. The size of
* the header is variable because of the possibility of there
* being options; hence, the size of the header is taken from
* the ip_vhl field instead of assuming sizeof(struct ip).
* The incoming pointer to an IP header is directly populated with
* the result.
*/
void
ipChksum(struct ip *ihdr)
{
register int i, stot;
register ushort *sp;
register long csum;
csum = 0;
ihdr->ip_sum = 0;
stot = (((ihdr->ip_vhl & 0x0f) << 2) / (int)sizeof(ushort));
sp = (ushort *) ihdr;
for (i=0;i<stot;i++,sp++) {
csum += *sp;
if (csum & 0x80000000)
csum = (csum & 0xffff) + (csum >> 16);
}
while(csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
ihdr->ip_sum = ~csum;
}
/* udpChksum():
* Compute the checksum of the UDP packet.
* The incoming pointer is to an ip header, the udp header after that ip
* header is directly populated with the result.
* Got part of this code out of Steven's TCP/IP Illustrated Volume 2.
*/
void
udpChksum(struct ip *ihdr)
{
register int i;
register ushort *datap;
register long sum;
int len;
struct Udphdr *uhdr;
struct UdpPseudohdr pseudohdr;
uhdr = (struct Udphdr *)(ihdr+1);
uhdr->uh_sum = 0;
/* Note that optionally, the checksum can be forced to zero here,
* so a return could replace the remaining code.
* That would be kinda dangerous, but it is an option according to
* the spec.
*/
/* Start with the checksum of the pseudo header:
* Note that we have to use memcpy because we don't know if the incoming
* stream is aligned properly.
*/
memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4);
memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4);
pseudohdr.zero = 0;
pseudohdr.proto = ihdr->ip_p;
pseudohdr.ulen = uhdr->uh_ulen;
/* Get checksum of pseudo header: */
sum = 0;
datap = (ushort *) &pseudohdr;
for (i=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++) {
sum += *datap++;
if (sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
}
len = ecs(uhdr->uh_ulen);
datap = (ushort *) uhdr;
/* If length is odd, pad with zero and add 1... */
if (len & 1) {
uchar *ucp;
ucp = (uchar *)uhdr;
ucp[len] = 0;
len++;
}
while(len) {
sum += *datap++;
if (sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
len -= 2;
}
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
uhdr->uh_sum = ~sum;
}
struct ether_header *
EtherCopy(struct ether_header *re)
{
struct ether_header *te;
te = (struct ether_header *) getXmitBuffer();
memcpy((char *)&(te->ether_shost),(char *)BinEnetAddr,6);
memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6);
te->ether_type = re->ether_type;
return(te);
}
ushort
ipId(void)
{
return(++UniqueIpId);
}
/* getTuneup():
* The DHCP, TFTP and ARP timeout & retry mechanism can be tuned based on
* the content of the shell variables DHCPRETRYTUNE, TFTPRETRYTUNE and
* ARPRETRYTUNE respectively.
* Return 0 if variable is not found, -1 if there is a detected error in
* the content of the shell variable; else 1 indicating that the three
* parameters have been loaded from the content of the shell variable.
*/
int
getTuneup(char *varname,int *rexmitdelay,int *giveupcount,int *rexmitdelaymax)
{
char *vp, *colon1, *colon2;
vp = getenv(varname);
if (!vp)
return(0);
colon1 = strchr(vp,':');
if (colon1) {
colon2 = strchr(colon1+1,':');
if (colon2) {
*rexmitdelay = (int)strtol(vp,0,0);
*giveupcount = (int)strtol(colon1+1,0,0);
*rexmitdelaymax = (int)strtol(colon2+1,0,0);
return(1);
}
}
printf("Syntax error in %s\n",varname);
return(-1);
}
/* RetransmitDelay():
* This function provides a common point for retransmission delay
* calculation. It is an implementation "similar" to the recommendation
* made in the RFC 2131 (DHCP) section 4.1 paragraph #8...
*
* The delay before the first retransmission is 4 seconds randomized by
* the value of a uniform random number chosen from the range -1 to +2.
* The delay before the next retransmission is 8 seconds randomized by
* the same number as previous randomization. Each subsequent retransmission
* delay is doubled up to a maximum of 66 seconds. Once a delay of 66
* seconds is reached, return that value for 6 subsequent delay
* requests, then return RETRANSMISSION_TIMEOUT (-1) indicating that the
* requestor should give up.
*
* The value of randomdelta will be 2, 1, 0 or -1 depending on the target's
* IP address.
*
* The return values will be...
* 4+randomdelta, 8+randomdelta, 16+randomdelta, etc... up to 64+randomdelta.
* Then after returning 64+randomdelta 6 times, return RETRANSMISSION_TIMEOUT.
*
* NOTE: if DELAY_RETURN is the opcode, then RETRANSMISSION_TIMEOUT is
* never returned, once the max is reached, it is always the value
* returned;
* if DELAY_OR_TIMEOUT_RETURN is the opcode, then once maxoutcount
* reaches 6, RETRANSMISSION_TIMEOUT is returned.
*
* NOTE1: this function supports the ability to modify the above-discussed
* parameters. Start with DELAY_INIT_DHCP to set up the parameters
* discussed above; start with DELAY_INIT_XXXX for others.
*/
int
RetransmitDelay(int opcode)
{
static int randomdelta; /* Used to slightly randomize the delay.
* Taken from the 2 least-significant-bits
* of the IP address (range = -1 to 2).
*/
static int rexmitdelay; /* Doubled each time DELAY_INCREMENT
* is called until it is greater than the
* value stored in rexmitdelaymax.
*/
static int rexmitdelaymax; /* See rexmitdelay. */
static int maxoutcount; /* Number of times the returned delay has
* reached its max.
*/
static int giveupcount; /* Once maxoutcount reaches this value, we
* give up and return TIMEOUT.
*/
int rexmitstate;
rexmitstate = RETRANSMISSION_ACTIVE;
switch(opcode) {
case DELAY_INIT_DHCP:
if (getTuneup("DHCPRETRYTUNE",&rexmitdelay,
&giveupcount,&rexmitdelaymax) <= 0) {
rexmitdelay = 4;
giveupcount = 6;
rexmitdelaymax = 64;
}
maxoutcount = 0;
randomdelta = (int)(BinIpAddr[3] & 3) - 1;
break;
case DELAY_INIT_TFTP:
if (getTuneup("TFTPRETRYTUNE",&rexmitdelay,
&giveupcount,&rexmitdelaymax) <= 0) {
rexmitdelay = 4;
giveupcount = 3;
rexmitdelaymax = 32;
}
maxoutcount = 0;
randomdelta = (int)(BinIpAddr[3] & 3) - 1;
break;
case DELAY_INIT_ARP:
if (getTuneup("ARPRETRYTUNE",&rexmitdelay,
&giveupcount,&rexmitdelaymax) <= 0) {
rexmitdelay = 1;
giveupcount = 0;
rexmitdelaymax = 4;
}
maxoutcount = 0;
randomdelta = 0;
break;
case DELAY_INCREMENT:
if (rexmitdelay < rexmitdelaymax)
rexmitdelay <<= 1; /* double it. */
else
maxoutcount++;
if (maxoutcount > giveupcount)
rexmitstate = RETRANSMISSION_TIMEOUT;
break;
case DELAY_OR_TIMEOUT_RETURN:
if (maxoutcount > giveupcount)
rexmitstate = RETRANSMISSION_TIMEOUT;
break;
case DELAY_RETURN:
break;
default:
printf("\007TimeoutAlgorithm error 0x%x.\n",opcode);
rexmitstate = RETRANSMISSION_TIMEOUT;
break;
}
if (rexmitstate == RETRANSMISSION_TIMEOUT)
return(RETRANSMISSION_TIMEOUT);
else
return(rexmitdelay+randomdelta);
}
/* monSendEnetPkt() & monRecvEnetPkt():
* These two functions allow the monitor to provide a primitive
* connect to the ethernet interface for an application (using
* mon_sendenetpkt() and mon_recvenetpkt()).
*
* Note: These are obviously not very sophisticated; however, they
* provide an immediate mechanism for LWIP to access the raw driver.
* without the application even being aware of the type of ethernet
* device.
*/
int
monSendEnetPkt(char *pkt, int pktlen)
{
/* Copy the incoming packet into a packet that has been allocated
* by the monitor's packet allocator for this ethernet device:
*/
memcpy(getXmitBuffer(),pkt,pktlen);
sendBuffer(pktlen);
return(pktlen);
}
int
monRecvEnetPkt(char *pkt, int pktlen)
{
int pcnt, len;
/* Prior to calling polletherdev(), this function sets up the globals
* AppPktPtr and AppPktLen so that if a packet is recived, and
* polletherdev() calls processPACKET(), the data will simply be
* copied to the requested buffer space instead of being processed
* by the monitor's packet handler (see the top of processPACKET()
* for the use of AppPktPtr & AppPktLen).
*
* NOTE: this assumes that the target-specific function polletherdev()
* will only process one packet per call. If it can process more than
* one per call, then packets will be lost here.
*/
AppPktPtr = pkt;
AppPktLen = pktlen;
pcnt = polletherdev();
if (pcnt == 0) {
len = 0;
}
else {
if (pcnt > 1)
len = -AppPktLen;
else
len = AppPktLen;
}
AppPktPtr = 0;
return(len);
}
/* storeMac():
* This function can be called in system startup (after flash drivers
* are initialized) to give the user the opportunity to program a
* MAC address into the "etheraddr" block of flash in monitor space.
* This is only done if that space is erased (0xff), so only on the
* first pass will it be called.
* It is useful for monitors that want to exist without a monrc file,
* but should still have a MAC address.
* As of uMon_1.0, this function can also be called by the ether command.
*/
void
storeMac(int verbose)
{
#if INCLUDE_FLASH
int snum, yes;
char macascii[24], prefill[24], buf[6];
if (etheraddr[0] != 0xff) {
if (verbose)
printf("MAC store abort: etheraddr[] contains data\n");
return;
}
/* If etheraddr[] is writeable (RAM), then assume that this
* function is being called as part of a RAM based temporary
* monitor; hence, no need to do it...
*/
etheraddr[0] = 0;
monDelay(100);
if (etheraddr[0] == 0) {
etheraddr[0] = 0xff;
if (verbose)
printf("MAC store abort: etheraddr[] in RAM\n");
return;
}
/* Use whatever is in config.h as the default MAC address,
* then allow the user to override it with getline_p()...
*/
strcpy(prefill,DEFAULT_ETHERADD);
printf("\nMAC address must be configured.\n");
printf("The system's MAC address is a 6-digit, colon-delimited string\n");
printf("(for example: 12:34:56:78:9a:bc). It must be unique for all\n");
printf("ethernet controllers present on a given subnet. MAC addresses\n");
printf("are often allocated by a product vendor to prevent duplication,\n");
printf("and are frequently documented on decals or other materials\n");
printf("provided with the product. The following prompt allows you\n");
printf("to specify the MAC address for this device.\n");
if (strlen(prefill) != 0)
printf("Use backspace if the printed default needs modification...\n");
printf("\n");
do {
printf("Enter MAC address (xx:xx:xx:xx:xx:xx):\n");
if (getline_p(macascii,sizeof(macascii),0,prefill) == 0)
return;
} while (EtherToBin(macascii,buf) == -1);
printf("Configuring '%s' as MAC address, ok?",macascii);
yes = askuser(" (y or n)");
putchar('\n');
if (!yes)
return;
if (addrtosector((uchar *)etheraddr,&snum,0,0) < 0)
return;
sprintf(buf,"%d",snum);
sectorProtect(buf,0);
AppFlashWrite((uchar *)etheraddr,(uchar *)macascii,strlen(macascii)+1);
sectorProtect(buf,1);
printf("MAC address burned in at 0x%lx\n",(long)etheraddr);
#else
printf("Error: MAC storage requires flash driver\n");
#endif
}
#endif /* INCLUDE_ETHERNET */
/* EtherToBin():
* Convert ascii MAC address string to binary. Note that this is outside
* the #if INCLUDE_ETHERNET because it is used by password.c. This correctly
* implies that if there is no ethernet interface, then we need a different
* solution for the password backdoor!.
*/
int
EtherToBin(char *ascii,uchar *binary)
{
int i, digit;
char *acpy;
acpy = ascii;
for(i=0;i<6;i++) {
digit = (int)strtol(acpy,&acpy,16);
if (((i != 5) && (*acpy++ != ':')) ||
((i == 5) && (*acpy != 0)) ||
(digit < 0) || (digit > 255)) {
printf("Misformed ethernet addr: %s, i = %d\n",ascii,i);
return(-1);
}
binary[i] = (uchar)digit;
}
return(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -