📄 networkstack.c
字号:
net_pings++;#endif }}static void net_handleudp(uint8_t hlen) { /* UDP: IP Header + * 0 - 1: srcport * 2 - 3: dstport * 4 - 5: length including header (>= 8) * 6 - 7: checksum * 8 - X: data */ if ((net_packet[hlen+2] == 0) && (net_packet[hlen+3] == 123)) { /* This goes to the NTP port */ struct tickdata td; uint16_t cs; uint32_t tstmp; uint8_t dcfv = dcfvalid; gettickdata(&td); if (dcftime[dcfv].timestamp == 0) { /* Oups, we have no signal yet - do not reply, * since we have no idea what day or time it is * without receiving the signal */ return; } if ((net_packet[hlen] == 0) && (net_packet[hlen+1] == 0)) { /* No sourceport - so we don't know where to send a reply */ return; } if ((net_packet[hlen+8] & 0x07) > 0x06) { /* We cannot handle mode 6 (control messages) */ } swapdestandsrceth(); swapdestandsrcip(); net_packet[hlen+2] = net_packet[hlen]; net_packet[hlen+3] = net_packet[hlen+1]; net_packet[hlen] = 0; net_packet[hlen+1] = 123; net_packet[hlen+4] = 0; net_packet[hlen+5] = 56; net_packet[hlen+8] = 0x1c; /* Flags: No Leap, V3, Server */ net_packet[hlen+9] = 1; /* Stratum */ if ((net_packet[hlen+10] < 4) || (net_packet[hlen+10] > 10)) { net_packet[hlen+10] = 6; /* Poll Interval (64 sec) */ } net_packet[hlen+11] = 0xee; /* Precision (Yes, this is a lie) */ memset(&net_packet[hlen+12], 0, 8); /* 8 bytes of 0 */ net_packet[hlen+14] = 0x04; /* These must not be 0 though, */ net_packet[hlen+18] = 0x04; /* so we fill in dummys */ net_packet[hlen+20] = 'D'; net_packet[hlen+21] = 'C'; net_packet[hlen+22] = 'F'; net_packet[hlen+23] = 0; tstmp = dcftime[dcfv].timestamp + 2208988800UL; /* Yes, this WILL overflow in 2036 */ if (dcftime[dcfv].issummertime) { /* Summertime: -3600 */ tstmp -= 3600UL; } /* Reference Timestamp */ net_packet[hlen+24] = (uint8_t)(tstmp >> 24); net_packet[hlen+25] = (uint8_t)(tstmp >> 16); net_packet[hlen+26] = (uint8_t)(tstmp >> 8); net_packet[hlen+27] = (uint8_t)(tstmp ); memset(&net_packet[hlen+28], 0, 4); /* Originate Timestamp */ memcpy(&net_packet[hlen+32], &net_packet[hlen+48], 8); /* Receive and Transmit Timestamp */ tstmp += ((uint16_t)(td.seconds - dcftime[dcfv].ticksecs)); net_packet[hlen+40] = net_packet[hlen+48] = (uint8_t)(tstmp >> 24); net_packet[hlen+41] = net_packet[hlen+49] = (uint8_t)(tstmp >> 16); net_packet[hlen+42] = net_packet[hlen+50] = (uint8_t)(tstmp >> 8); net_packet[hlen+43] = net_packet[hlen+51] = (uint8_t)(tstmp ); /* Set fraction in hlen+44 and hlen+52 */ tstmp = td.ticks; tstmp = (tstmp << 16) / TICKSPERSECOND; tstmp <<= 16; net_packet[hlen+44] = net_packet[hlen+52] = (uint8_t)(tstmp >> 24); net_packet[hlen+45] = net_packet[hlen+53] = (uint8_t)(tstmp >> 16); net_packet[hlen+46] = net_packet[hlen+54] = (uint8_t)(tstmp >> 8); net_packet[hlen+47] = net_packet[hlen+55] = (uint8_t)(tstmp ); /* IP header checksum */ net_packet[24] = net_packet[25] = 0; cs = net_calcipchecksum(&net_packet[14], (hlen - 14)); net_packet[24] = cs & 0xff; net_packet[25] = cs >> 8; /* UDP checksum */ net_packet[hlen+6] = net_packet[hlen+7] = 0; /* We have to add the "pseudo header" - what a piece of * crap... */ memcpy(&net_packet[hlen+56], &net_packet[26], 8); net_packet[hlen+64] = 0; net_packet[hlen+65] = 56; net_packet[hlen+66] = 0; net_packet[hlen+67] = 17; cs = net_calcipchecksum(&net_packet[hlen], 68); net_packet[hlen+6] = cs & 0xff; net_packet[hlen+7] = cs >> 8; net_sendpacket(net_packet, hlen + 56); led_statusleds |= led_status_netntp;#ifdef NETWORKSTATS net_ntpqs++;#endif } else if ((net_packet[hlen+2] == 0x7a) && (net_packet[hlen+3] == 0x69)) { /* Port 31337 can be used to send commands (with password) */ /* Nothing fancy here, structure of the packet is simple: * byte 8 - 16 password (8 characters + terminating \0) * byte 17 command: * 1 == display text * byte 18 - X additional data for commands * for command 1: byte 18 - 24 text to display. */ if (memcmp(&net_packet[hlen+8], net_rconpass, 8)) { /* Password incorrect */ return; } led_statusleds |= led_status_netrcon; switch (net_packet[hlen+17]) { case 1: /* Command "Display Text" */ memcpy(&led_dispoverride[0], &net_packet[hlen+18], 7); if ((net_packet[hlen+25] <= 0) || (net_packet[hlen+25] > 60)) { led_dispovcnt = 30; /* 5 seconds */ } else { led_dispovcnt = net_packet[hlen+25]; } break; case 2: /* Command "Set Display Brightness" */ led_brightness = net_packet[hlen+18]; break;#ifdef CLOCKFACEMODULE case 3: /* Command "Set Clockface Brightness" */ clockface_brightness = net_packet[hlen+18]; break;#endif /* CLOCKFACEMODULE */ };#ifdef NETWORKSTATS net_rcons++;#endif /* def NETWORKSTATS */#ifndef NET_NODPORTUNREACH } else { uint16_t i; /* Send back ICMP Port unreachable, unless packet is too * large. */ if (net_recvdbytes > 200) { return; } for (i = (net_recvdbytes-5); i >= 14; i--) { net_packet[i+hlen+8-14] = net_packet[i]; } net_recvdbytes += (hlen + 8); net_recvdbytes -= (14 + 4); /* And alter the header */ swapdestandsrceth(); swapdestandsrcip(); net_packet[23] = 1; /* We're now an ICMP packet */ net_packet[22] = 0x40; /* With a lot of TTL */ net_packet[17] += hlen + 8 - 14; /* And a new length */ net_packet[24] = net_packet[25] = 0; i = net_calcipchecksum(&net_packet[14], hlen-14); net_packet[24] = i & 0xff; net_packet[25] = i >> 8; /* Now fill in the first 8 bytes after header */ net_packet[hlen ] = 0x03; /* "Unreachable" */ net_packet[hlen+1] = 0x03; /* Type "Port" -> Port Unreach */ memset(&net_packet[hlen+2], 0, 6); i = net_calcipchecksum(&net_packet[hlen], (net_recvdbytes - hlen)); net_packet[hlen+2] = i & 0xff; net_packet[hlen+3] = i >> 8; net_sendpacket(net_packet, net_recvdbytes);#endif /* ndef NET_NODPORTUNREACH */ }}/* The name "HANDLEtcp" might be a bit misleading, because all this * actually does is to send back a TCP Reset */#ifndef NET_NOTCPRESETvoid net_handletcp(uint8_t hlen) { uint16_t i; i = *((uint16_t *)(&net_packet[hlen])); *((uint16_t *)(&net_packet[hlen])) = *((uint16_t *)(&net_packet[hlen+2])); *((uint16_t *)(&net_packet[hlen+2])) = i; for (i=0; i<4; i++) { net_packet[hlen+i+8] = net_packet[hlen+i+4]; net_packet[hlen+i+4] = 0; } net_packet[hlen+12] = 0x50; net_packet[hlen+13] = 0x14; memset(&net_packet[hlen+14], 0, 6); /* checksum @ 16+17 */ /* add the "pseudo header" for checksum calculation */ memcpy(&net_packet[hlen+20], &net_packet[26], 8); net_packet[hlen+28] = 0; net_packet[hlen+29] = 20; /* tcp length */ net_packet[hlen+30] = 0; net_packet[hlen+31] = 6; /* prot. number */ i = net_calcipchecksum(&net_packet[hlen], 32); net_packet[hlen+16] = i & 0xff; net_packet[hlen+17] = i >> 8; swapdestandsrceth(); swapdestandsrcip(); net_packet[24] = net_packet[25] = 0; i = net_calcipchecksum(&net_packet[14], (hlen - 14)); net_packet[24] = i & 0xff; net_packet[25] = i >> 8; net_sendpacket(net_packet, hlen+20);}#endif /* ndef NET_NOTCPRESET */void net_handleip(void) { uint8_t hlen; /* Header length (Points to start of actual data) */ if (memcmp(&net_packet[30], net_ip, 4)) { /* Not for us */ return; } if ((net_packet[14] & 0xf0) != 0x40) { /* Not IPv_4_ */ return; } hlen = ((net_packet[14] & 0x0f) << 2) + 14; if (((net_packet[20] & 0xBF) != 0x00) || (net_packet[21] != 0x00)) { /* We cannot handle fragmentation. */ return; } /* That should be enough sanity checks for now */ if (net_packet[23] == 1) { /* Protocol ICMP */ net_handleicmp(hlen); } else if (net_packet[23] == 17) { /* Protocol UDP */ net_handleudp(hlen);#ifndef NET_NOTCPRESET } else if (net_packet[23] == 6) { /* Protocol TCP */ net_handletcp(hlen);#endif /* ndef NET_NOTCPRESET */ }}void net_handlereceivedpacket(void) { /* For reference: Structure of a Ethernet Packet: * Destination Byte 0 - 5 * Source Byte 6 - 11 * Length/Type Byte 12 - 13 * Data at least 46 Bytes */ if ((net_recvdbytes >= 64) && ((net_packet[6] & NET_MCASTBIT) == 0)) { /* Packets shorter than 64 bytes are nonsense, and * Sanity check, so that we don't reply to * multi-/broadcast-addresses and create a flood */ if ((memcmp(net_packet, net_mac, 6) == 0) || ((net_packet[0] == 0xff) && (net_packet[1] == 0xff) && (net_packet[2] == 0xff) && (net_packet[3] == 0xff) && (net_packet[4] == 0xff) && (net_packet[5] == 0xff))) { /* Addressed to our unicast address or * Addressed to broadcast */ /* check if it's ARP (type 0x0806) * or IP (type 0x0800) */ if ((net_packet[12] == 0x08) /* Protocol ARP */ && (net_packet[13] == 0x06)) { net_handlearp(); } else if ((net_packet[12] == 0x08) /* Protocol IP */ && (net_packet[13] == 0x00)) { net_handleip(); } } }}static void readmacfromeeprom(void) { uint8_t i; writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_STOP | CMDR_NODMA); /* select byte wide transfers */ writene2kreg(NEDCR, DCR_BYTEDMA | DCR_FIFO8 | DCR_NOLPBK); writene2kreg(NERBCR0, 0); writene2kreg(NERBCR1, 0); writene2kreg(NEIMR, 0); /* no IRQs */ writene2kreg(NEISR, 0xff); /* ACK any irqs */ writene2kreg(NERCR, RCR_MONITOR); /* receive off */ writene2kreg(NETCR, TCR_INTLPBK); /* transmit off */ writene2kreg(NERBCR0, 32); /* Intend to read 32 Bytes */ writene2kreg(NERBCR1, 0); writene2kreg(NERSAR0, 0); /* low byte of start address (0x0000) */ writene2kreg(NERSAR1, 0); /* high byte of start address */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_DMAREAD); /* for some reason, 2 reads are required, otherwise you get duplicate * values. the comments in the linux driver talk about values being * "doubled up", but i don't know why. whatever - it works this way * and i don't have time to investigate :) */ for (i = 0; i < 6; i++) { readne2kreg(NERDMA); net_mac[i] = readne2kreg(NERDMA); } /* end (abort) the DMA transfer */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_NODMA);}void net_init(void) { uint8_t i; /* my step 0a: force a hardware reset on the card */ isareset(); /* my step 0b: read mac address from the card's onboard eeprom */ readmacfromeeprom(); /* step 1: program command register for page 0 * cheung, ns 0x21 */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_STOP | CMDR_NODMA); /* cheung does a soft reset here... */ /* step 2: initialize data configuration register * cheung 0x48, ns 0x58 */ writene2kreg(NEDCR, DCR_BYTEDMA | DCR_FIFO8 | DCR_NOLPBK); /* step 3: clear remote byte count registers * cheung, ns 0 */ writene2kreg(NERBCR0, 0); writene2kreg(NERBCR1, 0); /* step 4: initialize recieve configuration register * cheung: 0x0c, ns: 0, linux: 0x20 */ writene2kreg(NERCR, RCR_MONITOR); /* disable reception for now */ /* step 5: place the NIC in loopback mode (hey - don't i also have to set * a bit in DCR in order to go into loopback mode? hmm...) */ writene2kreg(NETCR, TCR_INTLPBK); /* step 5 and a half: initialize the transmit buffer start page */ writene2kreg(NETPSR, TXSTART); /* step 6: initialize receive buffer ring (256 byte blocks) * cheung: start=0x40, stop=0x76 (or 0x7c?) * ns: start=0x26, stop=0x40 * linux: 0x26/0x40 or 0x46/0x80 (NE1SM or NESM) */ writene2kreg(NEPSTA, RXSTART); writene2kreg(NEBNRY, RXSTART); writene2kreg(NEPSTO, RXSTOP); /* step 7: clear interrupt status register * cheung: performs this step earlier (after step #3) */ writene2kreg(NEISR, 0xff); /* step 8: initialize the interrupt mask register * cheung: 0 (out of order - after #7) * ns: 0x0b */ writene2kreg(NEIMR, 0); /* no interrupts, please */ /* step 9a: go to register page 1 */ writene2kreg(NECMDR, CMDR_PAGE1 | CMDR_STOP | CMDR_NODMA); /* step 9b: initialize hardware address * (what?! shouldn't this already be set from EEPROM?) */ for (i=0; i<6; i++) { writene2kreg(NEPAR0 + i, net_mac[i]); } /* step 9c: initialize multicast address (i don't care about multicast) */ /* ... not implemented ... */ /* step 9d: initialize CURRent pointer */ writene2kreg(NECURR, RXSTART + 1); /* step 10: put NIC in START mode */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_NODMA); /* step 11: initialize transmit control register (disable loopback mode) */ writene2kreg(NETCR, TCR_NOLPBK); /* should i re-set DCR here to cancel loopback? */ /* my step 12: initialize recieve configuration register so that we * can get packets */ writene2kreg(NERCR, RCR_BCAST); /* cheung reads the mac address from eeprom here. seems too late to me! */ /* FIXME? Enable ISA IRQs? the IRQ line is connected to PD4 */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -