PageRenderTime 6ms CodeModel.GetById 2ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 0ms

/EtherCard/ip_arp_udp_tcp.cpp

https://github.com/robomotic/Hardware
C++ | 841 lines | 779 code | 46 blank | 16 comment | 84 complexity | 9894fad939c5f5c8ee47b70de0d1903c MD5 | raw file
  1// IP, Arp, UDP and TCP functions.
  2// Author: Guido Socher 
  3// Copyright: GPL V2
  4//
  5// The TCP implementation uses some size optimisations which are valid
  6// only if all data can be sent in one single packet. This is however
  7// not a big limitation for a microcontroller as you will anyhow use
  8// small web-pages. The web server must send the entire web page in one
  9// packet. The client "web browser" as implemented here can also receive
 10// large pages.
 11//
 12// Mods bij jcw, 2010-05-20
 13
 14#include <avr/pgmspace.h>
 15#include "net.h"
 16#include "enc28j60.h"
 17#include "ip_config.h"
 18#include <WProgram.h>
 19
 20static byte wwwport_l=80; // server port
 21static byte wwwport_h;	 // Note: never use same as TCPCLIENT_SRC_PORT_H
 22static byte tcpclient_src_port_l=1; 
 23static byte tcp_fd; // a file descriptor, will be encoded into the port
 24static byte tcpsrvip[4];
 25static byte tcp_client_state;
 26static byte tcp_client_port_h;
 27static byte tcp_client_port_l;
 28static byte (*client_tcp_result_callback)(byte,byte,uint16_t,uint16_t);
 29static uint16_t (*client_tcp_datafill_callback)(byte);
 30#define TCPCLIENT_SRC_PORT_H 11
 31// #define TCP_client 1
 32static byte www_fd;
 33static byte browsertype; // 0 = get, 1 = post
 34static void (*client_browser_callback)(byte,uint16_t,uint16_t);
 35static prog_char *client_additionalheaderline;
 36static char *client_postval;
 37static prog_char *client_urlbuf;
 38static char *client_urlbuf_var;
 39static prog_char *client_hoststr;
 40static byte *bufptr; // ugly workaround for backward compatibility
 41static void (*icmp_callback)(byte *ip);
 42static int16_t delaycnt=1;
 43static byte gwip[4]; 
 44static byte gwmacaddr[6];
 45static byte waitgwmac; // 0=wait, 1=first req no anser, 2=have gwmac, 4=refeshing but have gw mac, 8=accept an arp reply
 46#define WGW_INITIAL_ARP 1
 47#define WGW_HAVE_GW_MAC 2
 48#define WGW_REFRESHING 4
 49#define WGW_ACCEPT_ARP_REPLY 8
 50static byte macaddr[6];
 51static byte ipaddr[4];
 52static uint16_t info_data_len;
 53static byte seqnum=0xa; // my initial tcp sequence number
 54
 55#define CLIENTMSS 550
 56#define TCP_DATA_START ((uint16_t)TCP_SRC_PORT_H_P+(buf[TCP_HEADER_LEN_P]>>4)*4)
 57
 58const char arpreqhdr[] PROGMEM = { 0,1,8,0,6,4,0,1 };
 59const char iphdr[] PROGMEM = { 0x45,0,0,0x82,0,0,0x40,0,0x20 };
 60const char ntpreqhdr[] PROGMEM = { 0xE3,0,4,0xFA,0,1,0,0,0,1 };
 61
 62static uint16_t checksum(byte *buf, uint16_t len,byte type){
 63	uint32_t sum = type==1 ? IP_PROTO_UDP_V+len-8 :
 64                    type==2 ? IP_PROTO_TCP_V+len-8 : 0;
 65	while(len >1){
 66		sum += 0xFFFF & (((uint32_t)*buf<<8)|*(buf+1));
 67		buf+=2;
 68		len-=2;
 69	}
 70	if (len)
 71		sum += ((uint32_t)*buf)<<8;
 72	while (sum>>16)
 73		sum = (sum & 0xFFFF)+(sum >> 16);
 74	return (uint16_t) sum ^ 0xFFFF;
 75}
 76
 77void init_ip_arp_udp_tcp(byte *mymac,byte *myip,uint16_t port){
 78	wwwport_h=(port>>8);
 79	wwwport_l=(port);
 80	byte i=0;
 81	while(i<4){
 82		ipaddr[i]=myip[i];
 83		i++;
 84	}
 85	i=0;
 86	while(i<6){
 87		macaddr[i]=mymac[i];
 88		i++;
 89	}
 90}
 91
 92static byte check_ip_message_is_from(byte *buf,byte *ip) {
 93	byte i=0;
 94	while(i<4){
 95		if (buf[IP_SRC_P+i]!=ip[i])
 96			return 0;
 97		i++;
 98	}
 99	return 1;
100}
101
102static byte eth_type_is_arp_and_my_ip(byte *buf,uint16_t len){
103	if (len<41)
104		return 0;
105	if (buf[ETH_TYPE_H_P] != ETHTYPE_ARP_H_V || 
106	   buf[ETH_TYPE_L_P] != ETHTYPE_ARP_L_V)
107		return 0;
108	byte i=0;
109	while(i<4){
110		if (buf[ETH_ARP_DST_IP_P+i] != ipaddr[i])
111			return 0;
112		i++;
113	}
114	return 1;
115}
116
117static byte eth_type_is_ip_and_my_ip(byte *buf,uint16_t len){
118	if (len<42)
119		return 0;
120	if (buf[ETH_TYPE_H_P]!=ETHTYPE_IP_H_V || 
121	   buf[ETH_TYPE_L_P]!=ETHTYPE_IP_L_V)
122		return 0;
123	if (buf[IP_HEADER_LEN_VER_P]!=0x45)
124		return 0;
125	byte i=0;
126	while(i<4){
127		if (buf[IP_DST_P+i]!=ipaddr[i])
128			return 0;
129		i++;
130	}
131	return 1;
132}
133static void make_eth(byte *buf) {
134	byte i=0;
135	while(i<6){
136		buf[ETH_DST_MAC +i]=buf[ETH_SRC_MAC +i];
137		buf[ETH_SRC_MAC +i]=macaddr[i];
138		i++;
139	}
140}
141static void fill_ip_hdr_checksum(byte *buf) {
142	buf[IP_CHECKSUM_P]=0;
143	buf[IP_CHECKSUM_P+1]=0;
144	buf[IP_FLAGS_P]=0x40; // don't fragment
145	buf[IP_FLAGS_P+1]=0;  // fragement offset
146	buf[IP_TTL_P]=64; // ttl
147	uint16_t ck=checksum(&buf[IP_P], IP_HEADER_LEN,0);
148	buf[IP_CHECKSUM_P]=ck>>8;
149	buf[IP_CHECKSUM_P+1]=ck;
150}
151
152static void make_ip(byte *buf) {
153	byte i=0;
154	while(i<4){
155		buf[IP_DST_P+i]=buf[IP_SRC_P+i];
156		buf[IP_SRC_P+i]=ipaddr[i];
157		i++;
158	}
159	fill_ip_hdr_checksum(buf);
160}
161
162static void step_seq(byte *buf,uint16_t rel_ack_num,byte cp_seq) {
163	byte i;
164	byte tseq;
165	i=4;
166	while(i>0){
167		rel_ack_num=buf[TCP_SEQ_H_P+i-1]+rel_ack_num;
168		tseq=buf[TCP_SEQACK_H_P+i-1];
169		buf[TCP_SEQACK_H_P+i-1]=0xff&rel_ack_num;
170		if (cp_seq)
171			buf[TCP_SEQ_H_P+i-1]=tseq;
172		else
173			buf[TCP_SEQ_H_P+i-1]= 0; // some preset value
174		rel_ack_num=rel_ack_num>>8;
175		i--;
176	}
177}
178
179static void make_tcphead(byte *buf,uint16_t rel_ack_num,byte cp_seq) {
180	byte i;
181	i=buf[TCP_DST_PORT_H_P];
182	buf[TCP_DST_PORT_H_P]=buf[TCP_SRC_PORT_H_P];
183	buf[TCP_SRC_PORT_H_P]=i;
184	i=buf[TCP_DST_PORT_L_P];
185	buf[TCP_DST_PORT_L_P]=buf[TCP_SRC_PORT_L_P];
186	buf[TCP_SRC_PORT_L_P]=i;
187	step_seq(buf,rel_ack_num,cp_seq);
188	buf[TCP_CHECKSUM_H_P]=0;
189	buf[TCP_CHECKSUM_L_P]=0;
190	buf[TCP_HEADER_LEN_P]=0x50;
191}
192
193void make_arp_answer_from_request(byte *buf) {
194	make_eth(buf);
195	buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V;
196	buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V;
197	byte i=0;
198	while(i<6){
199		buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i];
200		buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i];
201		i++;
202	}
203	i=0;
204	while(i<4){
205		buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i];
206		buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
207		i++;
208	}
209	enc28j60PacketSend(42,buf); 
210}
211
212void make_echo_reply_from_request(byte *buf,uint16_t len) {
213	make_eth(buf);
214	make_ip(buf);
215	buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;
216	if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))
217		buf[ICMP_CHECKSUM_P+1]++;
218	buf[ICMP_CHECKSUM_P]+=0x08;
219	//
220	enc28j60PacketSend(len,buf);
221}
222
223void make_udp_reply_from_request(byte *buf,char *data,byte datalen,uint16_t port) {
224	make_eth(buf);
225	if (datalen>220)
226		datalen=220;
227	buf[IP_TOTLEN_H_P]=0;
228	buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
229	make_ip(buf);
230	buf[UDP_DST_PORT_H_P]=buf[UDP_SRC_PORT_H_P];
231	buf[UDP_DST_PORT_L_P]= buf[UDP_SRC_PORT_L_P];
232	buf[UDP_SRC_PORT_H_P]=port>>8;
233	buf[UDP_SRC_PORT_L_P]=port;
234	buf[UDP_LEN_H_P]=0;
235	buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
236	buf[UDP_CHECKSUM_H_P]=0;
237	buf[UDP_CHECKSUM_L_P]=0;
238	byte i=0;
239	while(i<datalen){
240		buf[UDP_DATA_P+i]=data[i];
241		i++;
242	}
243	uint16_t ck=checksum(&buf[IP_SRC_P], 16 + datalen,1);
244	buf[UDP_CHECKSUM_H_P]=ck>>8;
245	buf[UDP_CHECKSUM_L_P]=ck;
246	enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
247}
248
249static void make_tcp_synack_from_syn(byte *buf) {
250	make_eth(buf);
251	buf[IP_TOTLEN_H_P]=0;
252	buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
253	make_ip(buf);
254	buf[TCP_FLAGS_P]=TCP_FLAGS_SYNACK_V;
255	make_tcphead(buf,1,0);
256	buf[TCP_SEQ_H_P+0]= 0;
257	buf[TCP_SEQ_H_P+1]= 0;
258	buf[TCP_SEQ_H_P+2]= seqnum; 
259	buf[TCP_SEQ_H_P+3]= 0;
260	seqnum+=3;
261	buf[TCP_OPTIONS_P]=2;
262	buf[TCP_OPTIONS_P+1]=4;
263	buf[TCP_OPTIONS_P+2]=0x05;
264	buf[TCP_OPTIONS_P+3]=0x0;
265	buf[TCP_HEADER_LEN_P]=0x60;
266	buf[TCP_WIN_SIZE]=0x5; // 1400=0x578
267	buf[TCP_WIN_SIZE+1]=0x78;
268	uint16_t ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2);
269	buf[TCP_CHECKSUM_H_P]=ck>>8;
270	buf[TCP_CHECKSUM_L_P]=ck;
271	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf);
272}
273
274static uint16_t get_tcp_data_len(byte *buf) {
275	int16_t i = (((int16_t)buf[IP_TOTLEN_H_P])<<8)|buf[IP_TOTLEN_L_P];
276	i-=IP_HEADER_LEN;
277	i-=(buf[TCP_HEADER_LEN_P]>>4)*4; // generate len in bytes;
278	if (i<=0)
279		i=0;
280	return (uint16_t)i;
281}
282
283uint16_t fill_tcp_data_p(byte *buf,uint16_t pos, const prog_char *progmem_s) {
284	char c;
285	while ((c = pgm_read_byte(progmem_s++)))
286		buf[TCP_CHECKSUM_L_P+3+pos++]=c;
287	return pos;
288}
289
290uint16_t fill_tcp_data_len(byte *buf,uint16_t pos, const byte *s, byte len) {
291	while (len--)
292		buf[TCP_CHECKSUM_L_P+3+pos++]=*s++;
293	return pos;
294}
295
296uint16_t fill_tcp_data(byte *buf,uint16_t pos, const char *s) {
297	return fill_tcp_data_len(buf,pos,(byte*)s,strlen(s));
298}
299
300static void make_tcp_ack_from_any(byte *buf,int16_t datlentoack,byte addflags) {
301	uint16_t j;
302	make_eth(buf);
303	buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|addflags;
304	if (addflags!=TCP_FLAGS_RST_V && datlentoack==0)
305		datlentoack=1;
306	make_tcphead(buf,datlentoack,1); // no options
307	j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
308	buf[IP_TOTLEN_H_P]=j>>8;
309	buf[IP_TOTLEN_L_P]=j;
310	make_ip(buf);
311	buf[TCP_WIN_SIZE]=0x4; // 1024=0x400, 1280=0x500 2048=0x800 768=0x300
312	buf[TCP_WIN_SIZE+1]=0;
313	j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2);
314	buf[TCP_CHECKSUM_H_P]=j>>8;
315	buf[TCP_CHECKSUM_L_P]=j;
316	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf);
317}
318
319static void make_tcp_ack_with_data_noflags(byte *buf,uint16_t dlen) {
320	uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
321	buf[IP_TOTLEN_H_P]=j>>8;
322	buf[IP_TOTLEN_L_P]=j;
323	fill_ip_hdr_checksum(buf);
324	buf[TCP_CHECKSUM_H_P]=0;
325	buf[TCP_CHECKSUM_L_P]=0;
326	j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlen,2);
327	buf[TCP_CHECKSUM_H_P]=j>>8;
328	buf[TCP_CHECKSUM_L_P]=j;
329	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN,buf);
330}
331
332void www_server_reply(byte *buf,uint16_t dlen) {
333	make_tcp_ack_from_any(buf,info_data_len,0); // send ack for http get
334	buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V;
335	make_tcp_ack_with_data_noflags(buf,dlen); // send data
336}
337
338static void fill_buf_p(byte *buf,uint16_t len, const prog_char *progmem_s) {
339	while (len--)
340		*buf++ = pgm_read_byte(progmem_s++);
341}
342
343void client_icmp_request(byte *buf,byte *destip) {
344	byte i=0;
345	while(i<6){
346		buf[ETH_DST_MAC +i]=gwmacaddr[i]; // gw mac in local lan or host mac
347		buf[ETH_SRC_MAC +i]=macaddr[i];
348		i++;
349	}
350	buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
351	buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
352	fill_buf_p(&buf[IP_P],9,iphdr);
353	buf[IP_TOTLEN_L_P]=0x54;
354	buf[IP_PROTO_P]=IP_PROTO_ICMP_V;
355	i=0;
356	while(i<4){
357		buf[IP_DST_P+i]=destip[i];
358		buf[IP_SRC_P+i]=ipaddr[i];
359		i++;
360	}
361	fill_ip_hdr_checksum(buf);
362	buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREQUEST_V;
363	buf[ICMP_TYPE_P+1]=0; // code
364	buf[ICMP_CHECKSUM_H_P]=0;
365	buf[ICMP_CHECKSUM_L_P]=0;
366	buf[ICMP_IDENT_H_P]=5; // some number 
367	buf[ICMP_IDENT_L_P]=ipaddr[3]; // last byte of my IP
368	buf[ICMP_IDENT_L_P+1]=0; // seq number, high byte
369	buf[ICMP_IDENT_L_P+2]=1; // seq number, low byte, we send only 1 ping at a time
370	i=0;
371	while(i<56){ 
372		buf[ICMP_DATA_P+i]=PINGPATTERN;
373		i++;
374	}
375	uint16_t ck=checksum(&buf[ICMP_TYPE_P], 56+8,0);
376	buf[ICMP_CHECKSUM_H_P]=ck>>8;
377	buf[ICMP_CHECKSUM_L_P]=ck;
378	enc28j60PacketSend(98,buf);
379}
380
381void client_ntp_request(byte *buf,byte *ntpip,byte srcport) {
382	byte i=0;
383	while(i<6){
384		buf[ETH_DST_MAC +i]=gwmacaddr[i]; // gw mac in local lan or host mac
385		buf[ETH_SRC_MAC +i]=macaddr[i];
386		i++;
387	}
388	buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
389	buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
390	fill_buf_p(&buf[IP_P],9,iphdr);
391	buf[IP_TOTLEN_L_P]=0x4c;
392	buf[IP_PROTO_P]=IP_PROTO_UDP_V;
393	i=0;
394	while(i<4){
395		buf[IP_DST_P+i]=ntpip[i];
396		buf[IP_SRC_P+i]=ipaddr[i];
397		i++;
398	}
399	fill_ip_hdr_checksum(buf);
400	buf[UDP_DST_PORT_H_P]=0;
401	buf[UDP_DST_PORT_L_P]=0x7b; // ntp=123
402	buf[UDP_SRC_PORT_H_P]=10;
403	buf[UDP_SRC_PORT_L_P]=srcport; // lower 8 bit of src port
404	buf[UDP_LEN_H_P]=0;
405	buf[UDP_LEN_L_P]=56; // fixed len
406	buf[UDP_CHECKSUM_H_P]=0;
407	buf[UDP_CHECKSUM_L_P]=0;
408	i=0;
409	while(i<48){ 
410		buf[UDP_DATA_P+i]=0;
411		i++;
412	}
413	fill_buf_p(&buf[UDP_DATA_P],10,ntpreqhdr);
414	uint16_t ck=checksum(&buf[IP_SRC_P], 16 + 48,1);
415	buf[UDP_CHECKSUM_H_P]=ck>>8;
416	buf[UDP_CHECKSUM_L_P]=ck;
417	enc28j60PacketSend(90,buf);
418}
419
420byte client_ntp_process_answer(byte *buf,uint32_t *time,byte dstport_l){
421	if (dstport_l && buf[UDP_DST_PORT_L_P]!=dstport_l)
422		return 0;
423	if (buf[UDP_LEN_H_P]!=0 || buf[UDP_LEN_L_P]!=56 || buf[UDP_SRC_PORT_L_P]!=0x7b)
424		return 0;
425	*time=((uint32_t)buf[0x52]<<24)|((uint32_t)buf[0x53]<<16)|((uint32_t)buf[0x54]<<8)|((uint32_t)buf[0x55]);
426	return 1;
427}
428
429void send_udp_prepare(byte *buf,uint16_t sport, byte *dip, uint16_t dport) {
430	byte i=0;
431	while(i<6){
432		buf[ETH_DST_MAC +i]=gwmacaddr[i]; // gw mac in local lan or host mac
433		buf[ETH_SRC_MAC +i]=macaddr[i];
434		i++;
435	}
436	buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
437	buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
438	fill_buf_p(&buf[IP_P],9,iphdr);
439	buf[IP_TOTLEN_H_P]=0;
440	buf[IP_PROTO_P]=IP_PROTO_UDP_V;
441	i=0;
442	while(i<4){
443		buf[IP_DST_P+i]=dip[i];
444		buf[IP_SRC_P+i]=ipaddr[i];
445		i++;
446	}
447	buf[UDP_DST_PORT_H_P]=(dport>>8);
448	buf[UDP_DST_PORT_L_P]=0xff&dport; 
449	buf[UDP_SRC_PORT_H_P]=(sport>>8);
450	buf[UDP_SRC_PORT_L_P]=sport; 
451	buf[UDP_LEN_H_P]=0;
452	buf[UDP_CHECKSUM_H_P]=0;
453	buf[UDP_CHECKSUM_L_P]=0;
454}
455
456void send_udp_transmit(byte *buf,byte datalen) {
457	buf[IP_TOTLEN_L_P]=IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
458	fill_ip_hdr_checksum(buf);
459	buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen;
460	uint16_t ck=checksum(&buf[IP_SRC_P], 16 + datalen,1);
461	buf[UDP_CHECKSUM_H_P]=ck>>8;
462	buf[UDP_CHECKSUM_L_P]=ck;
463	enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf);
464}
465
466void send_udp(byte *buf,char *data,byte datalen,uint16_t sport, byte *dip, uint16_t dport) {
467	send_udp_prepare(buf,sport, dip, dport);
468	byte i=0;
469	if (datalen>220)
470		datalen=220;
471	i=0;
472	while(i<datalen){
473		buf[UDP_DATA_P+i]=data[i];
474		i++;
475	}
476	send_udp_transmit(buf,datalen);
477}
478
479void send_wol(byte *buf,byte *wolmac) {
480	byte i=0;
481	byte m=0;
482	byte pos=0;
483	while(i<6){
484		buf[ETH_DST_MAC +i]=0xff;
485		buf[ETH_SRC_MAC +i]=macaddr[i];
486		i++;
487	}
488	buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
489	buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
490	fill_buf_p(&buf[IP_P],9,iphdr);
491	buf[IP_TOTLEN_L_P]=0x54;
492	buf[IP_PROTO_P]=IP_PROTO_ICMP_V;
493	i=0;
494	while(i<4){
495		buf[IP_SRC_P+i]=ipaddr[i];
496		buf[IP_DST_P+i]=0xff;
497		i++;
498	}
499	fill_ip_hdr_checksum(buf);
500	buf[UDP_DST_PORT_H_P]=0;
501	buf[UDP_DST_PORT_L_P]=0x9; // wol=normally 9
502	buf[UDP_SRC_PORT_H_P]=10;
503	buf[UDP_SRC_PORT_L_P]=0x42; // source port does not matter
504	buf[UDP_LEN_H_P]=0;
505	buf[UDP_LEN_L_P]=110; // fixed len
506	buf[UDP_CHECKSUM_H_P]=0;
507	buf[UDP_CHECKSUM_L_P]=0;
508	i=0;
509	while(i<6){ 
510		buf[UDP_DATA_P+i]=0xff;
511		i++;
512	}
513	m=0;
514	pos=UDP_DATA_P+i;
515	while (m<16){
516		i=0;
517		while(i<6){ 
518			buf[pos]=wolmac[i];
519			i++;
520			pos++;
521		}
522		m++;
523	}
524	uint16_t ck=checksum(&buf[IP_SRC_P], 16+ 102,1);
525	buf[UDP_CHECKSUM_H_P]=ck>>8;
526	buf[UDP_CHECKSUM_L_P]=ck;
527	enc28j60PacketSend(pos,buf);
528}
529
530// make a arp request
531void client_arp_whohas(byte *buf,byte *ip_we_search) {
532	byte i=0;
533	while(i<6){
534		buf[ETH_DST_MAC +i]=0xff;
535		buf[ETH_SRC_MAC +i]=macaddr[i];
536		i++;
537	}
538	buf[ETH_TYPE_H_P] = ETHTYPE_ARP_H_V;
539	buf[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V;
540	fill_buf_p(&buf[ETH_ARP_P],8,arpreqhdr);
541	i=0;
542	while(i<6){
543		buf[ETH_ARP_SRC_MAC_P +i]=macaddr[i];
544		buf[ETH_ARP_DST_MAC_P+i]=0;
545		i++;
546	}
547	i=0;
548	while(i<4){
549		buf[ETH_ARP_DST_IP_P+i]=*(ip_we_search +i);
550		buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i];
551		i++;
552	}
553	waitgwmac|=WGW_ACCEPT_ARP_REPLY;
554	enc28j60PacketSend(0x2a,buf);
555}
556
557byte client_waiting_gw(void) {
558	if (waitgwmac & WGW_HAVE_GW_MAC)
559		return 0;
560	return 1;
561}
562
563static byte client_store_gw_mac(byte *buf) {
564	byte i=0;
565	while(i<4){
566		if (buf[ETH_ARP_SRC_IP_P+i]!=gwip[i])
567			return 0;
568		i++;
569	}
570	i=0;
571	while(i<6){
572		gwmacaddr[i]=buf[ETH_ARP_SRC_MAC_P +i];
573		i++;
574	}
575	return 1;
576}
577
578static void client_gw_arp_refresh(void) {
579	if (waitgwmac & WGW_HAVE_GW_MAC)
580		waitgwmac|=WGW_REFRESHING;
581}
582
583void client_set_gwip(byte *gwipaddr) {
584	byte i=0;
585	waitgwmac=WGW_INITIAL_ARP; // causes an arp request in the packet loop
586	while(i<4){
587		gwip[i]=gwipaddr[i];
588		i++;
589	}
590}
591
592void client_tcp_set_serverip(byte *ipaddr) {
593	byte i=0;
594	while(i<4){
595		tcpsrvip[i]=ipaddr[i];
596		i++;
597	}
598}
599
600static void client_syn(byte *buf,byte srcport,byte dstport_h,byte dstport_l) {
601	byte i=0;
602	while(i<6){
603		buf[ETH_DST_MAC +i]=gwmacaddr[i]; // gw mac in local lan or host mac
604		buf[ETH_SRC_MAC +i]=macaddr[i];
605		i++;
606	}
607	buf[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
608	buf[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
609	fill_buf_p(&buf[IP_P],9,iphdr);
610	buf[IP_TOTLEN_L_P]=44; // good for syn
611	buf[IP_PROTO_P]=IP_PROTO_TCP_V;
612	i=0;
613	while(i<4){
614		buf[IP_DST_P+i]=tcpsrvip[i];
615		buf[IP_SRC_P+i]=ipaddr[i];
616		i++;
617	}
618	fill_ip_hdr_checksum(buf);
619	buf[TCP_DST_PORT_H_P]=dstport_h;
620	buf[TCP_DST_PORT_L_P]=dstport_l;
621	buf[TCP_SRC_PORT_H_P]=TCPCLIENT_SRC_PORT_H;
622	buf[TCP_SRC_PORT_L_P]=srcport; // lower 8 bit of src port
623	i=0;
624	while(i<8){
625		buf[TCP_SEQ_H_P+i]=0;
626		i++;
627	}
628	buf[TCP_SEQ_H_P+2]= seqnum; 
629	seqnum+=3;
630	buf[TCP_HEADER_LEN_P]=0x60; // 0x60=24 len: (0x60>>4) * 4
631	buf[TCP_FLAGS_P]=TCP_FLAGS_SYN_V;
632	buf[TCP_WIN_SIZE]=0x3; // 1024=0x400 768=0x300, initial window
633	buf[TCP_WIN_SIZE+1]=0x0;
634	buf[TCP_CHECKSUM_H_P]=0;
635	buf[TCP_CHECKSUM_L_P]=0;
636	buf[TCP_CHECKSUM_L_P+1]=0;
637	buf[TCP_CHECKSUM_L_P+2]=0;
638	buf[TCP_OPTIONS_P]=2;
639	buf[TCP_OPTIONS_P+1]=4;
640	buf[TCP_OPTIONS_P+2]=(CLIENTMSS>>8);
641	buf[TCP_OPTIONS_P+3]=CLIENTMSS;
642	uint16_t ck=checksum(&buf[IP_SRC_P], 8 +TCP_HEADER_LEN_PLAIN+4,2);
643	buf[TCP_CHECKSUM_H_P]=ck>>8;
644	buf[TCP_CHECKSUM_L_P]=ck;
645	// 4 is the tcp mss option:
646	enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN+4,buf);
647}
648
649byte client_tcp_req(byte (*result_callback)(byte fd,byte statuscode,uint16_t data_start_pos_in_buf, uint16_t len_of_data),uint16_t (*datafill_callback)(byte fd),uint16_t port) {
650	client_tcp_result_callback=result_callback;
651	client_tcp_datafill_callback=datafill_callback;
652	tcp_client_port_h=port>>8;
653	tcp_client_port_l=port;
654	tcp_client_state=1; // send a syn
655    tcp_fd = (tcp_fd + 1) & 7;
656	return tcp_fd;
657}
658
659static uint16_t www_client_internal_datafill_callback(byte fd){
660	char strbuf[5];
661	uint16_t len=0;
662	if (fd==www_fd){
663		if (browsertype==0){
664			len=fill_tcp_data_p(bufptr,0,PSTR("GET "));
665			len=fill_tcp_data_p(bufptr,len,client_urlbuf);
666			len=fill_tcp_data(bufptr,len,client_urlbuf_var);
667			len=fill_tcp_data_p(bufptr,len,PSTR(" HTTP/1.1\r\nHost: "));
668			len=fill_tcp_data_p(bufptr,len,client_hoststr);
669			len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.0\r\nAccept: text/html\r\nConnection: close\r\n\r\n"));
670		}else{
671			len=fill_tcp_data_p(bufptr,0,PSTR("POST "));
672			len=fill_tcp_data_p(bufptr,len,client_urlbuf);
673			len=fill_tcp_data_p(bufptr,len,PSTR(" HTTP/1.1\r\nHost: "));
674			len=fill_tcp_data_p(bufptr,len,client_hoststr);
675			if (client_additionalheaderline){
676				len=fill_tcp_data_p(bufptr,len,PSTR("\r\n"));
677				len=fill_tcp_data_p(bufptr,len,client_additionalheaderline);
678			}
679			len=fill_tcp_data_p(bufptr,len,PSTR("\r\nUser-Agent: tgr/1.1\r\nAccept: */*\r\nConnection: close\r\n"));
680			len=fill_tcp_data_p(bufptr,len,PSTR("Content-Length: "));
681			itoa(strlen(client_postval),strbuf,10);
682			len=fill_tcp_data(bufptr,len,strbuf);
683			len=fill_tcp_data_p(bufptr,len,PSTR("\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"));
684			len=fill_tcp_data(bufptr,len,client_postval);
685		}
686	}
687	return len;
688}
689
690static byte www_client_internal_result_callback(byte fd, byte statuscode, uint16_t datapos, uint16_t len_of_data){
691	if (fd!=www_fd)
692		(*client_browser_callback)(4,0,0);
693	else if (statuscode==0 && len_of_data>12 && client_browser_callback){
694        byte f = strncmp("200",(char *)&(bufptr[datapos+9]),3) != 0;
695		(*client_browser_callback)(f, ((uint16_t)TCP_SRC_PORT_H_P+(bufptr[TCP_HEADER_LEN_P]>>4)*4),len_of_data);
696	}
697	return 0;
698}
699
700void client_browse_url(prog_char *urlbuf, char *urlbuf_varpart, prog_char *hoststr,void (*callback)(byte,uint16_t,uint16_t)) {
701	client_urlbuf=urlbuf;
702	client_urlbuf_var=urlbuf_varpart;
703	client_hoststr=hoststr;
704	browsertype=0;
705	client_browser_callback=callback;
706	www_fd=client_tcp_req(&www_client_internal_result_callback,&www_client_internal_datafill_callback,80);
707}
708
709void client_http_post(prog_char *urlbuf, prog_char *hoststr, prog_char *additionalheaderline,char *postval,void (*callback)(byte,uint16_t,uint16_t)) {
710	client_urlbuf=urlbuf;
711	client_hoststr=hoststr;
712	client_additionalheaderline=additionalheaderline;
713	client_postval=postval;
714	browsertype=1;
715	client_browser_callback=callback;
716	www_fd=client_tcp_req(&www_client_internal_result_callback,&www_client_internal_datafill_callback,80);
717}
718
719void register_ping_rec_callback(void (*callback)(byte *srcip)) {
720	icmp_callback=callback;
721}
722
723byte packetloop_icmp_checkreply(byte *buf,byte *ip_monitoredhost) {
724	return buf[IP_PROTO_P]==IP_PROTO_ICMP_V &&
725	        buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREPLY_V &&
726	         buf[ICMP_DATA_P]== PINGPATTERN &&
727              check_ip_message_is_from(buf,ip_monitoredhost);
728}
729
730uint16_t packetloop_icmp_tcp(byte *buf,uint16_t plen) {
731	uint16_t len;
732	byte send_fin=0;
733	uint16_t tcpstart;
734	uint16_t save_len;
735	if (plen==0){
736		if ((waitgwmac & WGW_INITIAL_ARP||waitgwmac & WGW_REFRESHING) && delaycnt==0&& enc28j60linkup())
737			client_arp_whohas(buf,gwip);
738		delaycnt++;
739		if (tcp_client_state==1 && (waitgwmac & WGW_HAVE_GW_MAC)){ // send a syn
740			tcp_client_state=2;
741			tcpclient_src_port_l++; // allocate a new port
742			client_syn(buf,((tcp_fd<<5) | (0x1f & tcpclient_src_port_l)),tcp_client_port_h,tcp_client_port_l);
743		}
744		return 0;
745	}
746	if (eth_type_is_arp_and_my_ip(buf,plen)){
747		if (buf[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REQ_L_V)
748			make_arp_answer_from_request(buf);
749		if (waitgwmac & WGW_ACCEPT_ARP_REPLY && (buf[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REPLY_L_V) && client_store_gw_mac(buf))
750			waitgwmac=WGW_HAVE_GW_MAC;
751		return 0;
752	}
753	if (eth_type_is_ip_and_my_ip(buf,plen)==0)
754		return 0;
755	if (buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V){
756		if (icmp_callback)
757			(*icmp_callback)(&(buf[IP_SRC_P]));
758		make_echo_reply_from_request(buf,plen);
759		return 0;
760	}
761	if (plen<54 && buf[IP_PROTO_P]!=IP_PROTO_TCP_V )
762		return 0;
763	if ( buf[TCP_DST_PORT_H_P]==TCPCLIENT_SRC_PORT_H){
764		bufptr=buf; 
765		if (check_ip_message_is_from(buf,tcpsrvip)==0)
766			return 0;
767		if (buf[TCP_FLAGS_P] & TCP_FLAGS_RST_V){
768			if (client_tcp_result_callback)
769	(*client_tcp_result_callback)((buf[TCP_DST_PORT_L_P]>>5)&0x7,3,0,0);
770			tcp_client_state=5;
771			return 0;
772		}
773		len=get_tcp_data_len(buf);
774		if (tcp_client_state==2){
775			if ((buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) && (buf[TCP_FLAGS_P] &TCP_FLAGS_ACK_V)){
776				make_tcp_ack_from_any(buf,0,0);
777				buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V;
778				if (client_tcp_datafill_callback)
779	len=(*client_tcp_datafill_callback)((buf[TCP_SRC_PORT_L_P]>>5)&0x7);
780				else
781					len=0;
782				tcp_client_state=3;
783				make_tcp_ack_with_data_noflags(buf,len);
784				return 0;
785			}else{
786				tcp_client_state=1; // retry
787				len++;
788				if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
789					len=0;
790				make_tcp_ack_from_any(buf,len,TCP_FLAGS_RST_V);
791				return 0;
792			}
793		}
794		if (tcp_client_state==3 && len>0){ 
795			tcp_client_state=4;
796			if (client_tcp_result_callback){
797				tcpstart=TCP_DATA_START; // TCP_DATA_START is a formula
798				if (tcpstart>plen-8)
799					tcpstart=plen-8; // dummy but save
800				save_len=len;
801				if (tcpstart+len>plen)
802					save_len=plen-tcpstart;
803				send_fin = (*client_tcp_result_callback)((buf[TCP_DST_PORT_L_P]>>5)&0x7,0,tcpstart,save_len);
804			}
805			if (send_fin){
806				make_tcp_ack_from_any(buf,len,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
807				tcp_client_state=5;
808				return 0;
809			}
810		}
811		if (tcp_client_state==5)
812			return 0;
813		if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V){
814			make_tcp_ack_from_any(buf,len+1,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
815			tcp_client_state=5; // connection terminated
816			return 0;
817		}
818		if (len>0)
819			make_tcp_ack_from_any(buf,len,0);
820		return 0;
821	}
822	if (buf[TCP_DST_PORT_H_P]==wwwport_h && buf[TCP_DST_PORT_L_P]==wwwport_l){
823		if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V){
824			make_tcp_synack_from_syn(buf);
825			return 0;
826		}
827		if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
828			info_data_len=get_tcp_data_len(buf);
829			if (info_data_len==0){
830				if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V)
831					make_tcp_ack_from_any(buf,0,0);
832				return 0;
833			}
834			len=TCP_DATA_START; // TCP_DATA_START is a formula
835			if (len>plen-8)
836				return 0;
837			return len;
838		}
839	}
840	return 0;
841}