PageRenderTime 86ms CodeModel.GetById 126ms app.highlight 687ms RepoModel.GetById 103ms app.codeStats 1ms

/ip_arp_udp_tcp.c

https://github.com/electronic-dudeness/EnergyMeter
C | 1514 lines | 1032 code | 64 blank | 418 comment | 112 complexity | 410576dd6d1cbf2fed9fc026142e2093 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file