Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netlib / ipv6.c
1 /******************************************************************************
2  * Copyright (c) 2013 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 <string.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <time.h>
17 #include <ctype.h>
18 #include <sys/socket.h>
19 #include <netlib/ethernet.h>
20 #include <netlib/ipv6.h>
21 #include <netlib/icmpv6.h>
22 #include <netlib/ndp.h>
23 #include <netlib/udp.h>
24
25 #undef IPV6_DEBUG
26 //#define IPV6_DEBUG
27 #ifdef IPV6_DEBUG
28 #define dprintf(_x ...) do { printf(_x); } while (0)
29 #else
30 #define dprintf(_x ...)
31 #endif
32
33 /****************************** PROTOTYPES *******************************/
34 int8_t ip6addr_add (struct ip6addr_list_entry *new_address);
35 static void ipv6_init(int fd);
36 static int ip6_is_multicast (ip6_addr_t * ip);
37
38 /****************************** LOCAL VARIABLES **************************/
39
40 /* Own IPv6 address */
41 static struct ip6addr_list_entry *own_ip6;
42
43 /* Null IPv6 address */
44 static ip6_addr_t null_ip6;
45
46 /* helper variables */
47 static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
48
49
50 /****************************** IMPLEMENTATION ***************************/
51
52 /**
53  * IPv6: Set the own IPv6 address.
54  *
55  * @param  fd            Socket descriptor
56  * @param  _own_ip       client IPv6 address (e.g. ::1)
57  */
58 void
59 set_ipv6_address (int fd, ip6_addr_t *_own_ip6)
60 {
61         own_ip6 = malloc (sizeof(struct ip6addr_list_entry));
62
63         /* If no address was passed as a parameter generate a link-local
64          * address from our MAC address.*/
65         if (_own_ip6 == NULL)
66                 memcpy(&(own_ip6->addr.addr),
67                         ip6_create_ll_address(get_mac_address()),
68                        IPV6_ADDR_LENGTH);
69         else
70                 memcpy (&(own_ip6->addr.addr), _own_ip6, 16);
71
72         /* Add to our list of IPv6 addresses */
73         ip6addr_add (own_ip6);
74
75         ipv6_init(fd);
76 }
77
78 /**
79  * IPv6: Get pointer to own IPv6 address.
80  *
81  * @return pointer to client IPv6 address (e.g. ::1)
82  */
83 ip6_addr_t *
84 get_ipv6_address (void)
85 {
86         return (ip6_addr_t *) &(own_ip6->addr);
87 }
88
89 /**
90  * IPv6: Search for IPv6 address in list
91  *
92  * @return 0 - IPv6 address is not in list
93  *         1 - IPv6 address is in list
94  */
95 static int8_t
96 find_ip6addr (ip6_addr_t *ip)
97 {
98         struct ip6addr_list_entry *n = NULL;
99
100         if (ip == NULL)
101             return 0;
102
103         for (n = first_ip6; n != NULL ; n=n->next)
104                 if (ip6_cmp (&(n->addr), ip))
105                         return 1; /* IPv6 address is in  our list*/
106
107         return 0; /* not one of our IPv6 addresses*/
108 }
109
110 /**
111  * NET: Handles IPv6-packets
112  *
113  * @param  fd         - Socket descriptor
114  * @param  ip6_packet - Pointer to IPv6 header
115  * @param  packetsize - Size of Ipv6 packet
116  * @return ERROR      - -1 if packet is too small or unknown protocol
117  *                      return value of handle_udp
118  *
119  * @see handle_udp
120  * @see ip6hdr
121  */
122 int8_t
123 handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize)
124 {
125
126         struct ip6hdr *ip6 = NULL;
127         ip6 = (struct ip6hdr *) ip6_packet;
128
129         /* Only handle packets which are for us */
130         if (! find_ip6addr(&(ip6->dst)))
131                 return -1;
132
133         if (packetsize < sizeof(struct ip6hdr))
134                 return -1; // packet is too small
135
136         switch (ip6->nh) {
137                 case IPTYPE_UDP:
138                         return handle_udp (fd, ip6_packet + sizeof (struct ip6hdr),
139                                         ip6->pl);
140                 case IPTYPE_ICMPV6:
141                         return handle_icmpv6 (fd, (struct ethhdr *) ip6_packet - sizeof(struct ethhdr),
142                                               ip6_packet);
143         }
144
145         return -1; // unknown protocol
146 }
147
148  /**
149  * NET: Creates IPv6-packet. Places IPv6-header in a packet and fills it
150  *      with corresponding information.
151  *      <p>
152  *      Use this function with similar functions for other network layers
153  *      (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
154  *
155  * @param  packet      Points to the place where IPv6-header must be placed.
156  * @param  packetsize  Size of payload (i.e. excluding ethhdr and ip6hdr)
157  * @param  ip_proto    Type of the next level protocol (e.g. UDP).
158  * @param  ip6_src     Sender IPv6 address
159  * @param  ip6_dst     Receiver IPv6 address
160  * @see                ip6hdr
161  * @see                fill_iphdr
162  * @see                fill_ethhdr
163  * @see                fill_udphdr
164  * @see                fill_dnshdr
165  * @see                fill_btphdr
166  */
167 void
168 fill_ip6hdr (uint8_t * packet, uint16_t packetsize,
169              uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst)
170 {
171
172         struct ip6hdr * ip6h = (struct ip6hdr *) packet;
173
174         ip6h->ver_tc_fl = 6 << 28;      // set version to 6
175         ip6h->pl = packetsize;          // IPv6 payload size
176         ip6h->nh = ip_proto;
177         ip6h->hl = 255;
178         memcpy (&(ip6h->src), ip6_src, IPV6_ADDR_LENGTH);
179         memcpy (&(ip6h->dst), ip6_dst, IPV6_ADDR_LENGTH);
180 }
181
182 /**
183  * NET: For a given MAC calculates EUI64-Identifier.
184  *      See RFC 4291 "IP Version 6 Addressing Architecture"
185  *
186  */
187 uint64_t
188 mac2eui64 (const uint8_t *mac)
189 {
190         uint8_t eui64id[8];
191         uint64_t retid;
192
193         memcpy (eui64id, mac, 3);
194         memcpy (eui64id + 5, mac + 3, 3);
195         eui64id[3] = 0xff;
196         eui64id[4] = 0xfe;
197
198         memcpy(&retid, eui64id, 8);
199         return retid;
200 }
201
202 /**
203  * NET: create link-local IPv6 address
204  *
205  * @param  own_mac    MAC of NIC
206  * @return ll_addr    pointer to newly created link-local address
207  */
208 ip6_addr_t *
209 ip6_create_ll_address (const uint8_t *own_mac)
210 {
211         ip6_addr_t *ll_addr;
212
213         ll_addr = malloc (sizeof (struct ip6addr_list_entry));
214         memset (ll_addr, 0, IPV6_ADDR_LENGTH);
215         ll_addr->part.prefix       |= IPV6_LL_PREFIX;
216         ll_addr->part.interface_id |= mac2eui64((uint8_t *) own_mac);
217
218         return ll_addr;
219 }
220
221 /*
222  * NET: check if we already have an address with the same prefix.
223  * @param  struct ip6_addr_list_entry *ip6
224  * @return true or false
225  */
226 int8_t
227 unknown_prefix (ip6_addr_t *ip)
228 {
229         struct ip6addr_list_entry *node;
230
231         for( node = first_ip6; node != NULL; node=node->next )
232                 if( node->addr.part.prefix == ip->part.prefix )
233                         return 0; /* address is one of ours */
234
235         return 1; /* prefix not yet in our list */
236 }
237
238 /*
239  * NET: Create empty element for prefix list and return a pointer to it;
240  * @return NULL - malloc failed
241  *         ! NULL - pointer to new prefix_info
242  */
243 struct prefix_info *
244 ip6_create_prefix_info ()
245 {
246         struct prefix_info *prfx_info;
247
248         prfx_info = malloc (sizeof(struct prefix_info));
249         if (!prfx_info)
250                 return NULL;
251
252         return prfx_info;
253 }
254
255 /*
256  * NET: create a new IPv6 address with a given network prefix
257  *      and add it to our IPv6 address list
258  *
259  * @param  ip6_addr prefix (as received in RA)
260  * @return NULL - pointer to new ip6addr_list entry
261  */
262 void *
263 ip6_prefix2addr (ip6_addr_t prefix)
264 {
265         struct ip6addr_list_entry *new_address;
266         uint64_t interface_id;
267
268         new_address = malloc (sizeof(struct ip6addr_list_entry));
269         if( !new_address )
270                 return NULL;
271
272         /* fill new addr struct */
273         /* extract prefix from Router Advertisement */
274         memcpy (&(new_address->addr.part.prefix), &prefix, 8 );
275
276         /* interface id is generated from MAC address */
277         interface_id = mac2eui64 (get_mac_address());
278         memcpy (&(new_address->addr.part.interface_id), &interface_id, 8);
279
280         return new_address;
281 }
282
283 /**
284  * NET: add new IPv6 adress to list
285  *
286  * @param   ip6_addr *new_address
287  * @return  0 - passed pointer = NULL;
288  *          1 - ok
289  */
290 int8_t
291 ip6addr_add (struct ip6addr_list_entry *new_address)
292 {
293         struct ip6addr_list_entry *solicited_node;
294
295
296         if (new_address == NULL)
297                 return 0;
298
299          /* Don't add the same address twice */
300         if (find_ip6addr (&(new_address->addr)))
301                 return 0;
302
303         /* If address is a unicast address, we also have to process packets
304          * for its solicited-node multicast address.
305          * See RFC 2373 - IP Version 6 Adressing Architecture */
306         if (! ip6_is_multicast(&(new_address->addr))) {
307
308
309                 solicited_node = malloc(sizeof(struct ip6addr_list_entry));
310                 if (! solicited_node)
311                         return 0;
312
313                 solicited_node->addr.part.prefix       = IPV6_SOLIC_NODE_PREFIX;
314                 solicited_node->addr.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
315                 solicited_node->addr.addr[13] = new_address->addr.addr[13];
316                 solicited_node->addr.addr[14] = new_address->addr.addr[14];
317                 solicited_node->addr.addr[15] = new_address->addr.addr[15];
318                 ip6addr_add (solicited_node);
319         }
320
321         if (NULL == first_ip6)
322                 first_ip6 = new_address;
323         last_ip6->next = new_address;
324         last_ip6 = new_address;
325         last_ip6->next = NULL;
326
327         return 1; /* no error */
328 }
329
330 /**
331  * NET: Initialize IPv6
332  *
333  * @param  fd            socket fd
334  */
335 static void
336 ipv6_init (int fd)
337 {
338         int i = 0;
339
340         send_ip = &send_ipv6;
341
342         /* Address configuration parameters */
343         ip6_state.managed_mode = 0;
344
345         /* Null IPv6 address */
346         null_ip6.part.prefix       = 0;
347         null_ip6.part.interface_id = 0;
348
349         /* Multicast addresses */
350         all_nodes_ll.addr.part.prefix         = 0xff02000000000000;
351         all_nodes_ll.addr.part.interface_id   = 1;
352         all_dhcpv6_ll.addr.part.prefix        = 0xff02000000000000ULL;
353         all_dhcpv6_ll.addr.part.interface_id  = 0x10002ULL;
354         all_routers_ll.addr.part.prefix       = 0xff02000000000000;
355         all_routers_ll.addr.part.interface_id      = 2;
356
357         ip6addr_add(&all_nodes_ll);
358         /* ... */
359
360         /* Router list */
361         first_router = NULL;
362         last_router = first_router;
363
364         /* Init Neighbour cache */
365         first_neighbor = NULL;
366         last_neighbor  = first_neighbor;
367
368         send_router_solicitation (fd);
369         for(i=0; i < 4 && !is_ra_received(); i++) {
370                 set_timer(TICKS_SEC);
371                 do {
372                         receive_ether(fd);
373                         if (is_ra_received())
374                                 break;
375                 } while (get_timer() > 0);
376         }
377 }
378
379 /**
380  * NET: compare IPv6 adresses
381  *
382  * @param  ip6_addr ip_1
383  * @param  ip6_addr ip_2
384  */
385 int8_t
386 ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2)
387 {
388         return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]),
389                 IPV6_ADDR_LENGTH ));
390 }
391
392 /**
393  * NET: Calculate checksum over IPv6 header and upper-layer protocol
394  *      (e.g. UDP or ICMPv6)
395  *
396  * @param  *ip    - pointer to IPv6 address
397  * @return true or false
398  */
399 int
400 ip6_is_multicast (ip6_addr_t * ip)
401 {
402         uint8_t mc = 0xFF;
403         return ! memcmp(&ip->addr[0], &mc, 1);
404 }
405
406 /**
407  * NET: Generate multicast MAC address from IPv6 address
408  *      (e.g. UDP or ICMPv6)
409  *
410  * @param  *ip    - pointer to IPv6 address
411  * @return pointer to Multicast MAC address
412  */
413 static uint8_t *
414 ip6_to_multicast_mac (ip6_addr_t * ip)
415 {
416         uint8_t *mc_mac;
417
418         mc_mac = malloc(ETH_ALEN);
419         if (!mc_mac)
420                 return NULL;
421
422         mc_mac[0] = 0x33;
423         mc_mac[1] = 0x33;
424         memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4);
425
426         return mc_mac;
427 }
428
429 /**
430  * NET: calculate checksum over IPv6 header and upper-layer protocol
431  *      (e.g. UDP or ICMPv6)
432  *
433  * @param  struct ip6hdr *ip6h    - pointer to IPv6 header
434  * @param  unsigned short *packet - pointer to header of upper-layer
435  *                                  protocol
436  * @param  int words              - number of words (as in 2 bytes)
437  *                                  starting from *packet
438  * @return checksum
439  */
440 static unsigned short
441 ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words)
442 {
443         int i=0;
444         unsigned long checksum;
445         struct ip6hdr pseudo_ip6h;
446         unsigned short *pip6h;
447
448         memcpy (&pseudo_ip6h, ip6h, sizeof(struct ip6hdr));
449         pseudo_ip6h.hl        = ip6h->nh;
450         pseudo_ip6h.ver_tc_fl = 0;
451         pseudo_ip6h.nh        = 0;
452         pip6h = (unsigned short *) &pseudo_ip6h;
453
454         for (checksum = 0; words > 0; words--) {
455                 checksum += *packet++;
456                 i++;
457         }
458
459         for (i = 0; i < 20; i++) {
460                 checksum += *pip6h++;
461         }
462
463         checksum = (checksum >> 16) + (checksum & 0xffff);
464         checksum += (checksum >> 16);
465
466         return ~checksum;
467 }
468
469 /**
470  * NET: Handles IPv6-packets
471  *
472  * @param fd          socket fd
473  * @param ip6_packet  Pointer to IPv6 header in packet
474  * @param packetsize  Size of IPv6 packet
475  * @return -1 == ERRROR
476  *         return of handle_udp() or handle_icmp6()
477  *
478  * @see receive_ether
479  * @see ip6hdr
480  */
481 int
482 send_ipv6 (int fd, void* buffer, int len)
483 {
484         struct neighbor *n;
485         struct ip6hdr *ip6h;
486         struct udphdr *udph;
487         struct icmp6hdr *icmp6h;
488         ip6_addr_t ip_dst;
489         uint8_t *mac_addr, mac[6];
490
491         mac_addr = mac;
492
493         ip6h    = (struct ip6hdr *) buffer;
494         udph   = (struct udphdr *)   ((uint8_t *) ip6h + sizeof (struct ip6hdr));
495         icmp6h = (struct icmp6hdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr));
496
497         memcpy(&ip_dst, &ip6h->dst, 16);
498
499         if(len + sizeof(struct ethhdr) > 1500)
500                 return -1;
501
502         if ( ip6_cmp (&ip6h->src, &null_ip6))
503                 memcpy (&(ip6h->src), get_ipv6_address(), IPV6_ADDR_LENGTH);
504
505         if (ip6h->nh == 17) {//UDP
506                 udph->uh_sum = ip6_checksum (ip6h, (unsigned short *) udph ,
507                                              ip6h->pl >> 1);
508                 /* As per RFC 768, if the computed  checksum  is zero,
509                  * it is transmitted as all ones (the equivalent in
510                  * one's complement arithmetic).
511                  */
512                 if (udph->uh_sum == 0)
513                         udph->uh_sum = ~udph->uh_sum;
514         }
515         else if (ip6h->nh == 0x3a) //ICMPv6
516                 icmp6h->checksum = ip6_checksum (ip6h,
517                                                  (unsigned short *) icmp6h,
518                                                  ip6h->pl >> 1);
519
520         n = find_neighbor (&ip_dst);
521
522         // If packet is a neighbor solicitation
523         if (icmp6h->type == ICMPV6_NEIGHBOUR_SOLICITATION) {
524                 mac_addr = ip6_to_multicast_mac (&ip_dst);
525                 fill_ethhdr( buffer-sizeof(struct ethhdr), htons(ETHERTYPE_IPv6),
526                              get_mac_address(),
527                              mac_addr);
528         }
529
530         // If address is a multicast address, create a proper mac address
531         else if (ip6_is_multicast (&ip_dst)) {
532                 mac_addr = ip6_to_multicast_mac (&ip_dst);
533         }
534         else {
535                 // Check if the MAC address is already cached
536                 if (n) {
537                         if (memcmp(n->mac, null_mac, ETH_ALEN) != 0)
538                                 memcpy (mac_addr, &(n->mac), ETH_ALEN); /* found it */
539                 } else {
540                         mac_addr = null_mac;
541                         n = malloc(sizeof(struct neighbor));
542                         memcpy(&(n->ip.addr[0]), &ip_dst, 16);
543                         n->status = NB_PROBE;
544                         n->times_asked += 1;
545                         neighbor_add(n);
546                 }
547
548                 if (! memcmp (mac_addr, &null_mac, 6)) {
549                         if (n->eth_len == 0) {
550                                 send_neighbour_solicitation (fd, &ip_dst);
551
552                                 // Store the packet until we know the MAC address
553                                 memset(n->eth_frame, 0, 1500);
554                                 fill_ethhdr (n->eth_frame,
555                                              htons(ETHERTYPE_IPv6),
556                                              get_mac_address(),
557                                              mac_addr);
558                                 memcpy (&(n->eth_frame[sizeof(struct ethhdr)]),
559                                        buffer, len);
560                                 n->eth_len = len;
561                                 set_timer(TICKS_SEC);
562                                 do {
563                                         receive_ether(fd);
564                                 } while (get_timer() > 0);
565                         }
566                 }
567         }
568
569         fill_ethhdr (n->eth_frame, htons(ETHERTYPE_IPv6), get_mac_address(),
570                      mac_addr);
571         memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), buffer, len);
572         return send_ether (fd, n->eth_frame, len + sizeof(struct ethhdr));
573 }
574
575 static int
576 check_colons(const char *str)
577 {
578         char *pch, *prv;
579         int col = 0;
580         int dcol = 0;
581
582         dprintf("str : %s\n",str);
583         pch = strchr(str, ':');
584         while(pch != NULL){
585                 prv = pch;
586                 pch = strchr(pch+1, ':');
587                 if((pch-prv) != 1) {
588                         col++;
589                 } else {
590                         col--; /* Its part of double colon */
591                         dcol++;
592                 }
593         }
594
595         dprintf("The number of  col : %d \n",col);
596         dprintf("The number of dcol : %d \n",dcol);
597
598         if((dcol > 1) ||                      /* Cannot have 2 "::" */ 
599            ((dcol == 1) && (col > 5)) ||      /* Too many ':'s */
600            ((dcol == 0) && (col != 7)) ) {    /* Too few ':'s */
601                 dprintf(" exiting for check_colons \n");
602                 return 0;
603         }
604
605         return (col+dcol);
606 }
607
608 static int
609 ipv6str_to_bytes(const char *str, char *ip)
610 {
611         char block[5];
612         int res;
613         char *pos;
614         uint32_t cnt = 0, len;
615
616         dprintf("str : %s \n",str);
617
618         while (*str != 0) {
619                 if (cnt > 15 || !isxdigit(*str)){
620                         return 0;
621                 }
622                 if ((pos = strchr(str, ':')) != NULL) {
623                         len = (int16_t) (pos - str);
624                         dprintf("\t len  is : %d \n",len);
625                         if (len > 4)
626                                 return 0;
627                         strncpy(block, str, len);
628                         block[len] = 0;
629                         dprintf("\t str   : %s \n",str);
630                         dprintf("\t block : %s \n",block);
631                         str += len;
632                 } else {
633                         strncpy(block, str, 4);
634                         block[4] = 0;
635                         dprintf("\t str   : %s \n",str);
636                         dprintf("\t block : %s \n",block);
637                         str += strlen(block);
638                 }
639                 res = strtol(block, NULL, 16);
640                 dprintf("\t res : %x \n",res);
641                 if ((res > 0xFFFF) || (res < 0))
642                         return 0;
643                 ip[cnt++] = (res & 0xFF00) >> 8;
644                 ip[cnt++] = (res & 0x00FF);
645                 if (*str == ':'){
646                         str++;
647                 }
648         }
649
650         dprintf("cnt : %d\n",cnt);
651         return cnt;
652 }
653
654 int str_to_ipv6(const char *str, uint8_t *ip)
655 {
656         int i, k;
657         uint16_t len;
658         char *ptr;
659         char tmp[30], buf[16];
660
661         memset(ip,0,16);
662
663         if(!check_colons(str))
664                 return 0;
665
666         if ((ptr = strstr(str, "::")) != NULL) {
667                 /* Handle the ::1 IPv6 loopback */
668                 if(!strcmp(str,"::1")) {
669                         ip[15] = 1;
670                         return 16;
671                 }
672                 len = (ptr-str);
673                 dprintf(" len : %d \n",len);
674                 if (len >= sizeof(tmp))
675                         return 0;
676                 strncpy(tmp, str, len);
677                 tmp[len] = 0;
678                 ptr += 2;
679
680                 i = ipv6str_to_bytes(ptr, buf);
681                 if(i == 0)
682                 return i;
683
684                 #if defined(ARGS_DEBUG)
685                 int j;
686                 dprintf("=========== bottom part i : %d \n",i);
687                 for(j=0; j<i; j++)
688                         dprintf("%02x \t",buf[j]);
689                 #endif
690
691                 /* Copy the bottom part i.e bytes following "::" */
692                 memcpy(ip+(16-i), buf, i);
693
694                 k = ipv6str_to_bytes(tmp, buf);
695                 if(k == 0)
696                         return k;
697
698                 #if defined(ARGS_DEBUG)
699                 dprintf("=========== top part k : %d \n",k);
700                 for(j=0; j<k; j++)
701                         printf("%02x \t",buf[j]);
702                 #endif
703
704                 /* Copy the top part i.e bytes before "::"  */
705                 memcpy(ip, buf, k);
706                 #if defined(ARGS_DEBUG)
707                 dprintf("\n");
708                 for(j=0; j<16; j++)
709                         dprintf("%02x \t",ip[j]);
710                 #endif
711
712         } else {
713                 i = ipv6str_to_bytes(str, (char *)ip);
714         }
715         return i;
716 }
717
718 void ipv6_to_str(const uint8_t *ip, char *str)
719 {
720         int i, len;
721         uint8_t byte_even, byte_odd;
722         char *consec_zero, *strptr;
723
724         *str = 0;
725         for (i = 0; i < 16; i+=2) {
726                 byte_even = ip[i];
727                 byte_odd = ip[i+1];
728                 if (byte_even)
729                         sprintf(str, "%s%x%02x", str, byte_even, byte_odd);
730                 else if (byte_odd)
731                         sprintf(str, "%s%x", str, byte_odd);
732                 else
733                         strcat(str, "0");
734                 if (i != 14)
735                         strcat(str, ":");
736         }
737         strptr = str;
738         do {
739                 consec_zero = strstr(strptr, "0:0:");
740                 if (consec_zero) {
741                         len = consec_zero - strptr;
742                         if (!len)
743                                 break;
744                         else if (strptr[len-1] == ':')
745                                 break;
746                         else
747                                 strptr = consec_zero + 2;
748                 }
749         } while (consec_zero);
750         if (consec_zero) {
751                 len = consec_zero - str;
752                 str[len] = 0;
753                 if (len)
754                         strcat(str, ":");
755                 else
756                         strcat(str, "::");
757                 strptr = consec_zero + 4;
758                 while (*strptr) {
759                         if (!strncmp(strptr, "0:", 2))
760                                 strptr += 2;
761                         else
762                                 break;
763                 }
764                 strcat(str, strptr);
765                 if (!strcmp(str, "::0"))
766                         strcpy(str, "::");
767         }
768 }