add initial support for the crisarchitecture used on foxboards to openwrt
[openwrt/staging/lynxis/omap.git] / target / linux / etrax-2.6 / image / e100boot / src / sbl / network.c
1 /*!***************************************************************************
2 *!
3 *! FILE NAME : network.c
4 *!
5 *! DESCRIPTION: Network boot stuff for e100boot.
6 *!
7 *! ---------------------------------------------------------------------------
8 *! HISTORY
9 *!
10 *! DATE NAME CHANGES
11 *! ---- ---- -------
12 *! 1996 Ronny Raneup Initial version
13 *! 2002 05 02 Ronny Ranerup Moved it into this file
14 *! ---------------------------------------------------------------------------
15 *! (C) Copyright 1999, 2000, 2001, 2002 Axis Communications AB, LUND, SWEDEN
16 *!***************************************************************************/
17
18 /************************** Include files ********************************/
19
20 #include <stdio.h>
21 #include <pcap.h>
22 #include <conf.h> /* from configure */
23
24 #include <e100boot.h>
25 #include <common.h>
26 #include <network.h>
27
28 /************************** Constants and macros *************************/
29
30 #define CRC_LEN 4
31
32 /************************** Type definitions *****************************/
33
34 /************************** Global variables *****************************/
35
36 udword highest_ack_received;
37 udword last_ack_received = -1;
38 int new_ack = FALSE;
39 int got_new_packet = FALSE;
40
41 unsigned char dst_addr_of_device[] = { 0x01, 0x40, 0x8c, 0x00, 0x01, 0x00 };
42 unsigned char src_addr_of_device[] = { 0x02, 0x40, 0x8c, 0x00, 0x01, 0x00 };
43 unsigned char eth_addr_local[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
44
45 struct sockaddr sock_addr;
46 int sock_fd;
47 int pPacket = 0;
48 pcap_t *pd;
49
50 pcap_handler handler;
51
52 struct packet_buf first_rec_packet;
53 struct packet_buf *last_rec_packet = &first_rec_packet;
54
55 int promisc = 1; /* promiscuous mode */
56 int all_ids = TRUE;
57
58 int both_addresses = FALSE;
59 int p_packet_bpl = 8;
60 int printPacketType = CHAR;
61
62 unsigned int id;
63 int one_id_only = TRUE;
64
65 unsigned char buf[10000]; /* pcap buffer */
66
67 const struct pcap_pkthdr *hdrG;
68
69 char host1[MAX_STRING_LEN]; /* name of ethernet host */
70 char host2[MAX_STRING_LEN]; /* name of ethernet host */
71
72 /************************** Function prototypes **************************/
73
74 int timeout (struct timeval *tvThen, int ms);
75 int InitSendSocket (char *device_name);
76 int highest_seq_received (void);
77 struct packet_buf* ack_on_seq (int seq);
78 struct packet_buf* packet_with_seq (int seq);
79 struct timeval timeval_subtract (struct timeval *x, struct timeval *y);
80 void GetNextPacket (void);
81 void PrintPacket (const unsigned char *p, int size, int type);
82
83 /****************************************************************************
84 *#
85 *# FUNCTION NAME: net_init
86 *#
87 *# DESCRIPTION:
88 *#
89 *#---------------------------------------------------------------------------
90 *# HISTORY
91 *#
92 *# DATE NAME CHANGES
93 *# ---- ---- -------
94 *# 2002 05 02 ronny Initial version
95 *#
96 *#***************************************************************************/
97 void
98 net_init(void)
99 {
100 static char *dev;
101 static char errBuf[1000];
102
103 GetLocalEthAddr();
104 first_rec_packet.data = malloc(PACKET_SIZE);
105
106 if ((dev = pcap_lookupdev(errBuf)) == NULL) {
107 printf("Error %s\n", errBuf);
108 if (errno == EPERM)
109 {
110 printf("Make sure this program is executed with root privileges.\n");
111 }
112
113 exit(EXIT_FAILURE);
114 }
115
116 if ((pd = pcap_open_live(device, 200, promisc, 10, errBuf)) == NULL) {
117 printf("Error %s\n", errBuf);
118 if (errno == EPERM)
119 {
120 printf("Make sure this program is executed with root privileges.\n");
121 }
122
123 exit(EXIT_FAILURE);
124 }
125
126 handler = (pcap_handler) Handler;
127
128 InitSendSocket(device);
129 }
130
131 /****************************************************************************
132 *#
133 *# FUNCTION NAME: NetBoot
134 *#
135 *# DESCRIPTION: The main network boot routine.
136 *#
137 *#---------------------------------------------------------------------------
138 *# HISTORY
139 *#
140 *# DATE NAME CHANGES
141 *# ---- ---- -------
142 *# 2000 01 07 ronny Initial version
143 *# 2002 05 02 ronny Fixed segv bug
144 *#
145 *#***************************************************************************/
146
147 void
148 NetBoot(void)
149 {
150 struct packet_buf *p;
151 struct timeval tv;
152
153 gettimeofday(&tv, NULL);
154
155 p = create_packet(0);
156 SendToDevice(p->data, p->size);
157
158 while(1) {
159 static int all_trans = FALSE;
160
161 if (got_new_packet) {
162 got_new_packet = FALSE;
163
164 if (new_ack && first_packet) {
165 if (db4) {
166 printf("* got ACK %d.\n", last_ack_received);
167 printf("* ACK wanted %d.\n", first_packet->seq);
168 }
169 if (last_ack_received == first_packet->seq) {
170 if (!(p = create_packet(first_packet->seq+1))) {
171 //break;
172 }
173 first_packet = free_packet(first_packet);
174 }
175 }
176 }
177
178 if (new_ack || timeout(&tv, 500)) {
179 if (p) {
180 SendToDevice(p->data, p->size);
181 }
182 new_ack = FALSE;
183 gettimeofday(&tv, NULL);
184 }
185
186 GetNextPacket();
187 }
188 }
189
190 /****************************************************************************
191 *#
192 *# FUNCTION NAME: GetNextPacket
193 *#
194 *# DESCRIPTION:
195 *#
196 *#---------------------------------------------------------------------------
197 *# HISTORY
198 *#
199 *# DATE NAME CHANGES
200 *# ---- ---- -------
201 *# 961022 ronny Initial version
202 *#
203 *#***************************************************************************/
204
205 void
206 GetNextPacket(void)
207 {
208 int ret;
209
210 if (db2) printf("> GetNextPacket\n");
211
212 /* got_new_packet = FALSE;*/
213 if ((ret = pcap_dispatch(pd, 1, handler, buf)) == -1) {
214 pcap_perror(pd, "Error in pcap_dispatch");
215 exit(EXIT_FAILURE);
216 }
217
218 if (db2) printf("< GetNextPacket\n");
219 }
220
221 /****************************************************************************
222 *#
223 *# FUNCTION NAME: Handler
224 *#
225 *# PARAMETERS:
226 *#
227 *# DESCRIPTION:
228 *#
229 *#---------------------------------------------------------------------------
230 *# HISTORY
231 *#
232 *# DATE NAME CHANGES
233 *# ---- ---- -------
234 *# 961022 ronny Initial version
235 *#
236 *#***************************************************************************/
237
238 void
239 Handler(unsigned char *buf, const struct pcap_pkthdr *hdr,
240 const unsigned char *p)
241 {
242 const unsigned char *src = &p[6];
243 const unsigned char *dst = &p[0];
244 struct packet_header_T *h = (struct packet_header_T*)p;
245
246 if (db2) printf("> Handler\n");
247 got_new_packet = TRUE;
248 if ((!memcmp(src, eth_addr_local, 6) && !memcmp(dst, dst_addr_of_device, 6))
249 || (!memcmp(src, src_addr_of_device, 6) && !memcmp(dst, eth_addr_local, 6))) {
250 if (db1) printf("#RX######################################################\n");
251 if (db1) printf("Length: %u(0x%x)\n", (udword)hdr->len, (udword)hdr->len);
252 if (pPacket) PrintPacket(p, hdr->caplen, printPacketType);
253 DecodeSvintoBoot(p);
254 /* should clean up this... */
255 if ((ntohl(h->type) == ACK)) {
256 if (all_ids || (ntohl(h->id) == id)) {
257 if (all_ids && one_id_only) {
258 if (ntohl(h->id) == 0) {
259 all_ids = FALSE;
260 id = ntohl(h->id);
261 printf("Booting device with random id %8.8x.\n", id);
262 }
263 }
264 }
265 else {
266 printf("Got ACK from a new id, %8.8lx. Ignoring.\n",
267 (unsigned long)ntohl(h->id));
268 return;
269 }
270 new_ack = TRUE;
271 last_ack_received = ntohl(h->seq);
272 if (last_ack_received > highest_ack_received) {
273 highest_ack_received = last_ack_received;
274 }
275 }
276
277 if (db1) printf("#########################################################\n");
278
279 }
280 if (db2) printf("< Handler\n");
281 }
282
283 /****************************************************************************
284 *#
285 *# FUNCTION NAME: ack_on_seq
286 *#
287 *# PARAMETERS:
288 *#
289 *# DESCRIPTION:
290 *#
291 *#---------------------------------------------------------------------------
292 *# HISTORY
293 *#
294 *# DATE NAME CHANGES
295 *# ---- ---- -------
296 *# 980817 ronny Initial version
297 *#
298 *#***************************************************************************/
299
300 struct packet_buf *
301 packet_with_seq(int seq)
302 {
303 static int last_seq = 0;
304 struct packet_buf *p = first_packet;
305 struct packet_header_T *h;
306
307 if (seq < last_seq) {
308 p = first_packet;
309 }
310
311 while(p) {
312 h = (struct packet_header_T*)p->data;
313 if (ntohl(h->seq) == seq) {
314 return(p);
315 }
316 p = p->next;
317 }
318 return(NULL);
319 }
320
321 struct packet_buf *
322 ack_on_seq(int seq)
323 {
324 struct packet_buf *p = &first_rec_packet;
325 struct packet_header_T *h;
326
327 if (db1) printf("***> ack_on_seq: %d.\n", seq);
328
329 while (p) {
330 /* printf("\nPacket at %x.\n", p);*/
331 /* DecodeSvintoBoot(p->data);*/
332 h = (struct packet_header_T*)p->data;
333 if ( (ntohl(h->type) == ACK) && (ntohl(h->seq) == seq) ) {
334 if (all_ids || ntohl(h->id) == id) {
335 printf("***< ack_on_seq %d, ok.\n", seq);
336 return(p);
337 }
338 }
339 p = p->next;
340 }
341 if (db1) printf("***< ack_on_seq, no.\n");
342 return(NULL);
343 }
344
345 int
346 highest_seq_received(void)
347 {
348 struct packet_buf *p = &first_rec_packet;
349 struct packet_header_T *h;
350 int highest_seq = -1;
351
352 if (db1) printf("***> highest_seq_received\n");
353
354 while (p) {
355 /* printf("\nPacket at %x.\n", p);*/
356 /* DecodeSvintoBoot(p->data);*/
357 h = (struct packet_header_T*)p->data;
358 if ((ntohl(h->type) == ACK) && (all_ids || (ntohl(h->id) == id))) {
359 if ((int)ntohl(h->seq) > highest_seq) {
360 highest_seq = ntohl(h->seq);
361 if (db4) printf("Highest seq: %d\n", highest_seq);
362 }
363 }
364 p = p->next;
365 }
366
367 if (db1) printf("***< highest_seq_received: %d\n", highest_seq);
368 return(highest_seq);
369 }
370
371 /****************************************************************************
372 *#
373 *# FUNCTION NAME: PrintPacket
374 *#
375 *# PARAMETERS:
376 *#
377 *# DESCRIPTION:
378 *#
379 *#---------------------------------------------------------------------------
380 *# HISTORY
381 *#
382 *# DATE NAME CHANGES
383 *# ---- ---- -------
384 *# 961022 ronny Initial version
385 *#
386 *#***************************************************************************/
387
388 void
389 PrintPacket(const unsigned char *p, int size, int type)
390 {
391 int i;
392
393 /* printf("size %d\n", size);*/
394 for (i = 0; i != size; i++) {
395 if (i % p_packet_bpl == 0)
396 printf("\n%-4.4d: ", i);
397 if (type == UDEC)
398 printf("%-3d ", p[i]);
399 else if (type == HEX)
400 printf("%-2.2x ", p[i]);
401 else if (type == CHAR) {
402 if (isprint(p[i]))
403 printf("%-3c ", p[i]);
404 else
405 printf("%-3d ", p[i]);
406 }
407 else if (type == ASCII) {
408 if (isprint(p[i]))
409 printf("%c", p[i]);
410 else
411 printf(".");
412 }
413 }
414 printf("\n");
415 }
416
417 /****************************************************************************
418 *#
419 *# FUNCTION NAME: DecodeSvintoBoot
420 *#
421 *# PARAMETERS:
422 *#
423 *# DESCRIPTION: Decodes packets that follow the e100boot protocol.
424 *#
425 *#---------------------------------------------------------------------------
426 *# HISTORY
427 *#
428 *# DATE NAME CHANGES
429 *# ---- ---- -------
430 *# 961022 ronny Initial version
431 *#
432 *#***************************************************************************/
433
434 void
435 DecodeSvintoBoot(const unsigned char *p)
436 {
437 char *str;
438 volatile struct packet_header_T *ph = (struct packet_header_T*)p;
439
440 /* printf("size %d \n", sizeof(struct packet_header_T));*/
441
442 if (db4) printf("\n>DecodeSvintoBoot. Packet at 0x%x\n", (unsigned int)p);
443 if (db1) {
444 printf("%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x -> ", p[6],p[7],p[8],p[9],p[10], p[11]);
445 printf("%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n", p[0],p[1],p[2],p[3],p[4], p[5]);
446
447 printf("length : %4.4lx\n", (long)ntohs(ph->length));
448 printf("snap1 : %8.8lx\n", (long)ntohl(ph->snap1));
449 printf("snap2 : %8.8lx\n", (long)ntohl(ph->snap2));
450
451 switch (ntohl(ph->tag)) {
452 case 0xffffffff:
453 str = "(host > ETRAX)";
454 break;
455 case 0xfffffffe:
456 str = "(host < ETRAX)";
457 break;
458 default:
459 str = "(unknown)";
460 break;
461 }
462 printf("tag : %8.8lx %s\n", (unsigned long)ntohl(ph->tag), str);
463 printf("seq : %8.8lx\n", (unsigned long)ntohl(ph->seq));
464 }
465
466 switch (ntohl(ph->type)) {
467
468 case STRING:
469 str = "(STRING)";
470 fprintf(stderr, "%s", &p[sizeof(struct packet_header_T)]);
471 find_string((char*)&p[sizeof(struct packet_header_T)]);
472 break;
473
474 case NET_INT: {
475 char search_str[20];
476
477 str = "(NET_INT)";
478 sprintf(search_str, "0x%8.8x", ntohl(*(udword*)&p[sizeof(struct packet_header_T)]));
479 fprintf(stderr, search_str);
480 find_string(search_str);
481 break;
482 }
483
484 case NET_INT_NL: {
485 char search_str[20];
486
487 str = "(NET_INT_NL)";
488 sprintf(search_str, "0x%8.8x\n", ntohl(*(udword*)&p[sizeof(struct packet_header_T)]));
489 fprintf(stderr, search_str);
490 find_string(search_str);
491 break;
492 }
493
494 case ACK:
495 str = "(ACK)";
496 break;
497
498 case BOOT_PACKET:
499 str = "(bootpacket)";
500 break;
501
502 case BOOT_CMDS:
503 str = "(bootcmds)";
504 break;
505
506 default:
507 str = "(unknown)";
508 break;
509 }
510
511 if (db1) {
512 printf("(type : %8.8lx %s)\n", (unsigned long)ntohl(ph->type), str);
513 printf("(id : %8.8lx)\n", (unsigned long)ntohl(ph->id));
514 id = ntohl(ph->id);
515 }
516 }
517
518 /****************************************************************************
519 *#
520 *# FUNCTION NAME: GetLocalEthAddr
521 *#
522 *# PARAMETERS: None.
523 *#
524 *# DESCRIPTION:
525 *#
526 *#---------------------------------------------------------------------------
527 *# DATE NAME CHANGES
528 *# ---- ---- -------
529 *# 980818 ronny Initial version
530 *#
531 *#***************************************************************************/
532
533 void
534 GetLocalEthAddr(void)
535 {
536 int fd;
537 struct ifreq ifr;
538
539 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
540 perror("socket (GetLocalEthAddr)");
541 exit(EXIT_FAILURE);
542 }
543
544 strcpy(ifr.ifr_name, device);
545 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
546 perror("ioctl");
547 exit(EXIT_FAILURE);
548 }
549
550 memcpy(eth_addr_local, ifr.ifr_hwaddr.sa_data, 6);
551 if (db1) printf("Ethernet adress for device %s is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
552 device,
553 eth_addr_local[0],
554 eth_addr_local[1],
555 eth_addr_local[2],
556 eth_addr_local[3],
557 eth_addr_local[4],
558 eth_addr_local[5]);
559 shutdown(fd, 2);
560 }
561
562 /****************************************************************************
563 *#
564 *# FUNCTION NAME: SendToDevice
565 *#
566 *# PARAMETERS:
567 *#
568 *# DESCRIPTION:
569 *#
570 *#---------------------------------------------------------------------------
571 *# DATE NAME CHANGES
572 *# ---- ---- -------
573 *# 980818 ronny Initial version
574 *#
575 *#***************************************************************************/
576
577 void
578 SendToDevice(unsigned char *data, int data_len)
579 {
580 char fName[MAX_STRING_LEN];
581 FILE *fd;
582 struct packet_header_T *h = (struct packet_header_T*) data;
583
584 if (db1) printf("***> SendToDevice\n");
585
586 if (db2) printf("Sending %d bytes at 0x%x to %s.\n", data_len, (unsigned int)data, device);
587 if (db1) printf("#TX######################################################\n");
588 if (db1) DecodeSvintoBoot(data);
589
590 if (db1) printf("#########################################################\n");
591 if (toFiles || cmdsOnly) {
592 if (cmdsOnly) { /* use a simpler name */
593 sprintf(fName, "e100boot.cmds");
594 }
595 else {
596 sprintf(fName, "e100boot.seq%lu", (unsigned long)ntohl(h->seq));
597 }
598 if (db2) printf("Writing packet to file '%s'.\n", fName);
599 if ((fd = fopen(fName, "w+")) == NULL) {
600 printf("Cannot open/create '%s'. %s.\n", fName, strerror(errno));
601 exit(EXIT_FAILURE);
602 }
603 fwrite(data, data_len, 1, fd);
604 fclose(fd);
605 }
606 else if (sendto(sock_fd, data, data_len, 0, &sock_addr, sizeof(sock_addr)) < 0) {
607 perror("Sendto failed:");
608 exit(EXIT_FAILURE);
609 }
610
611 if (db1) printf("<*** SendToDevice\n");
612 }
613
614 /****************************************************************************
615 *#
616 *# FUNCTION NAME: InitSendSocket
617 *#
618 *# PARAMETERS:
619 *#
620 *# DESCRIPTION:
621 *#
622 *#---------------------------------------------------------------------------
623 *# DATE NAME CHANGES
624 *# ---- ---- -------
625 *# 980818 ronny Initial version
626 *#***************************************************************************/
627
628 int
629 InitSendSocket(char *device_name)
630 {
631 if ((sock_fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
632 perror("Socket call failed:");
633 exit(EXIT_FAILURE);
634 }
635
636 fcntl(sock_fd, F_SETFL, O_NDELAY);
637
638 sock_addr.sa_family = AF_INET;
639 strcpy(sock_addr.sa_data, device_name);
640
641 return sock_fd;
642 }
643
644 /****************************************************************************
645 *#
646 *# FUNCTION NAME: timeout
647 *#
648 *# PARAMETERS:
649 *#
650 *# DESCRIPTION:
651 *#
652 *#---------------------------------------------------------------------------
653 *# HISTORY
654 *#
655 *# DATE NAME CHANGES
656 *# ---- ---- -------
657 *# 980817 ronny Initial version
658 *#
659 *#***************************************************************************/
660
661 int
662 timeout(struct timeval *tvThen, int ms)
663 {
664 struct timeval tvNow;
665 struct timeval tvDiff;
666
667 (void) gettimeofday(&tvNow, NULL);
668 tvDiff = timeval_subtract(&tvNow, tvThen);
669 if (db4) printf("sec %d.%d\n", (int)tvDiff.tv_sec, (int)tvDiff.tv_usec);
670 if (ms * 1000 < (tvDiff.tv_sec * 1000000 + tvDiff.tv_usec)) {
671 if (db4) printf("TIMEOUT\n");
672 return(TRUE);
673 }
674
675 return(FALSE);
676 }
677
678 /****************************************************************************
679 *#
680 *# FUNCTION NAME: timeval_subtract
681 *#
682 *# PARAMETERS:
683 *#
684 *# DESCRIPTION: Subtract x-y, and return result.
685 *#
686 *# DATE NAME CHANGES
687 *# ---- ---- -------
688 *# 970128 ronny Initial version
689 *#
690 *#***************************************************************************/
691
692 struct timeval
693 timeval_subtract(struct timeval *x, struct timeval *y)
694 {
695 struct timeval diff;
696
697 diff.tv_sec = x->tv_sec - y->tv_sec;
698 diff.tv_usec = x->tv_usec - y->tv_usec;
699
700 if (diff.tv_usec < 0) {
701 diff.tv_sec--;
702 diff.tv_usec = 1000000 + diff.tv_usec;
703 }
704
705 return diff;
706 }