Advertisement
Guest User

Untitled

a guest
Sep 26th, 2013
348
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 60.32 KB | None | 0 0
  1. /*********************************************
  2.  * vim:sw=8:ts=8:si:et
  3.  * To use the above modeline in vim you must have "set modeline" in your .vimrc
  4.  *
  5.  * Author: Guido Socher
  6.  * Copyright:LGPL V2
  7.  * See http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
  8.  *
  9.  * IP, Arp, UDP and TCP functions.
  10.  *
  11.  * The TCP implementation uses some size optimisations which are valid
  12.  * only if all data can be sent in one single packet. This is however
  13.  * not a big limitation for a microcontroller as you will anyhow use
  14.  * small web-pages. The web server must send the entire web page in one
  15.  * packet. The client "web browser" as implemented here can also receive
  16.  * large pages.
  17.  *
  18.  * Chip type           : ATMEGA88/168/328/644 with ENC28J60
  19.  *********************************************/
  20. #include <avr/io.h>
  21. // http://www.nongnu.org/avr-libc/changes-1.8.html:
  22. #define __PROG_TYPES_COMPAT__
  23. #include <avr/pgmspace.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include <stdlib.h>
  27. #include "net.h"
  28. #include "enc28j60.h"
  29. #include "ip_config.h"
  30. #include "../RS/rs232.h"
  31.  
  32. // I use them to debug stuff:
  33. #define LEDOFF PORTB|=(1<<PORTB1)
  34. #define LEDON PORTB&=~(1<<PORTB1)
  35. #define LEDISOFF PORTB&(1<<PORTB1)
  36. //
  37.  
  38.  
  39. static uint8_t macaddr[6];
  40. static uint8_t ipaddr[4]={0,0,0,0};
  41. static uint8_t seqnum=0xa; // my initial tcp sequence number
  42. static void (*icmp_callback)(uint8_t *ip);
  43. //
  44. #if defined (NTP_client) || defined (UDP_client) || defined (TCP_client) || defined (PING_client)
  45. #define ARP_MAC_resolver_client 1
  46. #define ALL_clients 1
  47. #endif
  48. #if defined (WWW_client) || defined (TCP_client)
  49. // just lower byte, the upper byte is TCPCLIENT_SRC_PORT_H:
  50. static uint8_t tcpclient_src_port_l=1;
  51. static uint8_t tcp_fd=0; // a file descriptor, will be encoded into the port
  52. static uint8_t tcp_otherside_ip[4];
  53. static uint8_t tcp_dst_mac[6]; // normally the gateway via which we want to send
  54. static uint8_t tcp_client_state=0;
  55. static uint16_t tcp_client_port=0;
  56. // This function will be called if we ever get a result back from the
  57. // TCP connection to the sever:
  58. // close_connection= your_client_tcp_result_callback(uint8_t fd, uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data){...your code}
  59. // statuscode=0 means the buffer has valid data
  60. static uint8_t (*client_tcp_result_callback)(uint8_t,uint8_t,uint16_t,uint16_t);
  61. // len_of_data_filled_in=your_client_tcp_datafill_callback(uint8_t fd){...your code}
  62. static uint16_t (*client_tcp_datafill_callback)(uint8_t);
  63. #endif
  64.  
  65. #define TCPCLIENT_SRC_PORT_H 11
  66.  
  67. #if defined (WWW_client)
  68. // WWW_client uses TCP_client
  69. #define TCP_client 1
  70. static uint8_t www_fd=0;
  71. static uint8_t browsertype=0; // 0 = get, 1 = post
  72. static void (*client_browser_callback)(uint16_t,uint16_t,uint16_t); // the fields are: uint16_t webstatuscode,uint16_t datapos,uint16_t len; datapos is start of http data and len the the length of that data
  73. static const const char *client_additionalheaderline;
  74. static char *client_postval;
  75. static const const char *client_urlbuf;
  76. static const char *client_urlbuf_var;
  77. static const char *client_hoststr;
  78. static uint8_t *bufptr=0; // ugly workaround for backward compatibility
  79. #endif
  80.  
  81.  
  82. #ifdef ARP_MAC_resolver_client
  83. // This function will be called if we ever get a result back from the
  84. // the arp request we sent out.
  85. void (*client_arp_result_callback)(uint8_t*,uint8_t,uint8_t*);
  86. static int16_t arp_delaycnt=1;
  87. static uint8_t arpip[4];  // IP to find via arp
  88. static uint8_t arpip_state=0; // 0 at poweron, 1=req sent no answer yet, 2=have mac, 8=ready to accept an arp reply
  89. static uint8_t arp_reference_number=0;
  90. #define WGW_INITIAL_ARP 1
  91. #define WGW_HAVE_MAC 2
  92. #define WGW_ACCEPT_ARP_REPLY 8
  93. #endif
  94.  
  95. #ifdef WWW_server
  96. static uint8_t wwwport_l=80; // server port
  97. static uint8_t wwwport_h=0;  // Note: never use same as TCPCLIENT_SRC_PORT_H
  98. static uint16_t info_data_len=0;
  99. #endif
  100.  
  101. #if defined (ALL_clients)
  102. static uint8_t ipnetmask[4]={255,255,255,255};
  103. static uint8_t ipid=0x2; // IP-identification, it works as well if you do not change it but it is better to fill the field, we count this number up and wrap.
  104. const char iphdr[] PROGMEM ={0x45,0,0,0x82,0,0,0x40,0,0x20}; // 0x82 is the total len on ip, 0x20 is ttl (time to live), the second 0,0 is IP-identification and may be changed.
  105. #endif
  106.  
  107. #define CLIENTMSS 750
  108. #define TCP_DATA_START ((uint16_t)TCP_SRC_PORT_H_P+(buf[TCP_HEADER_LEN_P]>>4)*4)
  109. const char arpreqhdr[] PROGMEM ={0,1,8,0,6,4,0,1};
  110. #ifdef NTP_client
  111. const char ntpreqhdr[] PROGMEM ={0xe3,0,4,0xfa,0,1,0,0,0,1};
  112. #endif
  113.  
  114. // The Ip checksum is calculated over the ip header only starting
  115. // with the header length field and a total length of 20 bytes
  116. // unitl ip.dst
  117. // You must set the IP checksum field to zero before you start
  118. // the calculation.
  119. // len for ip is 20.
  120. //
  121. // For UDP/TCP we do not make up the required pseudo header. Instead we
  122. // use the ip.src and ip.dst fields of the real packet:
  123. // The udp checksum calculation starts with the ip.src field
  124. // Ip.src=4bytes,Ip.dst=4 bytes,Udp header=8bytes + data length=16+len
  125. // In other words the len here is 8 + length over which you actually
  126. // want to calculate the checksum.
  127. // You must set the checksum field to zero before you start
  128. // the calculation.
  129. // The same algorithm is also used for udp and tcp checksums.
  130. // len for udp is: 8 + 8 + data length
  131. // len for tcp is: 4+4 + 20 + option len + data length
  132. //
  133. // For more information on how this algorithm works see:
  134. // http://www.netfor2.com/checksum.html
  135. // http://www.msc.uky.edu/ken/cs471/notes/chap3.htm
  136. // The RFC has also a C code example: http://www.faqs.org/rfcs/rfc1071.html
  137. uint16_t checksum(uint8_t *buf, uint16_t len,uint8_t type){
  138.         // type 0=ip , icmp
  139.         //      1=udp
  140.         //      2=tcp
  141.         uint32_t sum = 0;
  142.  
  143.         //if(type==0){    
  144.         //        // do not add anything, standard IP checksum as described above
  145.         //        // Usable for ICMP and IP header
  146.         //}
  147.         if(type==1){
  148.                 sum+=IP_PROTO_UDP_V; // protocol udp
  149.                 // the length here is the length of udp (data+header len)
  150.                 // =length given to this function - (IP.scr+IP.dst length)
  151.                 sum+=len-8; // = real udp len
  152.         }
  153.         if(type==2){
  154.                 sum+=IP_PROTO_TCP_V;
  155.                 // the length here is the length of tcp (data+header len)
  156.                 // =length given to this function - (IP.scr+IP.dst length)
  157.                 sum+=len-8; // = real tcp len
  158.         }
  159.         // build the sum of 16bit words
  160.         while(len >1){
  161.                 sum += 0xFFFF & (((uint32_t)*buf<<8)|*(buf+1));
  162.                 buf+=2;
  163.                 len-=2;
  164.         }
  165.         // if there is a byte left then add it (padded with zero)
  166.         if (len){
  167.                 sum += ((uint32_t)(0xFF & *buf))<<8;
  168.         }
  169.         // now calculate the sum over the bytes in the sum
  170.         // until the result is only 16bit long
  171.         while (sum>>16){
  172.                 sum = (sum & 0xFFFF)+(sum >> 16);
  173.         }
  174.         // build 1's complement:
  175.         return( (uint16_t) sum ^ 0xFFFF);
  176. }
  177.  
  178. void init_mac(uint8_t *mymac){
  179.         if (mymac){
  180.                 memcpy(macaddr,mymac,6);
  181.         }
  182. }
  183.  
  184. #if defined (ALL_clients)
  185. void client_ifconfig(uint8_t *ip,uint8_t *netmask)
  186. {
  187.         uint8_t i;
  188.         if (ip){
  189.                 i=0;while(i<4){ipaddr[i]=ip[i];i++;}
  190.         }
  191.         if (netmask){
  192.                 i=0;while(i<4){ipnetmask[i]=netmask[i];i++;}
  193.         }
  194. }
  195.  
  196. // returns 1 if destip must be routed via the GW. Returns 0 if destip is on the local LAN
  197. uint8_t route_via_gw(uint8_t *destip)
  198. {
  199.     uint8_t i=0;
  200.     while(i<4){
  201.         if ((destip[i] & ipnetmask[i]) != (ipaddr[i] & ipnetmask[i])){
  202.             return(1);
  203.         }
  204.         i++;
  205.     }
  206.     return(0);
  207. }
  208. #endif
  209.  
  210.  
  211. uint8_t check_ip_message_is_from(uint8_t *buf,uint8_t *ip)
  212. {
  213.         uint8_t i=0;
  214.         while(i<4){
  215.                 if(buf[IP_SRC_P+i]!=ip[i]){
  216.                         return(0);
  217.                 }
  218.                 i++;
  219.         }
  220.         return(1);
  221. }
  222.  
  223. uint8_t eth_type_is_arp_and_my_ip(uint8_t *buf,uint16_t len){
  224.         uint8_t i=0;
  225.         //  
  226.         if (len<41){
  227.                 return(0);
  228.         }
  229.         if(buf[ETH_TYPE_H_P] != ETHTYPE_ARP_H_V ||
  230.            buf[ETH_TYPE_L_P] != ETHTYPE_ARP_L_V){
  231.                 return(0);
  232.         }
  233.         while(i<4){
  234.                 if(buf[ETH_ARP_DST_IP_P+i] != ipaddr[i]){
  235.                         return(0);
  236.                 }
  237.                 i++;
  238.         }
  239.         return(1);
  240. }
  241.  
  242. uint8_t eth_type_is_ip_and_my_ip(uint8_t *buf,uint16_t len){
  243.         uint8_t i=0;
  244.         //eth+ip+udp header is 42
  245.         if (len<42){
  246.                 return(0);
  247.         }
  248.         if(buf[ETH_TYPE_H_P]!=ETHTYPE_IP_H_V ||
  249.            buf[ETH_TYPE_L_P]!=ETHTYPE_IP_L_V){
  250.                 return(0);
  251.         }
  252.         if (buf[IP_HEADER_LEN_VER_P]!=0x45){
  253.                 // must be IP V4 and 20 byte header
  254.                 return(0);
  255.         }
  256.         while(i<4){
  257.                 if(buf[IP_DST_P+i]!=ipaddr[i]){
  258.                         return(0);
  259.                 }
  260.                 i++;
  261.         }
  262.         return(1);
  263. }
  264.  
  265. // make a return eth header from a received eth packet
  266. void make_eth(uint8_t *buf)
  267. {
  268.         uint8_t i=0;
  269.         //
  270.         //copy the destination mac from the source and fill my mac into src
  271.         while(i<6){
  272.                 buf[ETH_DST_MAC +i]=buf[ETH_SRC_MAC +i];
  273.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  274.                 i++;
  275.         }
  276. }
  277. void fill_ip_hdr_checksum(uint8_t *buf)
  278. {
  279.         uint16_t ck;
  280.         // clear the 2 byte checksum
  281.         buf[IP_CHECKSUM_P]=0;
  282.         buf[IP_CHECKSUM_P+1]=0;
  283.         buf[IP_FLAGS_P]=0x40; // don't fragment
  284.         buf[IP_FLAGS_P+1]=0;  // fragement offset
  285.         buf[IP_TTL_P]=64; // ttl
  286.         // calculate the checksum:
  287.         ck=checksum(&buf[IP_P], IP_HEADER_LEN,0);
  288.         buf[IP_CHECKSUM_P]=ck>>8;
  289.         buf[IP_CHECKSUM_P+1]=ck& 0xff;
  290. }
  291.  
  292. // make a return ip header from a received ip packet
  293. void make_ip(uint8_t *buf)
  294. {
  295.         uint8_t i=0;
  296.         while(i<4){
  297.                 buf[IP_DST_P+i]=buf[IP_SRC_P+i];
  298.                 buf[IP_SRC_P+i]=ipaddr[i];
  299.                 i++;
  300.         }
  301.         fill_ip_hdr_checksum(buf);
  302. }
  303.  
  304. // swap seq and ack number and count ack number up
  305. void step_seq(uint8_t *buf,uint16_t rel_ack_num,uint8_t cp_seq)
  306. {
  307.         uint8_t i;
  308.         uint8_t tseq;
  309.         i=4;
  310.         // sequence numbers:
  311.         // add the rel ack num to SEQACK
  312.         while(i>0){
  313.                 rel_ack_num=buf[TCP_SEQ_H_P+i-1]+rel_ack_num;
  314.                 tseq=buf[TCP_SEQACK_H_P+i-1];
  315.                 buf[TCP_SEQACK_H_P+i-1]=0xff&rel_ack_num;
  316.                 if (cp_seq){
  317.                         // copy the acknum sent to us into the sequence number
  318.                         buf[TCP_SEQ_H_P+i-1]=tseq;
  319.                 }else{
  320.                         buf[TCP_SEQ_H_P+i-1]= 0; // some preset value
  321.                 }
  322.                 rel_ack_num=rel_ack_num>>8;
  323.                 i--;
  324.         }
  325. }
  326.  
  327. // make a return tcp header from a received tcp packet
  328. // rel_ack_num is how much we must step the seq number received from the
  329. // other side. We do not send more than 765 bytes of text (=data) in the tcp packet.
  330. // No mss is included here.
  331. //
  332. // After calling this function you can fill in the first data byte at TCP_OPTIONS_P+4
  333. // If cp_seq=0 then an initial sequence number is used (should be use in synack)
  334. // otherwise it is copied from the packet we received
  335. void make_tcphead(uint8_t *buf,uint16_t rel_ack_num,uint8_t cp_seq)
  336. {
  337.         uint8_t i;
  338.         // copy ports:
  339.         i=buf[TCP_DST_PORT_H_P];
  340.         buf[TCP_DST_PORT_H_P]=buf[TCP_SRC_PORT_H_P];
  341.         buf[TCP_SRC_PORT_H_P]=i;
  342.         //
  343.         i=buf[TCP_DST_PORT_L_P];
  344.         buf[TCP_DST_PORT_L_P]=buf[TCP_SRC_PORT_L_P];
  345.         buf[TCP_SRC_PORT_L_P]=i;
  346.         step_seq(buf,rel_ack_num,cp_seq);
  347.         // zero the checksum
  348.         buf[TCP_CHECKSUM_H_P]=0;
  349.         buf[TCP_CHECKSUM_L_P]=0;
  350.         // no options:
  351.         // 20 bytes:
  352.         // The tcp header length is only a 4 bit field (the upper 4 bits).
  353.         // It is calculated in units of 4 bytes.
  354.         // E.g 20 bytes: 20/4=6 => 0x50=header len field
  355.         buf[TCP_HEADER_LEN_P]=0x50;
  356. }
  357.  
  358. void make_arp_answer_from_request(uint8_t *buf)
  359. {
  360.         uint8_t i=0;
  361.         //
  362.         make_eth(buf);
  363.         buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V;
  364.         buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V;
  365.         // fill the mac addresses:
  366.         while(i<6){
  367.                 buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i];
  368.                 buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i];
  369.                 i++;
  370.         }
  371.         i=0;
  372.         while(i<4){
  373.                 buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i];
  374.                 buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
  375.                 i++;
  376.         }
  377.         // eth+arp is 42 bytes:
  378.         enc28j60PacketSend(42,buf);
  379. }
  380.  
  381. void make_echo_reply_from_request(uint8_t *buf,uint16_t len)
  382. {
  383.         make_eth(buf);
  384.         make_ip(buf);
  385.         buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;
  386.         // we changed only the icmp.type field from request(=8) to reply(=0).
  387.         // we can therefore easily correct the checksum:
  388.         if (buf[ICMP_CHECKSUM_P] > (0xff-0x08)){
  389.                 buf[ICMP_CHECKSUM_P+1]++;
  390.         }
  391.         buf[ICMP_CHECKSUM_P]+=0x08;
  392.         //
  393.         enc28j60PacketSend(len,buf);
  394. }
  395.  
  396. // do some basic length calculations
  397. uint16_t get_tcp_data_len(uint8_t *buf)
  398. {
  399.         int16_t i;
  400.         i=(((int16_t)buf[IP_TOTLEN_H_P])<<8)|(buf[IP_TOTLEN_L_P]&0xff);
  401.         i-=IP_HEADER_LEN;
  402.         i-=(buf[TCP_HEADER_LEN_P]>>4)*4; // generate len in bytes;
  403.         if (i<=0){
  404.                 i=0;
  405.         }
  406.         return((uint16_t)i);
  407. }
  408.  
  409.  
  410. // fill in tcp data at position pos. pos=0 means start of
  411. // tcp data. Returns the position at which the string after
  412. // this string could be filled.
  413. uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const const char *progmem_s)
  414. {
  415.         char c;
  416.         // fill in tcp data at position pos
  417.         //
  418.         // with no options the data starts after the checksum + 2 more bytes (urgent ptr)
  419.         while ((c = pgm_read_byte(progmem_s++))) {
  420.                 buf[TCP_CHECKSUM_L_P+3+pos]=c;
  421.                 pos++;
  422.         }
  423.         return(pos);
  424. }
  425.  
  426. // fill a binary string of len data into the tcp packet
  427. uint16_t fill_tcp_data_len(uint8_t *buf,uint16_t pos, const uint8_t *s, uint8_t len)
  428. {
  429.         // fill in tcp data at position pos
  430.         //
  431.         // with no options the data starts after the checksum + 2 more bytes (urgent ptr)
  432.         while (len) {
  433.                 buf[TCP_CHECKSUM_L_P+3+pos]=*s;
  434.                 pos++;
  435.                 s++;
  436.                 len--;
  437.         }
  438.         return(pos);
  439. }
  440.  
  441. // fill in tcp data at position pos. pos=0 means start of
  442. // tcp data. Returns the position at which the string after
  443. // this string could be filled.
  444. uint16_t fill_tcp_data(uint8_t *buf,uint16_t pos, const char *s)
  445. {
  446.         return(fill_tcp_data_len(buf,pos,(uint8_t*)s,strlen(s)));
  447. }
  448.  
  449. // Make just an ack packet with no tcp data inside
  450. // This will modify the eth/ip/tcp header
  451. void make_tcp_ack_from_any(uint8_t *buf,int16_t datlentoack,uint8_t addflags)
  452. {
  453.         uint16_t j;
  454.         make_eth(buf);
  455.         // fill the header:
  456.         buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|addflags;
  457.         if (addflags==TCP_FLAGS_RST_V){
  458.                 make_tcphead(buf,datlentoack,1);
  459.         }else{
  460.                 if (datlentoack==0){
  461.                         // if there is no data then we must still acknoledge one packet
  462.                         datlentoack=1;
  463.                 }
  464.                 // normal case, ack the data:
  465.                 make_tcphead(buf,datlentoack,1); // no options
  466.         }
  467.         // total length field in the IP header must be set:
  468.         // 20 bytes IP + 20 bytes tcp (when no options)
  469.         j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
  470.         buf[IP_TOTLEN_H_P]=j>>8;
  471.         buf[IP_TOTLEN_L_P]=j& 0xff;
  472.         make_ip(buf);
  473.         // use a low window size otherwise we have to have
  474.         // timers and can not just react on every packet.
  475.         buf[TCP_WIN_SIZE]=0x4; // 1024=0x400, 1280=0x500 2048=0x800 768=0x300
  476.         buf[TCP_WIN_SIZE+1]=0;
  477.         // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
  478.         j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
  479.         buf[TCP_CHECKSUM_H_P]=j>>8;
  480.         buf[TCP_CHECKSUM_L_P]=j& 0xff;
  481.         enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
  482. }
  483.  
  484.  
  485. // dlen is the amount of tcp data (http data) we send in this packet
  486. // You can use this function only immediately after make_tcp_ack_from_any
  487. // This is because this function will NOT modify the eth/ip/tcp header except for
  488. // length and checksum
  489. // You must set TCP_FLAGS before calling this
  490. void make_tcp_ack_with_data_noflags(uint8_t *buf,uint16_t dlen)
  491. {
  492.         uint16_t j;
  493.         // total length field in the IP header must be set:
  494.         // 20 bytes IP + 20 bytes tcp (when no options) + len of data
  495.         j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
  496.         buf[IP_TOTLEN_H_P]=j>>8;
  497.         buf[IP_TOTLEN_L_P]=j& 0xff;
  498.         fill_ip_hdr_checksum(buf);
  499.         // zero the checksum
  500.         buf[TCP_CHECKSUM_H_P]=0;
  501.         buf[TCP_CHECKSUM_L_P]=0;
  502.         // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len
  503.         j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlen,2);
  504.         buf[TCP_CHECKSUM_H_P]=j>>8;
  505.         buf[TCP_CHECKSUM_L_P]=j& 0xff;
  506.         enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN,buf);
  507. }
  508.  
  509. #if defined (UDP_server)
  510. // a udp server
  511. void make_udp_reply_from_request_udpdat_ready(uint8_t *buf,uint16_t datalen,uint16_t port)
  512. {
  513.         uint16_t j;
  514.         make_eth(buf);
  515.         if (datalen>220){
  516.                 datalen=220;
  517.         }
  518.         // total length field in the IP header must be set:
  519.         j=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
  520.         buf[IP_TOTLEN_H_P]=j>>8;
  521.         buf[IP_TOTLEN_L_P]=j& 0xff;
  522.         make_ip(buf);
  523.         // send to port:
  524.         //buf[UDP_DST_PORT_H_P]=port>>8;
  525.         //buf[UDP_DST_PORT_L_P]=port & 0xff;
  526.         // sent to port of sender and use "port" as own source:
  527.         buf[UDP_DST_PORT_H_P]=buf[UDP_SRC_PORT_H_P];
  528.         buf[UDP_DST_PORT_L_P]= buf[UDP_SRC_PORT_L_P];
  529.         buf[UDP_SRC_PORT_H_P]=port>>8;
  530.         buf[UDP_SRC_PORT_L_P]=port & 0xff;
  531.         // calculte the udp length:
  532.         j=UDP_HEADER_LEN+datalen;
  533.         buf[UDP_LEN_H_P]=j>>8;
  534.         buf[UDP_LEN_L_P]=j& 0xff;
  535.         // zero the checksum
  536.         buf[UDP_CHECKSUM_H_P]=0;
  537.         buf[UDP_CHECKSUM_L_P]=0;
  538.         j=checksum(&buf[IP_SRC_P], 16 + datalen,1);
  539.         buf[UDP_CHECKSUM_H_P]=j>>8;
  540.         buf[UDP_CHECKSUM_L_P]=j& 0xff;
  541.         enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
  542. }
  543.  
  544. // you can send a max of 220 bytes of data because we use only one
  545. // byte for the data but udp messages are normally small.
  546. void make_udp_reply_from_request(uint8_t *buf,char *data,uint8_t datalen,uint16_t port)
  547. {
  548.         uint8_t i=0;
  549.         // copy the data:
  550.         while(i<datalen){
  551.                 buf[UDP_DATA_P+i]=data[i];
  552.                 i++;
  553.         }
  554.         make_udp_reply_from_request_udpdat_ready(buf,datalen,port);
  555. }
  556.  
  557. #endif // UDP_server
  558.  
  559. #if defined (UDP_server) || defined (WWW_server)
  560. // This initializes server
  561. // you must call this function once before you use any of the other functions:
  562. // mymac may be NULL and can be used if you did already call init_mac
  563. void init_udp_or_www_server(uint8_t *mymac,uint8_t *myip){
  564.         uint8_t i=0;
  565.         if (myip){
  566.                 while(i<4){
  567.                         ipaddr[i]=myip[i];
  568.                         i++;
  569.                 }
  570.         }
  571.         if (mymac) init_mac(mymac);
  572. }
  573. #endif // UDP_server || WWW_server
  574.  
  575. #ifdef WWW_server
  576. // not needed if you want port 80 (the default is port 80):
  577. void www_server_port(uint16_t port){
  578.         wwwport_h=(port>>8)&0xff;
  579.         wwwport_l=(port&0xff);
  580. }
  581.  
  582. // this is for the server not the client:
  583. void make_tcp_synack_from_syn(uint8_t *buf)
  584. {
  585.         uint16_t ck;
  586.         make_eth(buf);
  587.         // total length field in the IP header must be set:
  588.         // 20 bytes IP + 24 bytes (20tcp+4tcp options)
  589.         buf[IP_TOTLEN_H_P]=0;
  590.         buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
  591.         make_ip(buf);
  592.         buf[TCP_FLAGS_P]=TCP_FLAGS_SYNACK_V;
  593.         make_tcphead(buf,1,0);
  594.         // put an inital seq number
  595.         buf[TCP_SEQ_H_P+0]= 0;
  596.         buf[TCP_SEQ_H_P+1]= 0;
  597.         // we step only the second byte, this allows us to send packts
  598.         // with 255 bytes, 512  or 765 (step by 3) without generating
  599.         // overlapping numbers.
  600.         buf[TCP_SEQ_H_P+2]= seqnum;
  601.         buf[TCP_SEQ_H_P+3]= 0;
  602.         // step the inititial seq num by something we will not use
  603.         // during this tcp session:
  604.         seqnum+=3;
  605.         // add an mss options field with MSS to 1280:
  606.         // 1280 in hex is 0x500
  607.         buf[TCP_OPTIONS_P]=2;
  608.         buf[TCP_OPTIONS_P+1]=4;
  609.         buf[TCP_OPTIONS_P+2]=0x05;
  610.         buf[TCP_OPTIONS_P+3]=0x0;
  611.         // The tcp header length is only a 4 bit field (the upper 4 bits).
  612.         // It is calculated in units of 4 bytes.
  613.         // E.g 24 bytes: 24/4=6 => 0x60=header len field
  614.         buf[TCP_HEADER_LEN_P]=0x60;
  615.         // here we must just be sure that the web browser contacting us
  616.         // will send only one get packet
  617.         buf[TCP_WIN_SIZE]=0x0a; // was 1400=0x578, 2560=0xa00 suggested by Andras Tucsni to be able to receive bigger packets
  618.         buf[TCP_WIN_SIZE+1]=0; //
  619.         // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + 4 (one option: mss)
  620.         ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2);
  621.         buf[TCP_CHECKSUM_H_P]=ck>>8;
  622.         buf[TCP_CHECKSUM_L_P]=ck& 0xff;
  623.         // add 4 for option mss:
  624.         enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
  625. }
  626.  
  627. // you must have initialized info_data_len at some time before calling this function
  628. //
  629. // This info_data_len initialisation is done automatically if you call
  630. // packetloop_icmp_tcp(buf,enc28j60PacketReceive(BUFFER_SIZE, buf));
  631. // and test the return value for non zero.
  632. //
  633. // dlen is the amount of tcp data (http data) we send in this packet
  634. // You can use this function only immediately after make_tcp_ack_from_any
  635. // This is because this function will NOT modify the eth/ip/tcp header except for
  636. // length and checksum
  637. void www_server_reply(uint8_t *buf,uint16_t dlen)
  638. {
  639.         make_tcp_ack_from_any(buf,info_data_len,0); // send ack for http get
  640.         // fill the header:
  641.         // This code requires that we send only one data packet
  642.         // because we keep no state information. We must therefore set
  643.         // the fin here:
  644.         buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V;
  645.         make_tcp_ack_with_data_noflags(buf,dlen); // send data
  646. }
  647.  
  648. #endif // WWW_server
  649.  
  650. #if defined (ALL_clients)
  651. // fill buffer with a prog-mem string
  652. void fill_buf_p(uint8_t *buf,uint16_t len, const const char *progmem_s)
  653. {
  654.         while (len){
  655.                 *buf= pgm_read_byte(progmem_s);
  656.                 buf++;
  657.                 progmem_s++;
  658.                 len--;
  659.         }
  660. }
  661. #endif
  662.  
  663. #ifdef PING_client
  664. // icmp echo, matchpat is a pattern that has to be sent back by the
  665. // host answering the ping.
  666. // The ping is sent to destip  and mac dstmac
  667. void client_icmp_request(uint8_t *buf,uint8_t *destip,uint8_t *dstmac)
  668. {
  669.         uint8_t i=0;
  670.         uint16_t ck;
  671.         //
  672.         while(i<6){
  673.                 buf[ETH_DST_MAC +i]=dstmac[i]; // gw mac in local lan or host mac
  674.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  675.                 i++;
  676.         }
  677.         buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
  678.         buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
  679.         fill_buf_p(&buf[IP_P],9,iphdr);
  680.         buf[IP_ID_L_P]=ipid; ipid++;
  681.         buf[IP_TOTLEN_L_P]=0x54;
  682.         buf[IP_PROTO_P]=IP_PROTO_ICMP_V;
  683.         i=0;
  684.         while(i<4){
  685.                 buf[IP_DST_P+i]=destip[i];
  686.                 buf[IP_SRC_P+i]=ipaddr[i];
  687.                 i++;
  688.         }
  689.         fill_ip_hdr_checksum(buf);
  690.         buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREQUEST_V;
  691.         buf[ICMP_TYPE_P+1]=0; // code
  692.         // zero the checksum
  693.         buf[ICMP_CHECKSUM_H_P]=0;
  694.         buf[ICMP_CHECKSUM_L_P]=0;
  695.         // a possibly unique id of this host:
  696.         buf[ICMP_IDENT_H_P]=5; // some number
  697.         buf[ICMP_IDENT_L_P]=ipaddr[3]; // last byte of my IP
  698.         //
  699.         buf[ICMP_IDENT_L_P+1]=0; // seq number, high byte
  700.         buf[ICMP_IDENT_L_P+2]=1; // seq number, low byte, we send only 1 ping at a time
  701.         // copy the data:
  702.         i=0;
  703.         while(i<56){
  704.                 buf[ICMP_DATA_P+i]=PINGPATTERN;
  705.                 i++;
  706.         }
  707.         //
  708.         ck=checksum(&buf[ICMP_TYPE_P], 56+8,0);
  709.         buf[ICMP_CHECKSUM_H_P]=ck>>8;
  710.         buf[ICMP_CHECKSUM_L_P]=ck& 0xff;
  711.         enc28j60PacketSend(98,buf);
  712. }
  713. #endif // PING_client
  714.  
  715.  
  716. #ifdef NTP_client
  717. // ntp udp packet
  718. // See http://tools.ietf.org/html/rfc958 for details
  719. //
  720. void client_ntp_request(uint8_t *buf,uint8_t *ntpip,uint8_t srcport,uint8_t *dstmac)
  721. {
  722.         uint8_t i=0;
  723.         uint16_t ck;
  724.         if (!enc28j60linkup())return;
  725.         //
  726.         while(i<6){
  727.                 buf[ETH_DST_MAC +i]=dstmac[i]; // gw mac in local lan or host mac
  728.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  729.                 i++;
  730.         }
  731.         buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
  732.         buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
  733.         fill_buf_p(&buf[IP_P],9,iphdr);
  734.         buf[IP_ID_L_P]=ipid; ipid++;
  735.         buf[IP_TOTLEN_L_P]=0x4c;
  736.         buf[IP_PROTO_P]=IP_PROTO_UDP_V;
  737.         i=0;
  738.         while(i<4){
  739.                 buf[IP_DST_P+i]=ntpip[i];
  740.                 buf[IP_SRC_P+i]=ipaddr[i];
  741.                 i++;
  742.         }
  743.         fill_ip_hdr_checksum(buf);
  744.         buf[UDP_DST_PORT_H_P]=0;
  745.         buf[UDP_DST_PORT_L_P]=0x7b; // ntp=123
  746.         buf[UDP_SRC_PORT_H_P]=10;
  747.         buf[UDP_SRC_PORT_L_P]=srcport; // lower 8 bit of src port
  748.         buf[UDP_LEN_H_P]=0;
  749.         buf[UDP_LEN_L_P]=56; // fixed len
  750.         // zero the checksum
  751.         buf[UDP_CHECKSUM_H_P]=0;
  752.         buf[UDP_CHECKSUM_L_P]=0;
  753.         // copy the data:
  754.         i=0;
  755.         // most fields are zero, here we zero everything and fill later
  756.         while(i<48){
  757.                 buf[UDP_DATA_P+i]=0;
  758.                 i++;
  759.         }
  760.         fill_buf_p(&buf[UDP_DATA_P],10,ntpreqhdr);
  761.         //
  762.         ck=checksum(&buf[IP_SRC_P], 16 + 48,1);
  763.         buf[UDP_CHECKSUM_H_P]=ck>>8;
  764.         buf[UDP_CHECKSUM_L_P]=ck& 0xff;
  765.         enc28j60PacketSend(90,buf);
  766. }
  767. // process the answer from the ntp server:
  768. // if dstport==0 then accept any port otherwise only answers going to dstport
  769. // return 1 on sucessful processing of answer
  770. uint8_t client_ntp_process_answer(uint8_t *buf,uint32_t *time,uint8_t dstport_l){
  771.         if (dstport_l){
  772.                 if (buf[UDP_DST_PORT_L_P]!=dstport_l){
  773.                         return(0);
  774.                 }
  775.         }
  776.         if (buf[UDP_LEN_H_P]!=0 || buf[UDP_LEN_L_P]!=56 || buf[UDP_SRC_PORT_L_P]!=0x7b){
  777.                 // not ntp
  778.                 return(0);
  779.         }
  780.         // copy time from the transmit time stamp field:
  781.         *time=((uint32_t)buf[0x52]<<24)|((uint32_t)buf[0x53]<<16)|((uint32_t)buf[0x54]<<8)|((uint32_t)buf[0x55]);
  782.         return(1);
  783. }
  784. #endif
  785.  
  786. #ifdef UDP_client
  787. // -------------------- send a spontanious UDP packet to a server
  788. // There are two ways of using this:
  789. // 1) you call send_udp_prepare, you fill the data yourself into buf starting at buf[UDP_DATA_P],
  790. // you send the packet by calling send_udp_transmit
  791. //
  792. // 2) You just allocate a large enough buffer for you data and you call send_udp and nothing else
  793. // needs to be done.
  794. //
  795. void send_udp_prepare(uint8_t *buf,uint16_t sport, const uint8_t *dip, uint16_t dport,const uint8_t *dstmac)
  796. {
  797.         uint8_t i=0;
  798.         //
  799.         while(i<6){
  800.                 buf[ETH_DST_MAC +i]=dstmac[i]; // gw mac in local lan or host mac
  801.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  802.                 i++;
  803.         }
  804.         buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
  805.         buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
  806.         fill_buf_p(&buf[IP_P],9,iphdr);
  807.         buf[IP_ID_L_P]=ipid; ipid++;
  808.         // total length field in the IP header must be set:
  809.         buf[IP_TOTLEN_H_P]=0;
  810.         // done in transmit: buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
  811.         buf[IP_PROTO_P]=IP_PROTO_UDP_V;
  812.         i=0;
  813.         while(i<4){
  814.                 buf[IP_DST_P+i]=dip[i];
  815.                 buf[IP_SRC_P+i]=ipaddr[i];
  816.                 i++;
  817.         }
  818.         // done in transmit: fill_ip_hdr_checksum(buf);
  819.         buf[UDP_DST_PORT_H_P]=(dport>>8);
  820.         buf[UDP_DST_PORT_L_P]=0xff&dport;
  821.         buf[UDP_SRC_PORT_H_P]=(sport>>8);
  822.         buf[UDP_SRC_PORT_L_P]=sport&0xff;
  823.         buf[UDP_LEN_H_P]=0;
  824.         // done in transmit: buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
  825.         // zero the checksum
  826.         buf[UDP_CHECKSUM_H_P]=0;
  827.         buf[UDP_CHECKSUM_L_P]=0;
  828.         // copy the data:
  829.         // now starting with the first byte at buf[UDP_DATA_P]
  830.         //
  831. }
  832.  
  833. void send_udp_transmit(uint8_t *buf,uint16_t datalen)
  834. {
  835.         uint16_t tmp16;
  836.         tmp16=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
  837.         buf[IP_TOTLEN_L_P]=tmp16& 0xff;
  838.         buf[IP_TOTLEN_H_P]=tmp16>>8;
  839.         fill_ip_hdr_checksum(buf);
  840.         tmp16=UDP_HEADER_LEN+datalen;
  841.         buf[UDP_LEN_L_P]=tmp16& 0xff;
  842.         buf[UDP_LEN_H_P]=tmp16>>8;
  843.         //
  844.         tmp16=checksum(&buf[IP_SRC_P], 16 + datalen,1);
  845.         buf[UDP_CHECKSUM_L_P]=tmp16& 0xff;
  846.         buf[UDP_CHECKSUM_H_P]=tmp16>>8;
  847.         enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
  848. }
  849.  
  850. void send_udp(uint8_t *buf,char *data,uint8_t datalen,uint16_t sport, const uint8_t *dip, uint16_t dport,const uint8_t *dstmac)
  851. {
  852.         send_udp_prepare(buf,sport, dip, dport,dstmac);
  853.         uint8_t i=0;
  854.         // limit the length:
  855.         if (datalen>220){
  856.                 datalen=220;
  857.         }
  858.         // copy the data:
  859.         i=0;
  860.         while(i<datalen){
  861.                 buf[UDP_DATA_P+i]=data[i];
  862.                 i++;
  863.         }
  864.         //
  865.         send_udp_transmit(buf,datalen);
  866. }
  867. #endif // UDP_client
  868.  
  869. #ifdef WOL_client
  870. // -------------------- special code to make a WOL packet
  871.  
  872. // A WOL (Wake on Lan) packet is a UDP packet to the broadcast
  873. // address and UDP port 9. The data part contains 6x FF followed by
  874. // 16 times the mac address of the host to wake-up
  875. //
  876. void send_wol(uint8_t *buf,uint8_t *wolmac)
  877. {
  878.         uint8_t i=0;
  879.         uint8_t m=0;
  880.         uint8_t pos=0;
  881.         uint16_t ck;
  882.         //
  883.         while(i<6){
  884.                 buf[ETH_DST_MAC +i]=0xff;
  885.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  886.                 i++;
  887.         }
  888.         buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
  889.         buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
  890.         fill_buf_p(&buf[IP_P],9,iphdr);
  891.         buf[IP_ID_L_P]=ipid; ipid++;
  892.         buf[IP_TOTLEN_L_P]=0x82; //  fixed len
  893.         buf[IP_PROTO_P]=IP_PROTO_UDP_V; // wol uses udp
  894.         i=0;
  895.         while(i<4){
  896.                 buf[IP_SRC_P+i]=ipaddr[i];
  897.                 buf[IP_DST_P+i]=0xff;
  898.                 i++;
  899.         }
  900.         fill_ip_hdr_checksum(buf);
  901.         buf[UDP_DST_PORT_H_P]=0;
  902.         buf[UDP_DST_PORT_L_P]=0x9; // wol=normally 9
  903.         buf[UDP_SRC_PORT_H_P]=10;
  904.         buf[UDP_SRC_PORT_L_P]=0x42; // source port does not matter
  905.         buf[UDP_LEN_H_P]=0;
  906.         buf[UDP_LEN_L_P]=110; // fixed len
  907.         // zero the checksum
  908.         buf[UDP_CHECKSUM_H_P]=0;
  909.         buf[UDP_CHECKSUM_L_P]=0;
  910.         // copy the data (102 bytes):
  911.         i=0;
  912.         while(i<6){
  913.                 buf[UDP_DATA_P+i]=0xff;
  914.                 i++;
  915.         }
  916.         m=0;
  917.         pos=UDP_DATA_P+6;
  918.         while (m<16){
  919.                 i=0;
  920.                 while(i<6){
  921.                         buf[pos]=wolmac[i];
  922.                         i++;
  923.                         pos++;
  924.                 }
  925.                 m++;
  926.         }
  927.         //
  928.         ck=checksum(&buf[IP_SRC_P], 16+ 102,1);
  929.         buf[UDP_CHECKSUM_H_P]=ck>>8;
  930.         buf[UDP_CHECKSUM_L_P]=ck& 0xff;
  931.         enc28j60PacketSend(pos,buf);
  932. }
  933. #endif // WOL_client
  934.  
  935. #if defined GRATARP
  936. // Send a Gratuitous arp, this is to refresh the arp
  937. // cash of routers and switches. It can improve the response
  938. // time in wifi networks as some wifi equipment expects the initial
  939. // communication to not start from the network side. That is wrong
  940. // but some consumer devices are made like this.
  941. //
  942. // A Gratuitous ARP can be a request or a reply.
  943. // A request frame is as well called Unsolicited ARP
  944. uint8_t gratutious_arp(uint8_t *buf)
  945. {
  946.         uint8_t i=0;
  947.         if (!enc28j60linkup()){
  948.                 return(0);
  949.         }
  950.         //
  951.         while(i<6){
  952.                 buf[ETH_DST_MAC +i]=0xff;
  953.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  954.                 i++;
  955.         }
  956.         buf[ETH_TYPE_H_P] = ETHTYPE_ARP_H_V;
  957.         buf[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V;
  958.         // arp request and reply are the same execept for
  959.         // the opcode:
  960.         fill_buf_p(&buf[ETH_ARP_P],8,arpreqhdr);
  961.         //buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V; // reply
  962.         i=0;
  963.         while(i<6){
  964.                 buf[ETH_ARP_SRC_MAC_P +i]=macaddr[i];
  965.                 buf[ETH_ARP_DST_MAC_P+i]=0xff;
  966.                 i++;
  967.         }
  968.         i=0;
  969.         while(i<4){
  970.                 buf[ETH_ARP_DST_IP_P+i]=ipaddr[i];
  971.                 buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
  972.                 i++;
  973.         }
  974.         // 0x2a=42=len of packet
  975.         enc28j60PacketSend(0x2a,buf);
  976.         return(1);
  977. }
  978. #endif // GRATARP
  979.  
  980. #if ARP_MAC_resolver_client
  981. // make a arp request
  982. // Note: you must have initialized the stack with
  983. // init_udp_or_www_server or client_ifconfig
  984. // before you can use this function
  985. void client_arp_whohas(uint8_t *buf,uint8_t *ip_we_search)
  986. {
  987.         uint8_t i=0;
  988.         if (ipaddr[0]==0) return; // error ipaddr not set
  989.         //
  990.         while(i<6){
  991.                 buf[ETH_DST_MAC +i]=0xff;
  992.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  993.                 i++;
  994.         }
  995.         buf[ETH_TYPE_H_P] = ETHTYPE_ARP_H_V;
  996.         buf[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V;
  997.         fill_buf_p(&buf[ETH_ARP_P],8,arpreqhdr);
  998.         i=0;
  999.         while(i<6){
  1000.                 buf[ETH_ARP_SRC_MAC_P +i]=macaddr[i];
  1001.                 buf[ETH_ARP_DST_MAC_P+i]=0;
  1002.                 i++;
  1003.         }
  1004.         i=0;
  1005.         while(i<4){
  1006.                 buf[ETH_ARP_DST_IP_P+i]=*(ip_we_search +i);
  1007.                 buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
  1008.                 i++;
  1009.         }
  1010.         // 0x2a=42=len of packet
  1011.         enc28j60PacketSend(0x2a,buf);
  1012. }
  1013.  
  1014. // return zero when current transaction is finished
  1015. uint8_t get_mac_with_arp_wait(void)
  1016. {
  1017.         if (arpip_state == WGW_HAVE_MAC){
  1018.                 return(0);
  1019.         }
  1020.         return(1);
  1021. }
  1022.  
  1023. // reference_number is something that is just returned in the callback
  1024. // to make matching and waiting for a given ip/mac address pair easier
  1025. // Note: you must have initialized the stack with
  1026. // init_udp_or_www_server or client_ifconfig
  1027. // before you can use this function
  1028. void get_mac_with_arp(uint8_t *ip, uint8_t reference_number,void (*arp_result_callback)(uint8_t *ip,uint8_t reference_number,uint8_t *mac))
  1029. {
  1030.         uint8_t i=0;
  1031.         client_arp_result_callback=arp_result_callback;
  1032.         arpip_state=WGW_INITIAL_ARP; // causes an arp request in the packet loop
  1033.         arp_reference_number=reference_number;
  1034.         while(i<4){
  1035.                 arpip[i]=ip[i];
  1036.                 i++;
  1037.         }
  1038. }
  1039. #endif
  1040.  
  1041. #if defined (TCP_client)
  1042. // Make a tcp syn packet
  1043. void tcp_client_syn(uint8_t *buf,uint8_t srcport,uint16_t dstport)
  1044. {
  1045.         uint16_t ck;
  1046.         uint8_t i=0;
  1047.         // -- make the main part of the eth/IP/tcp header:
  1048.         while(i<6){
  1049.                 buf[ETH_DST_MAC +i]=tcp_dst_mac[i]; // gw mac in local lan or host mac
  1050.                 buf[ETH_SRC_MAC +i]=macaddr[i];
  1051.                 i++;
  1052.         }
  1053.         buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
  1054.         buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
  1055.         fill_buf_p(&buf[IP_P],9,iphdr);
  1056.         buf[IP_TOTLEN_L_P]=44; // good for syn
  1057.         buf[IP_ID_L_P]=ipid; ipid++;
  1058.         buf[IP_PROTO_P]=IP_PROTO_TCP_V;
  1059.         i=0;
  1060.         while(i<4){
  1061.                 buf[IP_DST_P+i]=tcp_otherside_ip[i];
  1062.                 buf[IP_SRC_P+i]=ipaddr[i];
  1063.                 i++;
  1064.         }
  1065.         fill_ip_hdr_checksum(buf);
  1066.         buf[TCP_DST_PORT_H_P]=(dstport>>8)&0xff;
  1067.         buf[TCP_DST_PORT_L_P]=(dstport&0xff);
  1068.         buf[TCP_SRC_PORT_H_P]=TCPCLIENT_SRC_PORT_H;
  1069.         buf[TCP_SRC_PORT_L_P]=srcport; // lower 8 bit of src port
  1070.         i=0;
  1071.         // zero out sequence number and acknowledgement number
  1072.         while(i<8){
  1073.                 buf[TCP_SEQ_H_P+i]=0;
  1074.                 i++;
  1075.         }
  1076.         // -- header ready
  1077.         // put inital seq number
  1078.         // we step only the second byte, this allows us to send packts
  1079.         // with 255 bytes 512 (if we step the initial seqnum by 2)
  1080.         // or 765 (step by 3)
  1081.         buf[TCP_SEQ_H_P+2]= seqnum;
  1082.         // step the inititial seq num by something we will not use
  1083.         // during this tcp session:
  1084.         seqnum+=3;
  1085.         buf[TCP_HEADER_LEN_P]=0x60; // 0x60=24 len: (0x60>>4) * 4
  1086.         buf[TCP_FLAGS_P]=TCP_FLAGS_SYN_V;
  1087.         // use a low window size otherwise we have to have
  1088.         // timers and can not just react on every packet.
  1089.         buf[TCP_WIN_SIZE]=0x3; // 1024=0x400 768=0x300, initial window
  1090.         buf[TCP_WIN_SIZE+1]=0x0;
  1091.         // zero the checksum
  1092.         buf[TCP_CHECKSUM_H_P]=0;
  1093.         buf[TCP_CHECKSUM_L_P]=0;
  1094.         // urgent pointer
  1095.         buf[TCP_CHECKSUM_L_P+1]=0;
  1096.         buf[TCP_CHECKSUM_L_P+2]=0;
  1097.         // MSS= max IP len that we want to have:
  1098.         buf[TCP_OPTIONS_P]=2;
  1099.         buf[TCP_OPTIONS_P+1]=4;
  1100.         buf[TCP_OPTIONS_P+2]=(CLIENTMSS>>8);
  1101.         buf[TCP_OPTIONS_P+3]=CLIENTMSS & 0xff;
  1102.         ck=checksum(&buf[IP_SRC_P], 8 +TCP_HEADER_LEN_PLAIN+4,2);
  1103.         buf[TCP_CHECKSUM_H_P]=ck>>8;
  1104.         buf[TCP_CHECKSUM_L_P]=ck& 0xff;
  1105.         // 4 is the tcp mss option:
  1106.         enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN+4,buf);
  1107. }
  1108. #endif // TCP_client
  1109.  
  1110. #if defined (TCP_client)
  1111. // This is how to use the tcp client:
  1112. //
  1113. // Declare a callback function to get the result (tcp data from the server):
  1114. //
  1115. // uint8_t your_client_tcp_result_callback(uint8_t fd, uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data){...your code;return(close_tcp_session);}
  1116. //
  1117. // statuscode=0 means the buffer has valid data, otherwise len and pos_in_buf
  1118. // are invalid. That is: do to use data_start_pos_in_buf and len_of_data
  1119. // if statuscode!=0.
  1120. //
  1121. // This callback gives you access to the TCP data of the first
  1122. // packet returned from the server. You should aim to minimize the server
  1123. // output such that this will be the only packet.
  1124. //
  1125. // close_tcp_session=1 means close the session now. close_tcp_session=0
  1126. // read all data and leave it to the other side to close it.
  1127. // If you connect to a web server then you want close_tcp_session=0.
  1128. // If you connect to a modbus/tcp equipment then you want close_tcp_session=1
  1129. //
  1130. // Declare a callback function to be called in order to fill in the
  1131. //
  1132. // request (tcp data sent to the server):
  1133. // uint16_t your_client_tcp_datafill_callback(uint8_t fd){...your code;return(len_of_data_filled_in);}
  1134. //
  1135. // Now call:
  1136. // fd=client_tcp_req(&your_client_tcp_result_callback,&your_client_tcp_datafill_callback,portnumber);
  1137. //
  1138. // fd is a file descriptor like number that you get back in the fill and result
  1139. // function so you know to which call of client_tcp_req this callback belongs.
  1140. //
  1141. // You can not start different clients (e.g modbus and web) at the
  1142. // same time but you can start them one after each other. That is
  1143. // when the request has timed out or when the result_callback was
  1144. // executed then you can start a new one. The fd makes it still possible to
  1145. // distinguish in the callback code the different types you started.
  1146. //
  1147. // Note that you might never get called back if the other side does
  1148. // not answer. A timer would be needed to recongnize such a condition.
  1149. //
  1150. // We use callback functions because that saves memory and a uC is very
  1151. // limited in memory
  1152. //
  1153. uint8_t client_tcp_req(uint8_t (*result_callback)(uint8_t fd,uint8_t statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data),uint16_t (*datafill_callback)(uint8_t fd),uint16_t port,uint8_t *dstip,uint8_t *dstmac)
  1154. {
  1155.         uint8_t i=0;
  1156.         client_tcp_result_callback=result_callback;
  1157.         client_tcp_datafill_callback=datafill_callback;
  1158.         while(i<4){tcp_otherside_ip[i]=dstip[i];i++;}
  1159.         i=0;
  1160.         while(i<6){tcp_dst_mac[i]=dstmac[i];i++;}
  1161.         tcp_client_port=port;
  1162.         tcp_client_state=1; // send a syn
  1163.         tcp_fd++;
  1164.         if (tcp_fd>7){
  1165.                 tcp_fd=0;
  1166.         }
  1167.         return(tcp_fd);
  1168. }
  1169. #endif //  TCP_client
  1170.  
  1171. #if defined (WWW_client)
  1172. uint16_t www_client_internal_datafill_callback(uint8_t fd){
  1173.         char strbuf[5];
  1174.         uint16_t len=0;
  1175.         if (fd==www_fd){
  1176.                 if (browsertype==0){
  1177.                         // GET
  1178.                         len=fill_tcp_data_p(bufptr,0,PSTR("GET "));
  1179.                         len=fill_tcp_data_p(bufptr,len,client_urlbuf);
  1180.                         len=fill_tcp_data(bufptr,len,client_urlbuf_var);
  1181.                         // I would prefer http/1.0 but there is a funny
  1182.                         // bug in some apache webservers which causes
  1183.                         // them to send two packets (fragmented PDU)
  1184.                         // if we don't use HTTP/1.1 + Connection: close
  1185.                         len=fill_tcp_data_p(bufptr,len,PSTR(" HTTP/1.1\r\nHost: "));
  1186.                         len=fill_tcp_data(bufptr,len,client_hoststr);
  1187.                         len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: text/html\r\n\r\n"));
  1188.                 }else{
  1189.                         // POST
  1190.                         len=fill_tcp_data_p(bufptr,0,PSTR("POST "));
  1191.                         len=fill_tcp_data_p(bufptr,len,client_urlbuf);
  1192.                         len=fill_tcp_data(bufptr,len,client_urlbuf_var);
  1193.                         len=fill_tcp_data_p(bufptr,len,PSTR(" HTTP/1.1\r\nHost: "));
  1194.                         len=fill_tcp_data(bufptr,len,client_hoststr);
  1195.                         if (client_additionalheaderline){
  1196.                                 len=fill_tcp_data_p(bufptr,len,PSTR("\r\n"));
  1197.                                 len=fill_tcp_data_p(bufptr,len,client_additionalheaderline);
  1198.                         }
  1199.                         len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: */*\r\n"));
  1200.                         len=fill_tcp_data_p(bufptr,len,PSTR("Content-Length: "));
  1201.                         itoa(strlen(client_postval),strbuf,10);
  1202.                         len=fill_tcp_data(bufptr,len,strbuf);
  1203.                         len=fill_tcp_data_p(bufptr,len,PSTR("\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"));
  1204.                         len=fill_tcp_data(bufptr,len,client_postval);
  1205.                 }
  1206.                 return(len);
  1207.         }
  1208.         return(0);
  1209. }
  1210.  
  1211. uint8_t www_client_internal_result_callback(uint8_t fd, uint8_t statuscode, uint16_t datapos, uint16_t len_of_data){
  1212.         uint16_t web_statuscode=0; // tcp status is OK but we need to check http layer too
  1213.         uint8_t i=0;
  1214.         if (fd!=www_fd){
  1215.                 (*client_browser_callback)(500,0,0);
  1216.                 return(0);
  1217.         }
  1218.         if (statuscode==0 && len_of_data>12){
  1219.                 // we might have a http status code
  1220.                 // http status codes are 3digit numbers as ascii text. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  1221.                 // The buffer would look like this: HTTP/1.1 200 OK\r\n
  1222.                 // web_statuscode=0 means we got a corrupted answer
  1223.  
  1224.             for (uint16_t t=0;t<len_of_data+datapos+100;t++){
  1225.                 USART_Transmit(bufptr[t]);
  1226.  
  1227.             }
  1228.             USART_napis("\n\r dlugosc:");
  1229.             USART_int(len_of_data);
  1230.  
  1231.             USART_napis("\n\r datapos:");
  1232.             USART_int(datapos);
  1233.  
  1234.             USART_napis("\n\r fd:");
  1235.             USART_int(fd);
  1236.  
  1237.  
  1238.                 if (client_browser_callback){
  1239.  
  1240.  
  1241.                         if (isblank(bufptr[datapos+8]) && isdigit(bufptr[datapos+9])&& isdigit(bufptr[datapos+11])){ // e.g 200 OK, a status code has 3 digits from datapos+9 to datapos+11, copy over the web/http status code to web_statuscode:
  1242.                                 while(i<2){
  1243.                                         web_statuscode+=bufptr[datapos+9+i]-'0';
  1244.                                         web_statuscode*=10;
  1245.                                         i++;
  1246.                                 }
  1247.                                 web_statuscode+=bufptr[datapos+11]-'0';
  1248.                         }
  1249.                         //(*client_browser_callback)(web_statuscode,((uint16_t)TCP_SRC_PORT_H_P+(bufptr[TCP_HEADER_LEN_P]>>4)*4),len_of_data);
  1250.                         (*client_browser_callback)(web_statuscode,datapos,len_of_data);
  1251.                 }
  1252.         }
  1253.         return(0);
  1254. }
  1255.  
  1256. // call this function externally like this:
  1257. //
  1258. // Declare a callback function: void browserresult(uint8_t webstatuscode,uint16_t datapos,uint16_t len){...your code}
  1259. // The variable datapos is the index in the packet buffer.
  1260. // Now call client_browser_url:
  1261. // client_browser_url(PSTR("/cgi-bin/checkip"),NULL,"tuxgraphics.org",&browserresult,other_side_ip,gwmac);
  1262. // urlbuf_varpart is a pointer to a string buffer that contains the second
  1263. // non constant part of the url. You must keep this buffer allocated until the
  1264. // callback function is executed or until you can be sure that the server side
  1265. // has timed out.
  1266. // hoststr is the name of the host. This is needed because many sites host several
  1267. // sites on the same physical machine with only one IP address. The web server needs
  1268. // to know to which site you want to go.
  1269. // webstatuscode is zero if there was no proper reply from the server (garbage message total communication failure, this is rare).
  1270. // webstatuscode is the http status code (e.g webstatuscode=200 for 200 OK);
  1271. // webstatuscode is zero if there was a garbage answer received from the server.
  1272. // For possible status codes look at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  1273. // Basically 2xx is success and any 5xx, 4xx is a failure.
  1274. // The string buffers to which urlbuf_varpart and hoststr are pointing
  1275. // must not be changed until the callback is executed.
  1276. //
  1277. void client_browse_url(const const char *urlbuf,const char *urlbuf_varpart,const char *hoststr,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac)
  1278. {
  1279.         if (!enc28j60linkup())return;
  1280.         client_urlbuf=urlbuf;
  1281.         client_urlbuf_var=urlbuf_varpart;
  1282.         client_hoststr=hoststr;
  1283.         browsertype=0;
  1284.         client_browser_callback=callback;
  1285.         www_fd=client_tcp_req(&www_client_internal_result_callback,&www_client_internal_datafill_callback,80,dstip,dstmac);
  1286. }
  1287.  
  1288. // client web browser using http POST operation:
  1289. // additionalheaderline must be set to NULL if not used.
  1290. // The string buffers to which urlbuf_varpart and hoststr are pointing
  1291. // must not be changed until the callback is executed.
  1292. // postval is a string buffer which can only be de-allocated by the caller
  1293. // when the post operation was really done (e.g when callback was executed).
  1294. // postval must be urlencoded.
  1295. void client_http_post(const const char *urlbuf, const char *urlbuf_varpart,const char *hoststr, const const char *additionalheaderline,char *postval,void (*callback)(uint16_t,uint16_t,uint16_t),uint8_t *dstip,uint8_t *dstmac)
  1296. {
  1297.         if (!enc28j60linkup())return;
  1298.         client_urlbuf=urlbuf;
  1299.         client_hoststr=hoststr;
  1300.         client_urlbuf_var=urlbuf_varpart;
  1301.         client_additionalheaderline=additionalheaderline;
  1302.         client_postval=postval;
  1303.         browsertype=1;
  1304.         client_browser_callback=callback;
  1305.         www_fd=client_tcp_req(&www_client_internal_result_callback,&www_client_internal_datafill_callback,80,dstip,dstmac);
  1306. }
  1307. #endif // WWW_client
  1308.  
  1309. void register_ping_rec_callback(void (*callback)(uint8_t *srcip))
  1310. {
  1311.         icmp_callback=callback;
  1312. }
  1313.  
  1314. #ifdef PING_client
  1315. // loop over this to check if we get a ping reply:
  1316. uint8_t packetloop_icmp_checkreply(uint8_t *buf,uint8_t *ip_monitoredhost)
  1317. {
  1318.         if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREPLY_V){
  1319.                 if (buf[ICMP_DATA_P]== PINGPATTERN){
  1320.                         if (check_ip_message_is_from(buf,ip_monitoredhost)){
  1321.                                 return(1);
  1322.                                 // ping reply is from monitored host and ping was from us
  1323.                         }
  1324.                 }
  1325.         }
  1326.         return(0);
  1327. }
  1328. #endif // PING_client
  1329.  
  1330.  
  1331. // return 0 to just continue in the packet loop and return the position
  1332. // of the tcp data if there is tcp data part
  1333. uint16_t packetloop_arp_icmp_tcp(uint8_t *buf,uint16_t plen)
  1334. {
  1335.         uint16_t len;
  1336. #if defined (TCP_client)
  1337.         uint8_t send_fin=0;
  1338.         uint16_t tcpstart;
  1339.         uint16_t save_len;
  1340. #endif
  1341. #ifdef ARP_MAC_resolver_client
  1342.         //plen will be unequal to zero if there is a valid
  1343.         // packet (without crc error):
  1344.         if(plen==0){
  1345.                 if (arpip_state == (WGW_ACCEPT_ARP_REPLY|WGW_INITIAL_ARP) && arp_delaycnt==0 ){
  1346.                         // arp_delaycnt has wrapped no arp reply yet
  1347.                         if (enc28j60linkup()) client_arp_whohas(buf,arpip);
  1348.                 }
  1349.                 if (arpip_state == WGW_INITIAL_ARP && enc28j60linkup()){
  1350.                         client_arp_whohas(buf,arpip);
  1351.                         arpip_state|=WGW_ACCEPT_ARP_REPLY; // WGW_INITIAL_ARP and WGW_ACCEPT_ARP_REPLY set
  1352.                         arp_delaycnt=0; // this is like a timer, not so precise but good enough, it wraps in about 2 sec
  1353.                 }
  1354.                 arp_delaycnt++;
  1355. #if defined (TCP_client)
  1356.                 if (tcp_client_state==1 && enc28j60linkup()){ // send a syn
  1357.                         tcp_client_state=2;
  1358.                         tcpclient_src_port_l++; // allocate a new port
  1359.                         // we encode our 3 bit fd into the src port this
  1360.                         // way we get it back in every message that comes
  1361.                         // from the server:
  1362.                         tcp_client_syn(buf,((tcp_fd<<5) | (0x1f & tcpclient_src_port_l)),tcp_client_port);
  1363.                 }
  1364. #endif
  1365.                 return(0);
  1366.         }
  1367. #endif // ARP_MAC_resolver_client
  1368.         // arp is broadcast if unknown but a host may also
  1369.         // verify the mac address by sending it to
  1370.         // a unicast address.
  1371.         if(eth_type_is_arp_and_my_ip(buf,plen)){
  1372.                 if (buf[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REQ_L_V){
  1373.                         // is it an arp request
  1374.                         make_arp_answer_from_request(buf);
  1375.                 }
  1376. #ifdef ARP_MAC_resolver_client
  1377.                 if ((arpip_state & WGW_ACCEPT_ARP_REPLY) && (buf[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REPLY_L_V)){
  1378.                         // is it an arp reply
  1379.                         if (memcmp(&buf[ETH_ARP_SRC_IP_P],arpip,4)!=0) return(0); // not an arp reply for the IP we were searching          
  1380.                         (*client_arp_result_callback)(arpip,arp_reference_number,buf+ETH_ARP_SRC_MAC_P);
  1381.                         arpip_state=WGW_HAVE_MAC;
  1382.                 }
  1383. #endif // ARP_MAC_resolver_client
  1384.                 return(0);
  1385.  
  1386.         }
  1387.         // check if ip packets are for us:
  1388.         if(eth_type_is_ip_and_my_ip(buf,plen)==0){
  1389.                 return(0);
  1390.         }
  1391.         if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
  1392.                 if (icmp_callback){
  1393.                         (*icmp_callback)(&(buf[IP_SRC_P]));
  1394.                 }
  1395.                 // a ping packet, let's send pong
  1396.                 make_echo_reply_from_request(buf,plen);
  1397.                 return(0);
  1398.         }
  1399.         if (plen<54 && buf[IP_PROTO_P]!=IP_PROTO_TCP_V ){
  1400.                 // smaller than the smallest TCP packet and not tcp port
  1401.                 return(0);
  1402.         }
  1403. #if defined (TCP_client)
  1404.         // a message for the tcp client, tcp_client_state is zero if client was never used
  1405.         if ( buf[TCP_DST_PORT_H_P]==TCPCLIENT_SRC_PORT_H){
  1406. #if defined (WWW_client)
  1407.                 // workaround to pass pointer to www_client_internal..
  1408.                 bufptr=buf;
  1409. #endif // WWW_client
  1410.                 if (check_ip_message_is_from(buf,tcp_otherside_ip)==0){
  1411.                         return(0);
  1412.                 }
  1413.                 // if we get a reset:
  1414.                 if (buf[TCP_FLAGS_P] & TCP_FLAGS_RST_V){
  1415.                         if (client_tcp_result_callback){
  1416.                                 // parameters in client_tcp_result_callback: fd, status, buf_start, len
  1417.                                 (*client_tcp_result_callback)((buf[TCP_DST_PORT_L_P]>>5)&0x7,3,0,0);
  1418.                         }
  1419.                         tcp_client_state=6;
  1420.                         return(0);
  1421.                 }
  1422.                 len=get_tcp_data_len(buf);
  1423.                 if (tcp_client_state==2){
  1424.                         if ((buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) && (buf[TCP_FLAGS_P] &TCP_FLAGS_ACK_V)){
  1425.                                 // synack, answer with ack
  1426.                                 make_tcp_ack_from_any(buf,0,0);
  1427.                                 buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V;
  1428.  
  1429.                                 // Make a tcp message with data. When calling this function we must
  1430.                                 // still have a valid tcp-ack in the buffer. In other words
  1431.                                 // you have just called make_tcp_ack_from_any(buf,0).
  1432.                                 if (client_tcp_datafill_callback){
  1433.                                         // in this case it is src port because the above
  1434.                                         // make_tcp_ack_from_any swaps the dst and src port:
  1435.                                         len=(*client_tcp_datafill_callback)((buf[TCP_SRC_PORT_L_P]>>5)&0x7);
  1436.                                 }else{
  1437.                                         // this is just to prevent a crash
  1438.                                         len=0;
  1439.                                 }
  1440.                                 tcp_client_state=3;
  1441.                                 make_tcp_ack_with_data_noflags(buf,len);
  1442.                                 return(0);
  1443.                         }else{
  1444.                                 // reset only if we have sent a syn and don't get syn-ack back.
  1445.                                 // If we connect to a non listen port then we get a RST
  1446.                                 // which will be handeled above. In other words there is
  1447.                                 // normally no danger for an endless loop.
  1448.                                 tcp_client_state=1; // retry
  1449.                                 // do not inform application layer as we retry.
  1450.                                 len++;
  1451.                                 if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
  1452.                                         // if packet was an ack then do not step the ack number
  1453.                                         len=0;
  1454.                                 }
  1455.                                 // refuse and reset the connection
  1456.                                 make_tcp_ack_from_any(buf,len,TCP_FLAGS_RST_V);
  1457.                                 return(0);
  1458.                         }
  1459.                 }
  1460.                 // in tcp_client_state==3 we will normally first get an empty
  1461.                 // ack-packet and then a ack-packet with data.
  1462.                 if (tcp_client_state==3 && len>0){
  1463.                         // our first real data packet
  1464.                         tcp_client_state=4;
  1465.                         // return the data we received
  1466.                         if (client_tcp_result_callback){
  1467.                                 tcpstart=TCP_DATA_START; // TCP_DATA_START is a formula
  1468.                                 // out of buffer bounds check, needed in case of fragmented IP packets
  1469.                                 if (tcpstart>plen-8){
  1470.                                         tcpstart=plen-8; // dummy but save
  1471.                                 }
  1472.                                 save_len=len;
  1473.                                 if (tcpstart+len>plen){
  1474.                                         save_len=plen-tcpstart;
  1475.                                 }
  1476.                                 send_fin=(*client_tcp_result_callback)((buf[TCP_DST_PORT_L_P]>>5)&0x7,0,tcpstart,save_len);
  1477.                         }
  1478.                         if (send_fin){
  1479.                                 make_tcp_ack_from_any(buf,len,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
  1480.                                 tcp_client_state=5;
  1481.                                 return(0);
  1482.                         }
  1483.                 }
  1484.                 if(tcp_client_state==5){
  1485.                         // we get one more final ack to our fin-ack:
  1486.                         if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
  1487.                                 tcp_client_state=6; // in state 6 communication should be finished
  1488.                         }
  1489.                         return(0);
  1490.                 }
  1491.                 if(tcp_client_state==6){
  1492.                         // something wrong, can't deal with this, reset the connection
  1493.                         len++;
  1494.                         if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V) len=0; // if packet was an ack then do not step the ack number
  1495.                         make_tcp_ack_from_any(buf,len,TCP_FLAGS_RST_V);
  1496.                         // just a single reset, do not repeat if more messages:
  1497.                         tcp_client_state=7;
  1498.                         return(0);
  1499.                 }
  1500.                 if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
  1501.                         // this normally a fin ack message but it could be
  1502.                         // any message with fin we answer with fin-ack:
  1503.                         make_tcp_ack_from_any(buf,len+1,TCP_FLAGS_FIN_V);
  1504.                         tcp_client_state=5; // connection terminated
  1505.                         return(0);
  1506.                 }
  1507.                 // ack all data (the web page may be long):
  1508.                 // if we just get a fragment then len will be zero
  1509.                 // and we ack only once we have the full packet
  1510.                 if (len>0){
  1511.                         make_tcp_ack_from_any(buf,len,0);
  1512.                 }
  1513.                 return(0);
  1514.         }
  1515. #endif // TCP_client
  1516.         //
  1517. #ifdef WWW_server
  1518.         // tcp port web server start
  1519.         if (buf[IP_PROTO_P]==IP_PROTO_TCP_V && buf[TCP_DST_PORT_H_P]==wwwport_h && buf[TCP_DST_PORT_L_P]==wwwport_l){
  1520.                 if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
  1521.                         make_tcp_synack_from_syn(buf);
  1522.                         // make_tcp_synack_from_syn does already send the syn,ack
  1523.                         return(0);
  1524.                 }
  1525.                 if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
  1526.                         info_data_len=get_tcp_data_len(buf);
  1527.                         // we can possibly have no data, just ack:
  1528.                         // Here we misuse plen for something else to save a variable.
  1529.                         // plen is now the position of start of the tcp user data.
  1530.                         if (info_data_len==0){
  1531.                                 if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
  1532.                                         // finack, answer with ack
  1533.                                         make_tcp_ack_from_any(buf,0,0);
  1534.                                 }
  1535.                                 // just an ack with no data, wait for next packet
  1536.                                 return(0);
  1537.                         }
  1538.                         // Here we misuse len for something else to save a variable
  1539.                         len=TCP_DATA_START; // TCP_DATA_START is a formula
  1540.                         // check for data corruption
  1541.                         if (len>plen-8){
  1542.                                 return(0);
  1543.                         }
  1544.                         return(len);
  1545.                 }
  1546.         }
  1547. #endif // WWW_server
  1548.         return(0);
  1549. }
  1550. /* end of ip_arp_udp.c */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement