📄 ether.c
字号:
/************************************************************* * File: lib/ether.c * Purpose: common ethernet functions * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 980615 Created from sonic.c * 981127 Moved the GETRXREC swapPkt here from drivers. *//* This module contains all of the chip-independent code needed to * PMON/IMON with an Ethernet download facility. The code is rather * primitive, it only understands UDP and ARP messages, and is only * able to send two types of packet (UDP REPLY and ARP REPLY). The * ether_xxx functions are performed by either sonic.c or am79970.c. */#include <defines.h>#ifdef ETHERNET/*#define VERBOSE /* be verbose */#include <mon.h>#include <termio.h>#include <ether.h>#ifdef CHECKS_ON#include <assert.h>#else#define assert(x)#endif#define swap32(n) ( \ ((((Ulong)(n))>>24)&0x000000ff) | \ ((((Ulong)(n))>>8)&0x0000ff00) | \ ((((Ulong)(n))<<8)&0x00ff0000) | \ ((((Ulong)(n))<<24)&0xff000000) \ )#define swap16(n) ( \ ((((Ushort)(n))>>8)&0x00ff) | \ ((((Ushort)(n))<<8)&0xff00) \ )#define ether_driver(a,b,c) (*ether_driver_ptr)(a,b,c)/* This is how you call the chip-dependent code. ether_driver_ptr * should have been initialized by your cpu-dependent module (eg. c4101.c), * to point to the appropriate driver (eg. sonic_driver). */vpFunc *ether_driver_ptr;static Ushort last_udp_seqno;static char *last_dest_addr;static Ushort tx_ip_id;static char *rx_byte_ptr;static int rx_byte_cnt;static int dotcnt;static RXREC *rx_desc;static char *dest_addr;static Uchar EnetAddr[6]; /* the MAC address */static filbuf();char *getMsg();#ifdef VERBOSEstatic printIp();static printUdp();static printArp();#endifextern int re_ether;extern int vflag;/************************************************************** ether_open(etheraddr)* Just like the standard open() except that it opens the* Ethernet controller.* 'etheraddr' is a string containing the MAC address in the* form aa:bb:cc:dd:ee:ff.*/ether_open(etheraddr)char *etheraddr;{char tmp[30],*p;int i,n;if (etheraddr == 0 || ether_driver_ptr == 0) return(-1);rx_byte_cnt = 0;rx_desc = 0;/* convert the mac address string into an array of 6 bytes */strcpy(tmp,etheraddr);for (i=0,p=strtok(tmp,":");p;p=strtok(0,":"),i++) { sscanf(p,"%x",&n); EnetAddr[i] = n; }if (!ether_driver(ETHER_INIT,EnetAddr,0)) return(-1);flush_cache(DCACHE);return(ETHERFD);}/************************************************************** ether_close()* Just like the standard close() except that it closes the* Ethernet controller.*/ether_close(){char *rxptr;int len;if (rx_desc) { rxptr = (char *)ether_driver(ETHER_GETRBA,rx_desc,&len); sendAck(rxptr,len); ether_driver(ETHER_RXDONE,rx_desc,0); }}/************************************************************** ether_read(fd,ptr,size)* Just like the standard read() except that it reads from the* Ethernet controller.*/ether_read(fd,ptr,size)int fd,size;char *ptr;{int i,c;for (i=0;i<size;) { c = ((rx_byte_cnt--)?*rx_byte_ptr++:filbuf(0)); ptr[i++] = c; if (c == '\n') break; }return(i);}/************************************************************** ether_bcopy()* supports "load -B", binary mode transfers*/ether_bcopy(){for (;;) { filbuf(1); bcopy(rx_byte_ptr,dest_addr,rx_byte_cnt); dest_addr += rx_byte_cnt; }}/************************************************************** filbuf(no_rtn)* Called when the buffer runs out of bytes.* It gets a packet of data and transfers it to the* buffer.*/static filbuf(no_rtn)int no_rtn;{RXREC *q;struct ether_header *e;char *rxptr;int len;if (rx_desc) { rxptr = (char *)ether_driver(ETHER_GETRBA,rx_desc,&len); sendAck(rxptr,len); ether_driver(ETHER_RXDONE,rx_desc,0); }while (1) { while (!ether_driver(ETHER_RXRDY,0,0)) { dotcnt--; if (dotcnt <= 0) { scandevs(); dotcnt = 100000; } } if (!(q=(RXREC *)ether_driver(ETHER_GETRXREC,0,0))) continue; e = (struct ether_header *)ether_driver(ETHER_GETRBA,q,&len);#ifndef MIPSEB if (!swapPkt(phy2k1(e))) { ether_driver(ETHER_RXDONE,(void *)q,0); continue; }#endif#ifdef VERBOSE if (vflag) printPkt(e);#endif if (e->ether_type == ETHERTYPE_ARP) { arpRequest(e); ether_driver(ETHER_RXDONE,q,0); continue; } rx_byte_ptr = getMsg(e,len,&rx_byte_cnt); if (rx_byte_ptr) break; ether_driver(ETHER_RXDONE,q,0); }assert(rx_byte_cnt != 0);rx_desc = q;if (no_rtn) return(0);rx_byte_cnt--;return(*rx_byte_ptr++);}/************************************************************** sendAck(re,len)* send an ACK back to the host*/sendAck(re,len)struct ether_header *re;Ushort len;{int i,n;Ushort *sp;Ulong t;struct ether_header *te;struct ip *ti,*ri;struct udphdr *tu,*ru;if (vflag) { printf("sendAck(%08x,%d)\n",re,len); printMem((char *)re,len); }assert(re != 0);n = 64;te = (struct ether_header *) ether_driver(ETHER_GETTBA,0,&n);te->ether_shost = re->ether_dhost;te->ether_dhost = re->ether_shost;te->ether_type = re->ether_type;ti = (struct ip *) (te+1);ri = (struct ip *) (re+1);ti->ip_vhl = ri->ip_vhl;ti->ip_tos = ri->ip_tos;ti->ip_len = sizeof(struct ip)+sizeof(struct udphdr);ti->ip_id = tx_ip_id++;ti->ip_off = 0;ti->ip_ttl = UDP_TTL;ti->ip_p = IP_UDP;bcopy(&(ri->ip_dst.s_addr),&(ti->ip_src.s_addr),sizeof(struct in_addr));bcopy(&(ri->ip_src.s_addr),&(ti->ip_dst.s_addr),sizeof(struct in_addr));tu = (struct udphdr *) (ti+1);ru = (struct udphdr *) (ri+1);tu->uh_sport = ru->uh_sport;tu->uh_dport = ru->uh_sport;tu->uh_ulen = 12;tu->uh_sum = 0; /* haven't figured this out, try zero */tu->uh_type = UDP_ACK;tu->uh_seqno = 0;if (ru->uh_type == UDP_DATA) tu->uh_seqno = ru->uh_seqno;#ifndef MIPSEBunswapPkt(te);#endif/* compute csum of ip hdr -> t */ti->ip_sum = 0;sp = (Ushort *) ti;for (i=0,t=0;i<(sizeof(struct ip)/sizeof(Ushort));i++,sp++) t += *sp;t = (t&0xffff)+(t>>16);ti->ip_sum = ~t;if (vflag) printMem((char *)te,64);#ifdef VERBOSEif (vflag) printPkt(te,64);#endifif (re_ether) swap32n(te,64);ether_driver(ETHER_TBARDY,0,0);}/************************************************************** char *getMsg(e,size,cnt)* Interprets the packet. * Is only able to understand UDP packets of type UDP_OPEN * and UDP_DATA.*/char *getMsg(e,size,cnt)struct ether_header *e;Ushort size;int *cnt;{struct ip *i;struct udphdr *u;int minlen;*cnt = 0;assert(e != 0);minlen = sizeof(struct ether_header)+sizeof(struct ip)+sizeof(struct udphdr);assert(size >= minlen);i = (struct ip *)(e+1);if (pingRequest(e)) return(0);if (i->ip_p != IP_UDP) return(0);u = (struct udphdr *)(i+1);switch (u->uh_type) { case UDP_OPEN : #ifndef MIPSEB u->uh_seqno = swap16(u->uh_seqno);#endif sscanf(&(u->uh_seqno),"%x",&dest_addr); last_udp_seqno = 0; tx_ip_id = i->ip_id; sendAck(e,size); return(0); case UDP_DATA : if (u->uh_seqno > last_udp_seqno) { last_dest_addr = dest_addr; last_udp_seqno = u->uh_seqno; } else { /* retry packet */ dest_addr = last_dest_addr; } *cnt = u->uh_ulen-sizeof(struct udphdr); return((char *)(u+1)); }return(0);}/************************************************************** pingRequest(e)*/pingRequest(e)struct ether_header *e;{struct ether_header *te;struct ip *i,*ti;struct icmp *m,*tm;Ushort *sp;Ulong t;int n,len;if (e->ether_type != ETHERTYPE_IP) return(0);i = (struct ip *)(e+1);if (i->ip_p != IP_ICMP) return(0);m = (struct icmp *)(i+1);if (m->icmp_type != ICMP_ECHO) return(0);/* This is a ping request */len = i->ip_len+sizeof(struct ether_header);te = (struct ether_header *) ether_driver(ETHER_GETTBA,0,&len);te->ether_dhost = e->ether_shost;bcopy(EnetAddr,&(te->ether_shost),6);te->ether_type = e->ether_type;/* build ip header */ti = (struct ip *) (te+1);ti->ip_vhl = i->ip_vhl;ti->ip_tos = i->ip_tos;ti->ip_len = i->ip_len;ti->ip_id = i->ip_id;ti->ip_off = i->ip_off;ti->ip_ttl = i->ip_ttl;ti->ip_p = i->ip_p; /* proto */bcopy(&(i->ip_dst.s_addr),&(ti->ip_src.s_addr),sizeof(struct in_addr));bcopy(&(i->ip_src.s_addr),&(ti->ip_dst.s_addr),sizeof(struct in_addr));/* build icmp header */tm = (struct icmp *) (ti+1);tm->icmp_type = ICMP_ECHOREPLY;tm->icmp_code = m->icmp_code;tm->icmp_cksum = 0;tm->icmp_id = m->icmp_id;tm->icmp_seq = m->icmp_seq;bcopy(m->icmp_data,tm->icmp_data,i->ip_len-sizeof(struct ip));/* this is a hack. The real checksum calc appears to be 16-bit addstarting at icmp_type and continuing for 62 bytes. Then add 4. Write
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -