1 /*!***************************************************************************
3 *! FILE NAME : network.c
5 *! DESCRIPTION: Network boot stuff for e100boot.
7 *! ---------------------------------------------------------------------------
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 *!***************************************************************************/
18 /************************** Include files ********************************/
22 #include <conf.h> /* from configure */
28 /************************** Constants and macros *************************/
32 /************************** Type definitions *****************************/
34 /************************** Global variables *****************************/
36 udword highest_ack_received
;
37 udword last_ack_received
= -1;
39 int got_new_packet
= FALSE
;
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 };
45 struct sockaddr sock_addr
;
52 struct packet_buf first_rec_packet
;
53 struct packet_buf
*last_rec_packet
= &first_rec_packet
;
55 int promisc
= 1; /* promiscuous mode */
58 int both_addresses
= FALSE
;
60 int printPacketType
= CHAR
;
63 int one_id_only
= TRUE
;
65 unsigned char buf
[10000]; /* pcap buffer */
67 const struct pcap_pkthdr
*hdrG
;
69 char host1
[MAX_STRING_LEN
]; /* name of ethernet host */
70 char host2
[MAX_STRING_LEN
]; /* name of ethernet host */
72 /************************** Function prototypes **************************/
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
);
83 /****************************************************************************
85 *# FUNCTION NAME: net_init
89 *#---------------------------------------------------------------------------
94 *# 2002 05 02 ronny Initial version
96 *#***************************************************************************/
101 static char errBuf
[1000];
104 first_rec_packet
.data
= malloc(PACKET_SIZE
);
106 if ((dev
= pcap_lookupdev(errBuf
)) == NULL
) {
107 printf("Error %s\n", errBuf
);
110 printf("Make sure this program is executed with root privileges.\n");
116 if ((pd
= pcap_open_live(device
, 200, promisc
, 10, errBuf
)) == NULL
) {
117 printf("Error %s\n", errBuf
);
120 printf("Make sure this program is executed with root privileges.\n");
126 handler
= (pcap_handler
) Handler
;
128 InitSendSocket(device
);
131 /****************************************************************************
133 *# FUNCTION NAME: NetBoot
135 *# DESCRIPTION: The main network boot routine.
137 *#---------------------------------------------------------------------------
142 *# 2000 01 07 ronny Initial version
143 *# 2002 05 02 ronny Fixed segv bug
145 *#***************************************************************************/
150 struct packet_buf
*p
;
153 gettimeofday(&tv
, NULL
);
155 p
= create_packet(0);
156 SendToDevice(p
->data
, p
->size
);
159 static int all_trans
= FALSE
;
161 if (got_new_packet
) {
162 got_new_packet
= FALSE
;
164 if (new_ack
&& first_packet
) {
166 printf("* got ACK %d.\n", last_ack_received
);
167 printf("* ACK wanted %d.\n", first_packet
->seq
);
169 if (last_ack_received
== first_packet
->seq
) {
170 if (!(p
= create_packet(first_packet
->seq
+1))) {
173 first_packet
= free_packet(first_packet
);
178 if (new_ack
|| timeout(&tv
, 500)) {
180 SendToDevice(p
->data
, p
->size
);
183 gettimeofday(&tv
, NULL
);
190 /****************************************************************************
192 *# FUNCTION NAME: GetNextPacket
196 *#---------------------------------------------------------------------------
201 *# 961022 ronny Initial version
203 *#***************************************************************************/
210 if (db2
) printf("> GetNextPacket\n");
212 /* got_new_packet = FALSE;*/
213 if ((ret
= pcap_dispatch(pd
, 1, handler
, buf
)) == -1) {
214 pcap_perror(pd
, "Error in pcap_dispatch");
218 if (db2
) printf("< GetNextPacket\n");
221 /****************************************************************************
223 *# FUNCTION NAME: Handler
229 *#---------------------------------------------------------------------------
234 *# 961022 ronny Initial version
236 *#***************************************************************************/
239 Handler(unsigned char *buf
, const struct pcap_pkthdr
*hdr
,
240 const unsigned char *p
)
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
;
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
);
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) {
261 printf("Booting device with random id %8.8x.\n", id
);
266 printf("Got ACK from a new id, %8.8lx. Ignoring.\n",
267 (unsigned long)ntohl(h
->id
));
271 last_ack_received
= ntohl(h
->seq
);
272 if (last_ack_received
> highest_ack_received
) {
273 highest_ack_received
= last_ack_received
;
277 if (db1
) printf("#########################################################\n");
280 if (db2
) printf("< Handler\n");
283 /****************************************************************************
285 *# FUNCTION NAME: ack_on_seq
291 *#---------------------------------------------------------------------------
296 *# 980817 ronny Initial version
298 *#***************************************************************************/
301 packet_with_seq(int seq
)
303 static int last_seq
= 0;
304 struct packet_buf
*p
= first_packet
;
305 struct packet_header_T
*h
;
307 if (seq
< last_seq
) {
312 h
= (struct packet_header_T
*)p
->data
;
313 if (ntohl(h
->seq
) == seq
) {
324 struct packet_buf
*p
= &first_rec_packet
;
325 struct packet_header_T
*h
;
327 if (db1
) printf("***> ack_on_seq: %d.\n", seq
);
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
);
341 if (db1
) printf("***< ack_on_seq, no.\n");
346 highest_seq_received(void)
348 struct packet_buf
*p
= &first_rec_packet
;
349 struct packet_header_T
*h
;
350 int highest_seq
= -1;
352 if (db1
) printf("***> highest_seq_received\n");
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
);
367 if (db1
) printf("***< highest_seq_received: %d\n", highest_seq
);
371 /****************************************************************************
373 *# FUNCTION NAME: PrintPacket
379 *#---------------------------------------------------------------------------
384 *# 961022 ronny Initial version
386 *#***************************************************************************/
389 PrintPacket(const unsigned char *p
, int size
, int type
)
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
);
398 printf("%-3d ", p
[i
]);
399 else if (type
== HEX
)
400 printf("%-2.2x ", p
[i
]);
401 else if (type
== CHAR
) {
403 printf("%-3c ", p
[i
]);
405 printf("%-3d ", p
[i
]);
407 else if (type
== ASCII
) {
417 /****************************************************************************
419 *# FUNCTION NAME: DecodeSvintoBoot
423 *# DESCRIPTION: Decodes packets that follow the e100boot protocol.
425 *#---------------------------------------------------------------------------
430 *# 961022 ronny Initial version
432 *#***************************************************************************/
435 DecodeSvintoBoot(const unsigned char *p
)
438 volatile struct packet_header_T
*ph
= (struct packet_header_T
*)p
;
440 /* printf("size %d \n", sizeof(struct packet_header_T));*/
442 if (db4
) printf("\n>DecodeSvintoBoot. Packet at 0x%x\n", (unsigned int)p
);
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]);
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
));
451 switch (ntohl(ph
->tag
)) {
453 str
= "(host > ETRAX)";
456 str
= "(host < ETRAX)";
462 printf("tag : %8.8lx %s\n", (unsigned long)ntohl(ph
->tag
), str
);
463 printf("seq : %8.8lx\n", (unsigned long)ntohl(ph
->seq
));
466 switch (ntohl(ph
->type
)) {
470 fprintf(stderr
, "%s", &p
[sizeof(struct packet_header_T
)]);
471 find_string((char*)&p
[sizeof(struct packet_header_T
)]);
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
);
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
);
499 str
= "(bootpacket)";
512 printf("(type : %8.8lx %s)\n", (unsigned long)ntohl(ph
->type
), str
);
513 printf("(id : %8.8lx)\n", (unsigned long)ntohl(ph
->id
));
518 /****************************************************************************
520 *# FUNCTION NAME: GetLocalEthAddr
526 *#---------------------------------------------------------------------------
529 *# 980818 ronny Initial version
531 *#***************************************************************************/
534 GetLocalEthAddr(void)
539 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
540 perror("socket (GetLocalEthAddr)");
544 strcpy(ifr
.ifr_name
, device
);
545 if (ioctl(fd
, SIOCGIFHWADDR
, &ifr
) < 0) {
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",
562 /****************************************************************************
564 *# FUNCTION NAME: SendToDevice
570 *#---------------------------------------------------------------------------
573 *# 980818 ronny Initial version
575 *#***************************************************************************/
578 SendToDevice(unsigned char *data
, int data_len
)
580 char fName
[MAX_STRING_LEN
];
582 struct packet_header_T
*h
= (struct packet_header_T
*) data
;
584 if (db1
) printf("***> SendToDevice\n");
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
);
590 if (db1
) printf("#########################################################\n");
591 if (toFiles
|| cmdsOnly
) {
592 if (cmdsOnly
) { /* use a simpler name */
593 sprintf(fName
, "e100boot.cmds");
596 sprintf(fName
, "e100boot.seq%lu", (unsigned long)ntohl(h
->seq
));
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
));
603 fwrite(data
, data_len
, 1, fd
);
606 else if (sendto(sock_fd
, data
, data_len
, 0, &sock_addr
, sizeof(sock_addr
)) < 0) {
607 perror("Sendto failed:");
611 if (db1
) printf("<*** SendToDevice\n");
614 /****************************************************************************
616 *# FUNCTION NAME: InitSendSocket
622 *#---------------------------------------------------------------------------
625 *# 980818 ronny Initial version
626 *#***************************************************************************/
629 InitSendSocket(char *device_name
)
631 if ((sock_fd
= socket(AF_INET
, SOCK_PACKET
, htons(ETH_P_ALL
))) < 0) {
632 perror("Socket call failed:");
636 fcntl(sock_fd
, F_SETFL
, O_NDELAY
);
638 sock_addr
.sa_family
= AF_INET
;
639 strcpy(sock_addr
.sa_data
, device_name
);
644 /****************************************************************************
646 *# FUNCTION NAME: timeout
652 *#---------------------------------------------------------------------------
657 *# 980817 ronny Initial version
659 *#***************************************************************************/
662 timeout(struct timeval
*tvThen
, int ms
)
664 struct timeval tvNow
;
665 struct timeval tvDiff
;
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");
678 /****************************************************************************
680 *# FUNCTION NAME: timeval_subtract
684 *# DESCRIPTION: Subtract x-y, and return result.
688 *# 970128 ronny Initial version
690 *#***************************************************************************/
693 timeval_subtract(struct timeval
*x
, struct timeval
*y
)
697 diff
.tv_sec
= x
->tv_sec
- y
->tv_sec
;
698 diff
.tv_usec
= x
->tv_usec
- y
->tv_usec
;
700 if (diff
.tv_usec
< 0) {
702 diff
.tv_usec
= 1000000 + diff
.tv_usec
;