Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netapps / netboot.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <netlib/tftp.h>
14 #include <netlib/ethernet.h>
15 #include <netlib/dhcp.h>
16 #include <netlib/dhcpv6.h>
17 #include <netlib/ipv4.h>
18 #include <netlib/ipv6.h>
19 #include <netlib/dns.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <time.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <netapps/args.h>
26 #include <libbootmsg/libbootmsg.h>
27 #include <of.h>
28 #include "netapps.h"
29
30 #define IP_INIT_DEFAULT 5
31 #define IP_INIT_NONE    0
32 #define IP_INIT_BOOTP   1
33 #define IP_INIT_DHCP    2
34 #define IP_INIT_DHCPV6_STATELESS    3
35 #define IP_INIT_IPV6_MANUAL         4
36
37 #define DEFAULT_BOOT_RETRIES 10
38 #define DEFAULT_TFTP_RETRIES 20
39 static int ip_version = 4;
40
41 typedef struct {
42         char filename[100];
43         int  ip_init;
44         char siaddr[4];
45         ip6_addr_t si6addr;
46         char ciaddr[4];
47         ip6_addr_t ci6addr;
48         char giaddr[4];
49         ip6_addr_t gi6addr;
50         int  bootp_retries;
51         int  tftp_retries;
52 } obp_tftp_args_t;
53
54
55 /**
56  * Parses a argument string for IPv6 booting, extracts all
57  * parameters and fills a structure accordingly
58  *
59  * @param  arg_str        string with arguments, separated with ','
60  * @param  argc           number of arguments
61  * @param  obp_tftp_args  structure which contains the result
62  * @return                updated arg_str
63  */
64 static const char * 
65 parse_ipv6args (const char *arg_str, unsigned int argc,
66                 obp_tftp_args_t *obp_tftp_args)
67 {
68         char *ptr = NULL;
69         char arg_buf[100];
70
71         // find out siaddr
72         if (argc == 0)
73                 memset(&obp_tftp_args->si6addr.addr, 0, 16);
74         else {
75                 argncpy(arg_str, 0, arg_buf, 100);
76                 if(str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) {
77                         arg_str = get_arg_ptr(arg_str, 1);
78                         --argc;
79                 }
80                 else if(arg_buf[0] == 0) {
81                         memset(&obp_tftp_args->si6addr.addr, 0, 16);
82                         arg_str = get_arg_ptr(arg_str, 1);
83                         --argc;
84                 }
85                 else
86                         memset(&obp_tftp_args->si6addr.addr, 0, 16);
87         }
88
89         // find out filename
90         if (argc == 0)
91                 obp_tftp_args->filename[0] = 0;
92         else {
93                 argncpy(arg_str, 0, obp_tftp_args->filename, 100);
94                 for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr)
95                         if(*ptr == '\\') {
96                                 *ptr = '/';
97                         }
98                 arg_str = get_arg_ptr(arg_str, 1);
99                 --argc;
100         }
101
102         // find out ciaddr
103         if (argc == 0)
104                 memset(&obp_tftp_args->ci6addr, 0, 16);
105         else {
106                 argncpy(arg_str, 0, arg_buf, 100);
107                 if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr[0]))) {
108                         arg_str = get_arg_ptr(arg_str, 1);
109                         --argc;
110                 }
111                 else if(arg_buf[0] == 0) {
112                         memset(&obp_tftp_args->ci6addr.addr, 0, 16);
113                         arg_str = get_arg_ptr(arg_str, 1);
114                         --argc;
115                 }
116                 else
117                         memset(&obp_tftp_args->ci6addr.addr, 0, 16);
118         }
119
120         // find out giaddr
121         if (argc == 0)
122                 memset(&obp_tftp_args->gi6addr, 0, 16);
123         else {
124                 argncpy(arg_str, 0, arg_buf, 100);
125                 if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) {
126                         arg_str = get_arg_ptr(arg_str, 1);
127                         --argc;
128                 }
129                 else if(arg_buf[0] == 0) {
130                         memset(&obp_tftp_args->gi6addr, 0, 16);
131                         arg_str = get_arg_ptr(arg_str, 1);
132                         --argc;
133                 }
134                 else
135                         memset(&obp_tftp_args->gi6addr.addr, 0, 16);
136         }
137
138         return arg_str;
139 }
140
141
142 /**
143  * Parses a argument string for IPv4 booting, extracts all
144  * parameters and fills a structure accordingly
145  *
146  * @param  arg_str        string with arguments, separated with ','
147  * @param  argc           number of arguments
148  * @param  obp_tftp_args  structure which contains the result
149  * @return                updated arg_str
150  */
151 static const char * 
152 parse_ipv4args (const char *arg_str, unsigned int argc,
153                 obp_tftp_args_t *obp_tftp_args)
154 {
155         char *ptr = NULL;
156         char arg_buf[100];
157
158         // find out siaddr
159         if(argc==0) {
160                 memset(obp_tftp_args->siaddr, 0, 4);
161         } else {
162                 argncpy(arg_str, 0, arg_buf, 100);
163                 if(strtoip(arg_buf, obp_tftp_args->siaddr)) {
164                         arg_str = get_arg_ptr(arg_str, 1);
165                         --argc;
166                 }
167                 else if(arg_buf[0] == 0) {
168                         memset(obp_tftp_args->siaddr, 0, 4);
169                         arg_str = get_arg_ptr(arg_str, 1);
170                         --argc;
171                 }
172                 else
173                         memset(obp_tftp_args->siaddr, 0, 4);
174         }
175
176         // find out filename
177         if(argc==0)
178                 obp_tftp_args->filename[0] = 0;
179         else {
180                 argncpy(arg_str, 0, obp_tftp_args->filename, 100);
181                 for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr)
182                         if(*ptr == '\\')
183                                 *ptr = '/';
184                 arg_str = get_arg_ptr(arg_str, 1);
185                 --argc;
186         }
187
188         // find out ciaddr
189         if(argc==0)
190                 memset(obp_tftp_args->ciaddr, 0, 4);
191         else {
192                 argncpy(arg_str, 0, arg_buf, 100);
193                 if(strtoip(arg_buf, obp_tftp_args->ciaddr)) {
194                         arg_str = get_arg_ptr(arg_str, 1);
195                         --argc;
196                 }
197                 else if(arg_buf[0] == 0) {
198                         memset(obp_tftp_args->ciaddr, 0, 4);
199                         arg_str = get_arg_ptr(arg_str, 1);
200                         --argc;
201                 }
202                 else
203                         memset(obp_tftp_args->ciaddr, 0, 4);
204         }
205
206         // find out giaddr
207         if(argc==0)
208                 memset(obp_tftp_args->giaddr, 0, 4);
209         else {
210                 argncpy(arg_str, 0, arg_buf, 100);
211                 if(strtoip(arg_buf, obp_tftp_args->giaddr)) {
212                         arg_str = get_arg_ptr(arg_str, 1);
213                         --argc;
214                 }
215                 else if(arg_buf[0] == 0) {
216                         memset(obp_tftp_args->giaddr, 0, 4);
217                         arg_str = get_arg_ptr(arg_str, 1);
218                         --argc;
219                 }
220                 else
221                         memset(obp_tftp_args->giaddr, 0, 4);
222         }
223
224         return arg_str;
225 }
226
227 /**
228  * Parses a argument string which is given by netload, extracts all
229  * parameters and fills a structure according to this
230  *
231  * Netload-Parameters:
232  *    [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
233  *
234  * @param  arg_str        string with arguments, separated with ','
235  * @param  obp_tftp_args  structure which contains the result
236  * @return                none
237  */
238 static void
239 parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args)
240 {
241         unsigned int argc;
242         char arg_buf[100];
243
244         memset(obp_tftp_args, 0, sizeof(*obp_tftp_args));
245
246         argc = get_args_count(arg_str);
247
248         // find out if we should use BOOTP or DHCP
249         if(argc==0)
250                 obp_tftp_args->ip_init = IP_INIT_DEFAULT;
251         else {
252                 argncpy(arg_str, 0, arg_buf, 100);
253                 if (strcasecmp(arg_buf, "bootp") == 0) {
254                         obp_tftp_args->ip_init = IP_INIT_BOOTP;
255                         arg_str = get_arg_ptr(arg_str, 1);
256                         --argc;
257                 }
258                 else if(strcasecmp(arg_buf, "dhcp") == 0) {
259                         obp_tftp_args->ip_init = IP_INIT_DHCP;
260                         arg_str = get_arg_ptr(arg_str, 1);
261                         --argc;
262                 }
263                 else if(strcasecmp(arg_buf, "ipv6") == 0) {
264                         obp_tftp_args->ip_init = IP_INIT_DHCPV6_STATELESS;
265                         arg_str = get_arg_ptr(arg_str, 1);
266                         --argc;
267                         ip_version = 6;
268                 }
269                 else
270                         obp_tftp_args->ip_init = IP_INIT_DEFAULT;
271         }
272
273         if (ip_version == 4) {
274                 arg_str = parse_ipv4args (arg_str, argc, obp_tftp_args);
275         }
276         else if (ip_version == 6) {
277                 arg_str = parse_ipv6args (arg_str, argc, obp_tftp_args);
278         }
279
280         // find out bootp-retries
281         if (argc == 0)
282                 obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
283         else {
284                 argncpy(arg_str, 0, arg_buf, 100);
285                 if(arg_buf[0] == 0)
286                         obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
287                 else {
288                         obp_tftp_args->bootp_retries = strtol(arg_buf, 0, 10);
289                         if(obp_tftp_args->bootp_retries < 0)
290                                 obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
291                 }
292                 arg_str = get_arg_ptr(arg_str, 1);
293                 --argc;
294         }
295
296         // find out tftp-retries
297         if (argc == 0)
298                 obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
299         else {
300                 argncpy(arg_str, 0, arg_buf, 100);
301                 if(arg_buf[0] == 0)
302                         obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
303                 else {
304                         obp_tftp_args->tftp_retries = strtol(arg_buf, 0, 10);
305                         if(obp_tftp_args->tftp_retries < 0)
306                                 obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
307                 }
308                 arg_str = get_arg_ptr(arg_str, 1);
309                 --argc;
310         }
311 }
312
313 /**
314  * DHCP: Wrapper for obtaining IP and configuration info from DHCP server
315  *       for both IPv4 and IPv6.
316  *       (makes several attempts).
317  *
318  * @param  ret_buffer    buffer for returning BOOTP-REPLY packet data
319  * @param  fn_ip         contains the following configuration information:
320  *                       client MAC, client IP, TFTP-server MAC,
321  *                       TFTP-server IP, Boot file name
322  * @param  retries       No. of DHCP attempts
323  * @param  flags         flags for specifying type of dhcp attempt (IPv4/IPv6)
324  *                       ZERO   - attempt DHCPv4 followed by DHCPv6
325  *                       F_IPV4 - attempt only DHCPv4
326  *                       F_IPV6 - attempt only DHCPv6
327  * @return               ZERO - IP and configuration info obtained;
328  *                       NON ZERO - error condition occurs.
329  */
330 int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flags)
331 {
332         int i = (int) retries+1;
333         int rc = -1;
334
335         printf("    ");
336
337         do {
338                 printf("\b\b\b%03d", i-1);
339                 if (getchar() == 27) {
340                         printf("\nAborted\n");
341                         return -1;
342                 }
343                 if (!--i) {
344                         printf("\nGiving up after %d DHCP requests\n", retries);
345                         return -1;
346                 }
347                 if (!flags || (flags == F_IPV4)) {
348                         ip_version = 4;
349                         rc = dhcpv4(ret_buffer, fn_ip);
350                 }
351                 if ((!flags && (rc == -1)) || (flags == F_IPV6)) {
352                         ip_version = 6;
353                         set_ipv6_address(fn_ip->fd, 0);
354                         rc = dhcpv6(ret_buffer, fn_ip);
355                         if (rc == 0) {
356                                 printf("\n");
357                                 memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16);
358                                 break;
359                         }
360
361                 }
362                 if (rc != -1) /* either success or non-dhcp failure */
363                         break;
364         } while (1);
365         printf("\b\b\b\b");
366
367         return rc;
368 }
369
370 int
371 netboot(int argc, char *argv[])
372 {
373         char buf[256];
374         int rc;
375         int len = strtol(argv[2], 0, 16);
376         char *buffer = (char *) strtol(argv[1], 0, 16);
377         char *ret_buffer = (char *) strtol(argv[3], 0, 16);
378         filename_ip_t fn_ip;
379         int fd_device;
380         tftp_err_t tftp_err;
381         obp_tftp_args_t obp_tftp_args;
382         char null_ip[4] = { 0x00, 0x00, 0x00, 0x00 };
383         char null_ip6[16] = { 0x00, 0x00, 0x00, 0x00,
384                              0x00, 0x00, 0x00, 0x00,
385                              0x00, 0x00, 0x00, 0x00, 
386                              0x00, 0x00, 0x00, 0x00 };
387         int huge_load = strtol(argv[4], 0, 10);
388         int32_t block_size = strtol(argv[5], 0, 10);
389         uint8_t own_mac[6];
390
391         printf("\n");
392         printf(" Bootloader 1.6 \n");
393         memset(&fn_ip, 0, sizeof(filename_ip_t));
394
395         /***********************************************************
396          *
397          * Initialize network stuff and retrieve boot informations
398          *
399          ***********************************************************/
400
401         /* Wait for link up and get mac_addr from device */
402         for(rc=0; rc<DEFAULT_BOOT_RETRIES; ++rc) {
403                 if(rc > 0) {
404                         set_timer(TICKS_SEC);
405                         while (get_timer() > 0);
406                 }
407                 fd_device = socket(0, 0, 0, (char*) own_mac);
408                 if(fd_device != -2)
409                         break;
410                 if(getchar() == 27) {
411                         fd_device = -2;
412                         break;
413                 }
414         }
415
416         if (fd_device == -1) {
417                 strcpy(buf,"E3000: (net) Could not read MAC address");
418                 bootmsg_error(0x3000, &buf[7]);
419
420                 write_mm_log(buf, strlen(buf), 0x91);
421                 return -100;
422         }
423         else if (fd_device == -2) {
424                 strcpy(buf,"E3006: (net) Could not initialize network device");
425                 bootmsg_error(0x3006, &buf[7]);
426
427                 write_mm_log(buf, strlen(buf), 0x91);
428                 return -101;
429         }
430
431         fn_ip.fd = fd_device;
432
433         printf("  Reading MAC address from device: "
434                "%02x:%02x:%02x:%02x:%02x:%02x\n",
435                own_mac[0], own_mac[1], own_mac[2],
436                own_mac[3], own_mac[4], own_mac[5]);
437
438         // init ethernet layer
439         set_mac_address(own_mac);
440
441         if (argc > 6) {
442                 parse_args(argv[6], &obp_tftp_args);
443                 if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES)
444                         obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES;
445                 else
446                         obp_tftp_args.bootp_retries -= rc;
447         }
448         else {
449                 memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t));
450                 obp_tftp_args.ip_init = IP_INIT_DEFAULT;
451                 obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES;
452                 obp_tftp_args.tftp_retries = DEFAULT_TFTP_RETRIES;
453         }
454         memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4);
455
456         //  reset of error code
457         rc = 0;
458
459         /* if we still have got all necessary parameters, then we don't
460            need to perform an BOOTP/DHCP-Request */
461         if (ip_version == 4) {
462                 if (memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0
463                     && memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0
464                     && obp_tftp_args.filename[0] != 0) {
465
466                         memcpy(&fn_ip.server_ip, &obp_tftp_args.siaddr, 4);
467                         obp_tftp_args.ip_init = IP_INIT_NONE;
468                 }
469         }
470         else if (ip_version == 6) {
471                 if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0
472                     && memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0
473                     && obp_tftp_args.filename[0] != 0) {
474
475                         memcpy(&fn_ip.server_ip6.addr[0],
476                                &obp_tftp_args.si6addr.addr, 16);
477                         obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL;
478                 }
479                 else {
480                         obp_tftp_args.ip_init = IP_INIT_DHCPV6_STATELESS;
481                 }
482         }
483
484         // construction of fn_ip from parameter
485         switch(obp_tftp_args.ip_init) {
486         case IP_INIT_BOOTP:
487                 printf("  Requesting IP address via BOOTP: ");
488                 // if giaddr in not specified, then we have to identify
489                 // the BOOTP server via broadcasts
490                 if(memcmp(obp_tftp_args.giaddr, null_ip, 4) == 0) {
491                         // don't do this, when using DHCP !!!
492                         fn_ip.server_ip = 0xFFFFFFFF;
493                 }
494                 // if giaddr is specified, then we have to use this
495                 // IP address as proxy to identify the BOOTP server
496                 else {
497                         memcpy(&fn_ip.server_ip, obp_tftp_args.giaddr, 4);
498                 }
499                 rc = bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries);
500                 break;
501         case IP_INIT_DHCP:
502                 printf("  Requesting IP address via DHCPv4: ");
503                 rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV4);
504                 break;
505         case IP_INIT_DHCPV6_STATELESS:
506                 printf("  Requesting information via DHCPv6: ");
507                 rc = dhcp(ret_buffer, &fn_ip,
508                           obp_tftp_args.bootp_retries, F_IPV6);
509                 break;
510         case IP_INIT_IPV6_MANUAL:
511                 set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr);
512                 break;
513         case IP_INIT_DEFAULT:
514                 printf("  Requesting IP address via DHCP: ");
515                 rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, 0);
516                 break;
517         case IP_INIT_NONE:
518         default:
519                 break;
520         }
521
522         if(rc >= 0 && ip_version == 4) {
523                 if(memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0
524                 && memcmp(obp_tftp_args.ciaddr, &fn_ip.own_ip, 4) != 0)
525                         memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4);
526
527                 if(memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0
528                 && memcmp(obp_tftp_args.siaddr, &fn_ip.server_ip, 4) != 0)
529                         memcpy(&fn_ip.server_ip, obp_tftp_args.siaddr, 4);
530
531                 // init IPv4 layer
532                 set_ipv4_address(fn_ip.own_ip);
533         }
534         else if (rc >= 0 && ip_version == 6) {
535                 if(memcmp(&obp_tftp_args.ci6addr.addr, null_ip6, 16) != 0
536                 && memcmp(&obp_tftp_args.ci6addr.addr, &fn_ip.own_ip6, 16) != 0)
537                         memcpy(&fn_ip.own_ip6, &obp_tftp_args.ci6addr.addr, 16);
538
539                 if(memcmp(&obp_tftp_args.si6addr.addr, null_ip6, 16) != 0
540                 && memcmp(&obp_tftp_args.si6addr.addr, &fn_ip.server_ip6.addr, 16) != 0)
541                         memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16);
542         }
543         if (rc == -1) {
544                 strcpy(buf,"E3001: (net) Could not get IP address");
545                 bootmsg_error(0x3001, &buf[7]);
546
547                 write_mm_log(buf, strlen(buf), 0x91);
548                 return -101;
549         }
550
551         if(ip_version == 4)
552                 printf("%d.%d.%d.%d\n",
553                         ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
554                         ((fn_ip.own_ip >>  8) & 0xFF), ( fn_ip.own_ip        & 0xFF));
555
556         if (rc == -2) {
557                 sprintf(buf,
558                         "E3002: (net) ARP request to TFTP server "
559                         "(%d.%d.%d.%d) failed",
560                         ((fn_ip.server_ip >> 24) & 0xFF),
561                         ((fn_ip.server_ip >> 16) & 0xFF),
562                         ((fn_ip.server_ip >>  8) & 0xFF),
563                         ( fn_ip.server_ip        & 0xFF));
564                 bootmsg_error(0x3002, &buf[7]);
565
566                 write_mm_log(buf, strlen(buf), 0x91);
567                 return -102;
568         }
569         if (rc == -4 || rc == -3) {
570                 strcpy(buf,"E3008: (net) Can't obtain TFTP server IP address");
571                 bootmsg_error(0x3008, &buf[7]);
572
573                 write_mm_log(buf, strlen(buf), 0x91);
574                 return -107;
575         }
576
577
578         /***********************************************************
579          *
580          * Load file via TFTP into buffer provided by OpenFirmware
581          *
582          ***********************************************************/
583
584         if (obp_tftp_args.filename[0] != 0) {
585                 strncpy((char *) fn_ip.filename, obp_tftp_args.filename, sizeof(fn_ip.filename)-1);
586                 fn_ip.filename[sizeof(fn_ip.filename)-1] = 0;
587         }
588
589         if (ip_version == 4) {
590                 printf("  Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n",
591                         fn_ip.filename,
592                         ((fn_ip.server_ip >> 24) & 0xFF),
593                         ((fn_ip.server_ip >> 16) & 0xFF),
594                         ((fn_ip.server_ip >>  8) & 0xFF),
595                         ( fn_ip.server_ip        & 0xFF));
596         } else if (ip_version == 6) {
597                 char ip6_str[40];
598                 printf("  Requesting file \"%s\" via TFTP from ", fn_ip.filename);
599                 ipv6_to_str(fn_ip.server_ip6.addr, ip6_str);
600                 printf("%s\n", ip6_str);
601         }
602
603         // accept at most 20 bad packets
604         // wait at most for 40 packets
605         rc = tftp(&fn_ip, (unsigned char *) buffer,
606                   len, obp_tftp_args.tftp_retries,
607                   &tftp_err, huge_load, block_size, ip_version);
608
609         if(obp_tftp_args.ip_init == IP_INIT_DHCP)
610                 dhcp_send_release(fn_ip.fd);
611
612         if (rc > 0) {
613                 printf("  TFTP: Received %s (%d KBytes)\n", fn_ip.filename,
614                        rc / 1024);
615         } else if (rc == -1) {
616                 bootmsg_error(0x3003, "(net) unknown TFTP error");
617                 return -103;
618         } else if (rc == -2) {
619                 sprintf(buf,
620                         "E3004: (net) TFTP buffer of %d bytes "
621                         "is too small for %s",
622                         len, fn_ip.filename);
623                 bootmsg_error(0x3004, &buf[7]);
624
625                 write_mm_log(buf, strlen(buf), 0x91);
626                 return -104;
627         } else if (rc == -3) {
628                 sprintf(buf,"E3009: (net) file not found: %s",
629                        fn_ip.filename);
630                 bootmsg_error(0x3009, &buf[7]);
631
632                 write_mm_log(buf, strlen(buf), 0x91);
633                 return -108;
634         } else if (rc == -4) {
635                 strcpy(buf,"E3010: (net) TFTP access violation");
636                 bootmsg_error(0x3010, &buf[7]);
637
638                 write_mm_log(buf, strlen(buf), 0x91);
639                 return -109;
640         } else if (rc == -5) {
641                 strcpy(buf,"E3011: (net) illegal TFTP operation");
642                 bootmsg_error(0x3011, &buf[7]);
643
644                 write_mm_log(buf, strlen(buf), 0x91);
645                 return -110;
646         } else if (rc == -6) {
647                 strcpy(buf, "E3012: (net) unknown TFTP transfer ID");
648                 bootmsg_error(0x3012, &buf[7]);
649
650                 write_mm_log(buf, strlen(buf), 0x91);
651                 return -111;
652         } else if (rc == -7) {
653                 strcpy(buf, "E3013: (net) no such TFTP user");
654                 bootmsg_error(0x3013, &buf[7]);
655
656                 write_mm_log(buf, strlen(buf), 0x91);
657                 return -112;
658         } else if (rc == -8) {
659                 strcpy(buf, "E3017: (net) TFTP blocksize negotiation failed");
660                 bootmsg_error(0x3017, &buf[7]);
661
662                 write_mm_log(buf, strlen(buf), 0x91);
663                 return -116;
664         } else if (rc == -9) {
665                 strcpy(buf,"E3018: (net) file exceeds maximum TFTP transfer size");
666                 bootmsg_error(0x3018, &buf[7]);
667
668                 write_mm_log(buf, strlen(buf), 0x91);
669                 return -117;
670         } else if (rc <= -10 && rc >= -15) {
671                 sprintf(buf,"E3005: (net) ICMP ERROR \"");
672                 switch (rc) {
673                 case -ICMP_NET_UNREACHABLE - 10:
674                         sprintf(buf+strlen(buf),"net unreachable");
675                         break;
676                 case -ICMP_HOST_UNREACHABLE - 10:
677                         sprintf(buf+strlen(buf),"host unreachable");
678                         break;
679                 case -ICMP_PROTOCOL_UNREACHABLE - 10:
680                         sprintf(buf+strlen(buf),"protocol unreachable");
681                         break;
682                 case -ICMP_PORT_UNREACHABLE - 10:
683                         sprintf(buf+strlen(buf),"port unreachable");
684                         break;
685                 case -ICMP_FRAGMENTATION_NEEDED - 10:
686                         sprintf(buf+strlen(buf),"fragmentation needed and DF set");
687                         break;
688                 case -ICMP_SOURCE_ROUTE_FAILED - 10:
689                         sprintf(buf+strlen(buf),"source route failed");
690                         break;
691                 default:
692                         sprintf(buf+strlen(buf)," UNKNOWN");
693                         break;
694                 }
695                 sprintf(buf+strlen(buf),"\"");
696                 bootmsg_error(0x3005, &buf[7]);
697
698                 write_mm_log(buf, strlen(buf), 0x91);
699                 return -105;
700         } else if (rc == -40) {
701                 sprintf(buf,
702                         "E3014: (net) TFTP error occurred after "
703                         "%d bad packets received",
704                         tftp_err.bad_tftp_packets);
705                 bootmsg_error(0x3014, &buf[7]);
706                 write_mm_log(buf, strlen(buf), 0x91);
707                 return -113;
708         } else if (rc == -41) {
709                 sprintf(buf,
710                         "E3015: (net) TFTP error occurred after "
711                         "missing %d responses",
712                         tftp_err.no_packets);
713                 bootmsg_error(0x3015, &buf[7]);
714                 write_mm_log(buf, strlen(buf), 0x91);
715                 return -114;
716         } else if (rc == -42) {
717                 sprintf(buf,
718                         "E3016: (net) TFTP error missing block %d, "
719                         "expected block was %d",
720                         tftp_err.blocks_missed,
721                         tftp_err.blocks_received);
722                 bootmsg_error(0x3016, &buf[7]);
723                 write_mm_log(buf, strlen(buf), 0x91);
724                 return -115;
725         }
726         return rc;
727 }
728
729 /**
730  * Parses a tftp arguments, extracts all
731  * parameters and fills server ip according to this
732  *
733  * Parameters:
734  * @param  buffer        string with arguments,
735  * @param  server_ip     server ip as result
736  * @param  filename      default filename
737  * @param  fd            Socket descriptor
738  * @param  len           len of the buffer,
739  * @return               0 on SUCCESS and -1 on failure
740  */
741 int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd,
742                     int len)
743 {
744         char *raw;
745         char *tmp, *tmp1;
746         int i, j = 0;
747         char domainname[256];
748         uint8_t server_ip6[16];
749
750         raw = malloc(len);
751         if (raw == NULL) {
752                 printf("\n unable to allocate memory, parsing failed\n");
753                 return -1;
754         }
755         strncpy(raw,(const char *)buffer,len);
756         /*tftp url contains tftp://[fd00:4f53:4444:90:214:5eff:fed9:b200]/testfile*/
757         if(strncmp(raw,"tftp://",7)){
758                 printf("\n tftp missing in %s\n",raw);
759                 free(raw);
760                 return -1;
761         }
762         tmp = strchr(raw,'[');
763         if(tmp != NULL && *tmp == '[') {
764                 /*check for valid ipv6 address*/
765                 tmp1 = strchr(tmp,']');
766                 if (tmp1 == NULL) {
767                         printf("\n missing ] in %s\n",raw);
768                         free(raw);
769                         return -1;
770                 }
771                 i = tmp1 - tmp;
772                 /*look for file name*/
773                 tmp1 = strchr(tmp,'/');
774                 if (tmp1 == NULL) {
775                         printf("\n missing filename in %s\n",raw);
776                         free(raw);
777                         return -1;
778                 }
779                 tmp[i] = '\0';
780                 /*check for 16 byte ipv6 address */
781                 if (!str_to_ipv6((tmp+1), (uint8_t *)(server_ip))) {
782                         printf("\n wrong format IPV6 address in %s\n",raw);
783                         free(raw);
784                         return -1;;
785                 }
786                 else {
787                         /*found filename */
788                         strcpy(filename,(tmp1+1));
789                         free(raw);
790                         return 0;
791                 }
792         }
793         else {
794                 /*here tftp://hostname/testfile from option request of dhcp*/
795                 /*look for dns server name */
796                 tmp1 = strchr(raw,'.');
797                 if(tmp1 == NULL) {
798                         printf("\n missing . seperator in %s\n",raw);
799                         free(raw);
800                         return -1;
801                 }
802                 /*look for domain name beyond dns server name
803                 * so ignore the current . and look for one more
804                 */
805                 tmp = strchr((tmp1+1),'.');
806                 if(tmp == NULL) {
807                         printf("\n missing domain in %s\n",raw);
808                         free(raw);
809                         return -1;
810                 }
811                 tmp1 = strchr(tmp1,'/');
812                 if (tmp1 == NULL) {
813                         printf("\n missing filename in %s\n",raw);
814                         free(raw);
815                         return -1;
816                 }
817                 j = tmp1 - (raw + 7);
818                 tmp = raw + 7;
819                 tmp[j] = '\0';
820                 strcpy(domainname, tmp);
821                 if (dns_get_ip(fd, (int8_t *)domainname, server_ip6, 6) == 0) {
822                         printf("\n DNS failed for IPV6\n");
823                         return -1;
824                 }
825                 ipv6_to_str(server_ip6, server_ip);
826
827                 strcpy(filename,(tmp1+1));
828                 free(raw);
829                 return 0;
830         }
831
832 }