📄 miniweb.c
字号:
/* Copyright (c) 2001, Adam Dunkels. All rights reserved. * * Redistribution or modification is prohibited. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */#define STATEFUL#include "dev.h"#include "miniweb.h"/* These are kept in CPU registers. */static unsigned char a, x, y, c;/* These are kept in RAM. */static unsigned char ipaddr[4];static unsigned char srcport[2];static unsigned char port;static unsigned char seqno[4];static struct tcpip_header *stateptr;static unsigned char chksum[2];static unsigned short len;static unsigned char *tmpptr;#ifdef STATEFULstatic struct tcpip_header *tmpstateptr;static unsigned char cwnd;static unsigned char tcpstate;static unsigned char inflight;#endif /* STATEFUL *//* These actually only need four bits each. */static unsigned char timer, txtime, nrtx;/* Only two bits of state needed here. */static unsigned char chksumflags;#define CHKSUMFLAG_BYTE 2#define CHKSUMFLAG_CARRY 1/* This is just a declaration, and does not use RAM. */extern struct tcpip_header *pages[];extern struct tcpip_header reset;static void tcpip_output(void);#define NULL (void *)0#define Y_NORESPONSE 0#define Y_RESPONSE 1#define Y_NEWDATA 2/* a + c << 8 = a + x + c *//*#define ADC(a, c, x) do { \ unsigned short __tmp; \ __tmp = a + (x) + c; \ a = __tmp & 0xff; \ c = __tmp >> 8; \ } while(0)*/#define ADD_CHK1(x) ADC(chksum[0], c, x);#define ADD_CHK2(x) ADC(chksum[1], c, x); /*#define ADD_CHK(x) do { \ if(!(chksumflags & CHKSUMFLAG_BYTE)) { \ ADD_CHK1(x); \ chksumflags = chksumflags | CHKSUMFLAG_BYTE; \ } else { \ ADD_CHK2(x); \ chksumflags = chksumflags & ~CHKSUMFLAG_BYTE; \ } \ } while(0)#define DEV_GETC(x) do { \ DEV_GET(x); \ ADD_CHK(x); \ } while(0) */#define ADC(a, c, x) adc(&(a), &(c), x)#define ADD_CHK(x) add_chk(x)#define DEV_GETC(x) x = dev_getc()#define DEV_WAITC(x) DEV_WAIT(x); ADD_CHK(x)/*-----------------------------------------------------------------------------------*/static voidadc(unsigned char *a, unsigned char *c, unsigned char x){ unsigned short tmp; tmp = *a + x + *c; *a = tmp & 0xff; *c = tmp >> 8; }/*-----------------------------------------------------------------------------------*/static voidadd_chk(unsigned char x){ ADC(chksum[(chksumflags & CHKSUMFLAG_BYTE) >> 1], c, x); chksumflags ^= CHKSUMFLAG_BYTE;}/*-----------------------------------------------------------------------------------*/static unsigned chardev_getc(void){ unsigned char x; DEV_GET(x); ADD_CHK(x); return x;}/*-----------------------------------------------------------------------------------*/voidminiweb_init(void){ nrtx = 0;#ifdef STATEFUL tcpstate = LISTEN; cwnd = 1; inflight = 0;#endif /* STATEFUL */}/*-----------------------------------------------------------------------------------*/voidminiweb_main_loop(void) { while(1) { drop: DEV_DROP();#ifdef STATEFUL /* The content of the y register signals whether we should send out a new packet once the input processing is done. y = 0 means that we should not send out a packet and y != 0 means that we should send out a packet. */ y = Y_NORESPONSE;#endif /* STATEFUL */ chksum[0] = chksum[1] = 0; chksumflags = 0; /* Get first byte of IP packet, which is the IP version number and IP header length. */ DEV_WAITC(a); /* We discard every packet that isn't IP version 4 and that has IP options. */ if(a != 0x45) { printf("Packet dropped due to options or version mismatch\n"); goto drop; } /* IP Type of Service field, discard. */ DEV_GETC(a); /* IP packet length. */ DEV_GETC(a); len = a << 8; DEV_GETC(a); len |= a; /* IP ID, discard. */ DEV_GETC(a); DEV_GETC(a); /* Fragmentation offset. */ DEV_GETC(a); if((a & 0x20) || (a & 0x1f) != 0) { printf("Got IP fragment, dropping\n"); goto drop; } DEV_GETC(a); if(a != 0) { printf("Got IP fragment, dropping\n"); goto drop; } /* TTL, discard. */ DEV_GETC(a); /* Get the IP protocol field. If this isn't a TCP packet, we drop it. */ DEV_GETC(a); if(a != IP_PROTO_TCP) { printf("Not a TCP packet, dropping\n"); goto drop; } /* Get the IP checksum field, and discard it. */ DEV_GETC(a); DEV_GETC(a); /* Get the source address of the packet, which we will use as the destination address for our replies. */ DEV_GETC(a); ipaddr[0] = a; DEV_GETC(a); ipaddr[1] = a; DEV_GETC(a); ipaddr[2] = a; DEV_GETC(a); ipaddr[3] = a; /* And we discard the destination IP address. */ DEV_GETC(a); DEV_GETC(a); DEV_GETC(a); DEV_GETC(a); /* Check the computed IP header checksum. If it fails, we go ahead and drop the packet. */ while(c) { ADD_CHK(0); } if(chksum[0] != 0xff || chksum[1] != 0xff) { printf("Failed IP header checksum, dropping\n"); goto drop; } /* Thus the IP processing is done with, and we carry on with the TCP layer. */ chksum[0] = chksum[1] = 0; c = 0; chksumflags = 0; /* Get the source TCP port and store it for our replies. */#ifdef STATEFUL DEV_GETC(a); if(tcpstate == LISTEN || tcpstate == TIME_WAIT) { srcport[0] = a; } else if(srcport[0] != a) { printf("Got new port and not in LISTEN or TIME_WAIT, dropping packet\n"); goto drop; } DEV_GETC(a); if(tcpstate == LISTEN || tcpstate == TIME_WAIT) { srcport[1] = a; } else if(srcport[1] != a) { printf("Got new port and not in LISTEN or TIME_WAIT, dropping packet\n"); goto drop; }#else /* STATEFUL */ DEV_GETC(a); srcport[0] = a; DEV_GETC(a); srcport[1] = a;#endif /* STATEFUL */ /* Get the TCP destination port. */ DEV_GETC(a); DEV_GETC(a);#ifdef STATEFUL if(tcpstate == LISTEN || tcpstate == TIME_WAIT) { port = a; }#else /* STATEFUL */ port = a;#endif /* STATEFUL */ if(port < PORTLOW || port >= PORTHIGH) { printf("Port outside range %d\n", port); goto drop; } /* Get the TCP sequence number. */ DEV_GETC(a); seqno[0] = a; DEV_GETC(a); seqno[1] = a; DEV_GETC(a); seqno[2] = a; DEV_GETC(a); seqno[3] = a; /* Next, check the acknowledgement. If it acknowledges outstanding data, we move the state pointer upwards. (This has room for massive assembler optimizations.) Since we never send out any sequence numbers that wrap, we can use standard arithmetic here. */#ifndef STATEFUL stateptr = pages[port - PORTLOW];#endif /* STATEFUL */#ifdef STATEFUL if(tcpstate != LISTEN) {#endif /* STATEFUL */ for(x = 0; x < 4; x ++) { DEV_GETC(a); while(stateptr != NULL && a > stateptr->seqno[x]) { stateptr = stateptr->next;#ifdef STATEFUL y = Y_RESPONSE; inflight--;#endif /* STATEFUL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -