📄 net_3c509.cxx
字号:
if (len) MsgLog::printf("cksum: out of data\n"); if (byte_swapped) { UNSWAP; } REDUCE; ADDCARRY; return (sum ^ 0xffff);}#elif !defined(INCREDIBLY_SLOW)/* * Checksum routine for Internet Protocol family headers (Portable Version). * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. */#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}typedef uint32_t u_int32_t;typedef uint16_t u_int16_t;typedef uint8_t u_int8_t;typedef char int8_t;intin_cksum(register uint16_t *buf, register int len){ register u_int16_t *w; register int sum = 0; register int mlen = len; int byte_swapped = 0; union { u_int8_t c[2]; u_int16_t s; } s_util; union { u_int16_t s[2]; u_int32_t l; } l_util; w = buf; if (len < mlen) mlen = len; len -= mlen; /* * Force to even boundary. */ if ((1 & (long) w) && (mlen > 0)) { REDUCE; sum <<= 8; s_util.c[0] = *(u_int8_t *)w; w = (u_int16_t *)((int8_t *)w + 1); mlen--; byte_swapped = 1; } /* * Unroll the loop to make overhead from * branches &c small. */ while ((mlen -= 32) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; w += 16; } mlen += 32; while ((mlen -= 8) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; w += 4; } mlen += 8; if (mlen == 0 && byte_swapped == 0) goto done; REDUCE; while ((mlen -= 2) >= 0) { sum += *w++; } if (byte_swapped) { REDUCE; sum <<= 8; byte_swapped = 0; if (mlen == -1) { s_util.c[1] = *(u_int8_t *)w; sum += s_util.s; mlen = 0; } else mlen = -1; } else if (mlen == -1) s_util.c[0] = *(u_int8_t *)w;done: if (len) MsgLog::printf("cksum: out of data\n"); if (mlen == -1) { /* The last mbuf has odd # of bytes. Follow the standard (the odd byte may be shifted left by 8 bits or not as determined by endian-ness of the machine) */ s_util.c[1] = 0; sum += s_util.s; } REDUCE; return (~sum & 0xffff);}#elseuint16_tin_cksum(uint16_t *buf, int len){ uint32_t cksum=0; if ((u_long)buf & 0x01) { cksum=(*(u_char *)buf)<<8; buf=(uint16_t *)((char *)buf+1); len--; } while (len>1) { cksum+=*buf++; if (cksum & 0x10000) cksum=(cksum & 0xFFFF)+1; len-=2; } if (len) { cksum+=*(u_char *)buf; if (cksum & 0x10000) cksum=(cksum & 0xFFFF)+1; } return ~cksum;}#endif#define ETHERTYPE_IP 0x0800 /* IP protocol */#define ICMP_ECHOREPLY 0 /* echo reply */#define ICMP_ECHO 8 /* echo service */#define IPPROTO_ICMP 1 /* control message protocol */#define LEN_ICMP_HDR 16#define LEN_ICMP_DATA 48#define LEN_ICMP (LEN_ICMP_HDR+LEN_ICMP_DATA)#define LEN_IP (sizeof(struct ip)+LEN_ICMP)#define ETHER_ADDR_LEN 6struct ether_addr { uint8_t ether_addr_octet[6];};struct ether_header { uint8_t ether_dhost[ETHER_ADDR_LEN]; uint8_t ether_shost[ETHER_ADDR_LEN]; uint16_t ether_type;};struct in_addr { Word s_addr;};struct ip {#if BYTE_ORDER == LITTLE_ENDIAN uint8_t ip_hl:4, /* header length */ ip_v:4; /* version */#endif#if BYTE_ORDER == BIG_ENDIAN uint8_t ip_v:4, /* version */ ip_hl:4; /* header length */#endif uint8_t ip_tos; /* type of service */ short ip_len; /* total length */ uint16_t ip_id; /* identification */ short ip_off; /* fragment offset field */#define IP_DF 0x4000 /* dont fragment flag */#define IP_MF 0x2000 /* more fragments flag */#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ uint8_t ip_ttl; /* time to live */ uint8_t ip_p; /* protocol */ uint16_t ip_sum; /* checksum */ struct in_addr ip_src, ip_dst; /* source and dest address */};/* * Structure of an icmp header. */typedef short n_short;typedef unsigned int n_time;struct icmp { uint8_t icmp_type; /* type of message, see below */ uint8_t icmp_code; /* type sub code */ uint16_t icmp_cksum; /* ones complement cksum of struct */ union { uint8_t ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { n_short icd_id; n_short icd_seq; } ih_idseq; int ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { n_short ipm_void; n_short ipm_nextmtu; } ih_pmtu; } icmp_hun;#define icmp_pptr icmp_hun.ih_pptr#define icmp_gwaddr icmp_hun.ih_gwaddr#define icmp_id icmp_hun.ih_idseq.icd_id#define icmp_seq icmp_hun.ih_idseq.icd_seq#define icmp_void icmp_hun.ih_void#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu union { struct id_ts { n_time its_otime; n_time its_rtime; n_time its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; unsigned int id_mask; char id_data[1]; } icmp_dun;#define icmp_otime icmp_dun.id_ts.its_otime#define icmp_rtime icmp_dun.id_ts.its_rtime#define icmp_ttime icmp_dun.id_ts.its_ttime#define icmp_ip icmp_dun.id_ip.idi_ip#define icmp_mask icmp_dun.id_mask#define icmp_data icmp_dun.id_data};static uint32_t IpIdNext = 0;boolPingPacket(NetInterface *ni, uint8_t *pPkt, uint32_t len){ struct ether_header *h_ether=(struct ether_header *)pPkt; struct ip *h_ip=(struct ip *)(pPkt+sizeof(struct ether_header)); struct icmp *h_icmp=(struct icmp *)(((char *)h_ip)+(h_ip->ip_hl<<2)); struct in_addr tmp; uint16_t the_ether_type = ETHERTYPE_IP; HTONS(the_ether_type); if (!(h_ether->ether_type == the_ether_type && len>=LEN_IP && h_ip->ip_p == IPPROTO_ICMP && h_icmp->icmp_type == ICMP_ECHO)) return false; if (h_ip->ip_ttl == 0) return false;#if 0 MsgLog::printf("It's icmp echo!\n");#endif bcopy(h_ether->ether_shost, h_ether->ether_dhost, sizeof(struct ether_addr)); bcopy(ni->info.niAddr, h_ether->ether_shost, sizeof(struct ether_addr)); if (in_cksum((uint16_t *)h_ip, (h_ip->ip_hl<<2))) return false;#if 0 MsgLog::printf("Cksum OK\n");#endif tmp=h_ip->ip_dst; h_ip->ip_dst=h_ip->ip_src; h_ip->ip_sum=0; h_ip->ip_src=tmp; h_ip->ip_ttl = 64; /* it's a new packet! */ h_ip->ip_id=IpIdNext++; h_ip->ip_sum=in_cksum((uint16_t *)h_ip, h_ip->ip_hl<<2); h_icmp->icmp_cksum=0; h_icmp->icmp_type=ICMP_ECHOREPLY; h_icmp->icmp_cksum=in_cksum((uint16_t *)h_icmp, h_ip->ip_len-(h_ip->ip_hl<<2)); return true;}#endif/* SLEAZY HACK ALERT -- it proves that the x86 caches are not * write-allocate. The consequence is that the packet comes in from * the I/O port, goes through the store buffer TO MAIN MEMORY, and * promptly gets read back in by the in_cksum routine. For things the * size of ethernet packets, it is therefore worth forcing them into * the cache. */inline voidIoRdPkt(NetInterface *ni, uint8_t *buf, uint32_t len){ /* Patch up the buffer alignment so we can move the data quickly: */ while ((uint32_t) buf & 3) { *buf++ = in8(ni->ioAddr + Wn1Rxuint8_tFifo); len --; } ins32(ni->ioAddr + Wn1RxFifo, buf, len >> 2); buf += (len & ~3u); len &= 3; while (len--) *buf++ = in8(ni->ioAddr + Wn1Rxuint8_tFifo); /* A complete, good packet has been read. We do not need to read dribble * bytes. */}inline voidIoWrPkt(NetInterface *ni, uint8_t *buf, uint32_t len){ uint32_t totlen = len & 3; /* Begin sending the packet, but be careful about send buffer * alignment: */ while ((uint32_t) buf & 3) { out8(*buf++, ni->ioAddr + Wn1Txuint8_tFifo); /* write to low-order byte */ len--; } /* sndBufPtr is now word aligned. Send as many words as we can: */ outs32(ni->ioAddr + Wn1TxFifo, buf, len >> 2); buf += (len & ~3u); len &= 3; while (len--) out8(*buf++, ni->ioAddr + Wn1Txuint8_tFifo); /* write to low-order byte */ while (totlen & 3) { out8(0, ni->ioAddr + Wn1Txuint8_tFifo); /* write to low-order byte */ totlen++; }}static voidSkipBadRxPackets(NetInterface *ni){ /* Check the status to see if the packet is any good -- if not, * there is really no point waking up the caller. */ for ( ;; ) { uint16_t rx_status = in16(ni->ioAddr + Wn1RxStatus); if (rx_status & RxsIncomplete) return; if (rx_status & RxsError) { bool goodPacket = false; /* Packet reception error -- update the error statistics: */ uint16_t whichErr = rx_status & RxsErrType;#ifdef VERBOSE MsgLog::printf("Rx: dropped packet (");#endif switch (whichErr) { case RxsOverrun: ni->stats.rxOverrun++;#ifdef VERBOSE MsgLog::printf("overrun");#endif break; case RxsOversize: ni->stats.rxLengthErrors++;#ifdef VERBOSE MsgLog::printf("oversize");#endif break; case RxsDribble: ni->stats.rxFrameErrors++; goodPacket = true; /* packet should be processed! */#ifdef VERBOSE MsgLog::printf("dribble");#endif break; case RxsRunt: ni->stats.rxLengthErrors++;#ifdef VERBOSE MsgLog::printf("runt");#endif break; case RxsAlignment: ni->stats.rxFrameErrors++;#ifdef VERBOSE MsgLog::printf("align");#endif break; case RxsCRC: ni->stats.rxCrcErrors++;#ifdef VERBOSE MsgLog::printf("crc");#endif break; } if (goodPacket) break; ni->stats.rxDropped++; #ifdef VERBOSE MsgLog::printf(") dropped pkt 0x%04x err=%d\n", rx_status);#endif OutCmd(ni, RxDiscard, true); } else break; }}/* RxPacket logic: * * Skip past any bad packets in the FIFO. * If packets remain * mask out packet receive interrupts * wake up readers, if any * ack the interrupt */static voidRxPacket(NetInterface *ni){#ifdef VERBOSE MsgLog::printf("Got rd pkt intr on %s\n", ni->info.name);#endif SkipBadRxPackets(ni); uint16_t rx_status = in16(ni->ioAddr + Wn1RxStatus); /* We have skipped past all the bad packets. See if any good * packets remain: */ if ( (rx_status & RxsIncomplete) == 0 ) { /* Disable receive completion interrupts */ ni->curInts &= ~RxComplete; /* MsgLog::printf("Disable RxComplete interrupt\n"); */ OutCmd(ni, SetIntrMask | ni->curInts); ni->rdQ.WakeAll(0, true); } /* Finally, ack this interrupt: */ OutCmd(ni, AckIntr | RxComplete | RxEarly);}static inline voidClearTxStatusStack(NetInterface *ni){ uint16_t tx_status = 0; int i = 4; while (--i > 0 && (tx_status = in8(ni->ioAddr + Wn1TxStatus)) > 0) { /* This generates printfs on collisions, which happens with acks. * MsgLog::printf("3c509: tx_status = 0x%08x\n", tx_status); */ if (tx_status & (TxsJabber | TxsUnderrun | TxsCollisions)) ni->stats.txAbort++; if (tx_status & (TxsJabber|TxsUnderrun)) OutCmd(ni, TxReset, true); if (tx_status & (TxsJabber|TxsUnderrun|TxsCollisions|TxsStatusOverflow)) OutCmd(ni, TxEnable); /* Pop the status stack. */ out8(0x00, ni->ioAddr + Wn1TxStatus); }}static voidWritePacket(NetInterface * ni, Invocation& inv){ uint64_t dw = rdtsc(); ClearTxStatusStack(ni); /* See if the TX Fifo has room for the outbound packet: */ uint16_t txFree = in16(ni->ioAddr + Wn1TxFree);#if 0 MsgLog::printf("inv.entry.len=%d\n", inv.entry.len);#endif if (inv.entry.len < MIN_ENET_PACKET_SZ || inv.entry.len > MAX_ENET_PACKET_SZ) { /* input buffer not aligned properly. */ inv.exit.code = RC_RequestError; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -