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