1 
2 /***************************************************************************
3  * ICMPv6Header.cc -- The ICMPv6Header Class represents an ICMP version 6  *
4  * packet. It contains methods to set any header field. In general, these  *
5  * methods do error checkings and byte order conversion.                   *
6  *                                                                         *
7  ***********************IMPORTANT NMAP LICENSE TERMS************************
8  *                                                                         *
9  * The Nmap Security Scanner is (C) 1996-2020 Insecure.Com LLC ("The Nmap  *
10  * Project"). Nmap is also a registered trademark of the Nmap Project.     *
11  *                                                                         *
12  * This program is distributed under the terms of the Nmap Public Source   *
13  * License (NPSL). The exact license text applying to a particular Nmap    *
14  * release or source code control revision is contained in the LICENSE     *
15  * file distributed with that version of Nmap or source code control       *
16  * revision. More Nmap copyright/legal information is available from       *
17  * https://nmap.org/book/man-legal.html, and further information on the    *
18  * NPSL license itself can be found at https://nmap.org/npsl. This header  *
19  * summarizes some key points from the Nmap license, but is no substitute  *
20  * for the actual license text.                                            *
21  *                                                                         *
22  * Nmap is generally free for end users to download and use themselves,    *
23  * including commercial use. It is available from https://nmap.org.        *
24  *                                                                         *
25  * The Nmap license generally prohibits companies from using and           *
26  * redistributing Nmap in commercial products, but we sell a special Nmap  *
27  * OEM Edition with a more permissive license and special features for     *
28  * this purpose. See https://nmap.org/oem                                  *
29  *                                                                         *
30  * If you have received a written Nmap license agreement or contract       *
31  * stating terms other than these (such as an Nmap OEM license), you may   *
32  * choose to use and redistribute Nmap under those terms instead.          *
33  *                                                                         *
34  * The official Nmap Windows builds include the Npcap software             *
35  * (https://npcap.org) for packet capture and transmission. It is under    *
36  * separate license terms which forbid redistribution without special      *
37  * permission. So the official Nmap Windows builds may not be              *
38  * redistributed without special permission (such as an Nmap OEM           *
39  * license).                                                               *
40  *                                                                         *
41  * Source is provided to this software because we believe users have a     *
42  * right to know exactly what a program is going to do before they run it. *
43  * This also allows you to audit the software for security holes.          *
44  *                                                                         *
45  * Source code also allows you to port Nmap to new platforms, fix bugs,    *
46  * and add new features.  You are highly encouraged to submit your         *
47  * changes as a Github PR or by email to the dev@nmap.org mailing list     *
48  * for possible incorporation into the main distribution. Unless you       *
49  * specify otherwise, it is understood that you are offering us very       *
50  * broad rights to use your submissions as described in the Nmap Public    *
51  * Source License Contributor Agreement. This is important because we      *
52  * fund the project by selling licenses with various terms, and also       *
53  * because the inability to relicense code has caused devastating          *
54  * problems for other Free Software projects (such as KDE and NASM).       *
55  *                                                                         *
56  * The free version of Nmap is distributed in the hope that it will be     *
57  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of  *
58  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,        *
59  * indemnification and commercial support are all available through the    *
60  * Npcap OEM program--see https://nmap.org/oem.                            *
61  *                                                                         *
62  ***************************************************************************/
63 /* This code was originally part of the Nping tool.                        */
64 
65 #include "ICMPv6Header.h"
66 #include "IPv6Header.h"
67 #include <assert.h>
68 
69 /******************************************************************************/
70 /* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS                        */
71 /******************************************************************************/
ICMPv6Header()72 ICMPv6Header::ICMPv6Header() {
73   this->reset();
74 } /* End of ICMPv6Header constructor */
75 
76 
~ICMPv6Header()77 ICMPv6Header::~ICMPv6Header() {
78 
79 } /* End of ICMPv6Header destructor */
80 
81 
82 /** Sets every attribute to its default value */
reset()83 void ICMPv6Header::reset(){
84   memset(&this->h, 0, sizeof(nping_icmpv6_hdr_t));
85   h_du = (dest_unreach_msg_t       *)this->h.data;
86   h_ptb= (pkt_too_big_msg_t        *)this->h.data;
87   h_te = (time_exceeded_msg_t      *)this->h.data;
88   h_pp = (parameter_problem_msg_t  *)this->h.data;
89   h_e  = (echo_msg_t               *)this->h.data;
90   h_ra = (router_advert_msg_t      *)this->h.data;
91   h_rs = (router_solicit_msg_t     *)this->h.data;
92   h_na = (neighbor_advert_msg_t    *)this->h.data;
93   h_ns = (neighbor_solicit_msg_t   *)this->h.data;
94   h_r  = (redirect_msg_t           *)this->h.data;
95   h_rr = (router_renumbering_msg_t *)this->h.data;
96   h_ni = (nodeinfo_msg_t           *)this->h.data;
97   h_mld= (mld_msg_t                *)this->h.data;
98 } /* End of reset() */
99 
100 
101 /******************************************************************************/
102 /* PacketElement:: OVERWRITTEN METHODS                                        */
103 /******************************************************************************/
104 
105 /** @warning This method is essential for the superclass getBinaryBuffer()
106  *  method to work. Do NOT change a thing unless you know what you're doing  */
getBufferPointer()107 u8 *ICMPv6Header::getBufferPointer(){
108   return (u8*)(&this->h);
109 } /* End of getBufferPointer() */
110 
111 
112 /** Stores supplied packet in the internal buffer so the information
113   * can be accessed using the standard get & set methods.
114   * @warning  The ICMPv6Header class is able to hold a maximum of
115   * sizeof(nping_icmpv6_hdr_t) bytes. If the supplied buffer is longer than
116   * that, only the first 1508 bytes will be stored in the internal buffer.
117   * @warning Supplied len MUST be at least 8 bytes (min ICMPv6 header length).
118   * @return OP_SUCCESS on success and OP_FAILURE in case of error */
storeRecvData(const u8 * buf,size_t len)119 int ICMPv6Header::storeRecvData(const u8 *buf, size_t len){
120   if(buf==NULL || len<ICMPv6_MIN_HEADER_LEN){
121     this->length=0;
122     return OP_FAILURE;
123   }else{
124     int stored_len = MIN( sizeof(nping_icmpv6_hdr_t), len);
125     this->reset(); /* Re-init the object, just in case the caller had used it already */
126     this->length=stored_len;
127     memcpy(&(this->h), buf, stored_len);
128   }
129  return OP_SUCCESS;
130 } /* End of storeRecvData() */
131 
132 
133 /* Returns a protocol identifier. This is used by packet parsing funtions
134  * that return linked lists of PacketElement objects, to determine the protocol
135  * the object represents. */
protocol_id() const136 int ICMPv6Header::protocol_id() const {
137     return HEADER_TYPE_ICMPv6;
138 } /* End of protocol_id() */
139 
140 
141 /** Determines if the data stored in the object after an storeRecvData() call
142   * is valid and safe to use. This mainly checks the length of the data but may
143   * also test the value of certain protocol fields to ensure their correctness.
144   * @return the length, in bytes, of the header, if its found to be valid or
145   * OP_FAILURE (-1) otherwise. */
validate()146 int ICMPv6Header::validate(){
147   int should_have=this->getHeaderLengthFromType( this->getType() );
148   if(this->length < should_have){
149       return OP_FAILURE;
150   }else{
151       /* WARNING: If we extend this class to support new ICMPv6 types with
152        * a variable length header (not even sure they exist), we need to
153        * parse the objects data and return our actual size, not this size that
154        * is obtained from the type. */
155       return should_have;
156   }
157 } /* End of validate() */
158 
159 
160 /** Prints the contents of the header and calls print() on the next protocol
161   * header in the chain (if there is any).
162   * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
print(FILE * output,int detail) const163 int ICMPv6Header::print(FILE *output, int detail) const {
164   u8 type=this->getType();
165   u8 code=this->getCode();
166   const char *typestr=this->type2string(type, code);
167 
168   fprintf(output, "ICMPv6[%s", typestr);
169   if(detail>=PRINT_DETAIL_MED)
170     fprintf(output, " (type=%u/code=%u)", type, code);
171 
172   switch(type) {
173 
174     case ICMPv6_UNREACH:
175     case ICMPv6_TIMXCEED:
176       if(detail>=PRINT_DETAIL_HIGH)
177         fprintf(output, " unused=%lu", (long unsigned int)this->getUnused());
178     break;
179 
180     case ICMPv6_ROUTERSOLICIT:
181       if(detail>=PRINT_DETAIL_HIGH)
182         fprintf(output, " reserved=%lu", (long unsigned int)this->getReserved());
183     break;
184 
185     case ICMPv6_PKTTOOBIG:
186       fprintf(output, " mtu=%lu", (long unsigned int)this->getMTU());
187     break;
188 
189     case ICMPv6_PARAMPROB:
190       fprintf(output, " pointer=%lu", (long unsigned int)this->getPointer());
191     break;
192 
193     case ICMPv6_ECHO:
194     case ICMPv6_ECHOREPLY:
195       fprintf(output, " id=%u seq=%u", this->getIdentifier(), this->getSequence());
196     break;
197 
198     case ICMPv6_NODEINFOQUERY:
199     case ICMPv6_NODEINFORESP:
200       if(this->getNodeInfoFlags()!=0){
201         fprintf(output, " flags=");
202         if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_T)
203           fprintf(output, "T");
204         if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_A)
205           fprintf(output, "A");
206         if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_C)
207           fprintf(output, "C");
208         if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_L)
209           fprintf(output, "L");
210         if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_G)
211           fprintf(output, "G");
212         if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_S)
213           fprintf(output, "S");
214         }
215       if(detail>=PRINT_DETAIL_HIGH){
216         #ifdef WIN32
217           fprintf(output, " nonce=%I64u",  (long long unsigned int)this->getNonce());
218         #else
219           fprintf(output, " nonce=%llu",  (long long unsigned int)this->getNonce());
220         #endif
221       }
222     break;
223 
224     default:
225         /* Print nothing */
226     break;
227   }
228 
229   if(detail>=PRINT_DETAIL_HIGH)
230       fprintf(output, " csum=0x%04X", ntohs(this->getSum()));
231   fprintf(output, "]");
232   if(this->next!=NULL){
233     print_separator(output, detail);
234     next->print(output, detail);
235   }
236   return OP_SUCCESS;
237 } /* End of print() */
238 
239 
240 /******************************************************************************/
241 /* PROTOCOL-SPECIFIC METHODS                                                  */
242 /******************************************************************************/
243 
244 /******************************************************************************/
245 /* ICMPv6 COMMON HEADER                                                       */
246 /******************************************************************************/
247 
248 /** Set ICMPv6 type field */
setType(u8 val)249 int ICMPv6Header::setType(u8 val){
250   this->h.type = val;
251   this->length = getHeaderLengthFromType(val);
252   return OP_SUCCESS;
253 } /* End of setType() */
254 
255 
256 /** Returns ICMPv6 type field */
getType() const257 u8 ICMPv6Header::getType() const {
258   return this->h.type;
259 } /* End of getType() */
260 
261 
262 /* Returns true if the supplied ICMPv6 type is supported by this class */
validateType(u8 val)263 bool ICMPv6Header::validateType(u8 val){
264   switch( val ){
265     case ICMPv6_UNREACH:
266     case ICMPv6_PKTTOOBIG:
267     case ICMPv6_TIMXCEED:
268     case ICMPv6_PARAMPROB:
269     case ICMPv6_ECHO:
270     case ICMPv6_ECHOREPLY:
271     case ICMPv6_ROUTERSOLICIT:
272     case ICMPv6_ROUTERADVERT:
273     case ICMPv6_NGHBRSOLICIT:
274     case ICMPv6_NGHBRADVERT:
275     case ICMPv6_REDIRECT:
276     case ICMPv6_RTRRENUM:
277         return true;
278     break;
279 
280     default:
281         return false;
282     break;
283   }
284   return false;
285 } /* End of validateType() */
286 
287 
validateType()288 bool ICMPv6Header::validateType(){
289   return validateType(this->h.type);
290 } /* End of validateType() */
291 
292 
293 /** Set ICMPv6 code field */
setCode(u8 val)294 int ICMPv6Header::setCode(u8 val){
295   this->h.code = val;
296   return OP_SUCCESS;
297 } /* End of setCode() */
298 
299 
300 /** Returns ICMPv6 code field */
getCode() const301 u8 ICMPv6Header::getCode() const {
302   return this->h.code;
303 } /* End of getCode() */
304 
305 
306 /** Given an ICMP Type and a code, determines whether the code corresponds to
307   * a RFC compliant code (eg: code 0x03  for "port unreachable" in ICMP
308   * Unreachable messages) or just some other bogus code. */
validateCode(u8 type,u8 code)309 bool ICMPv6Header::validateCode(u8 type, u8 code){
310 //    switch (type){
311 //
312 //        case ICMPv6_UNREACH:
313 //            return (code==0);
314 //        break;
315 //
316 //        case ICMPv6_PKTTOOBIG:
317 //            switch( code ){
318 //                case XXXXXXXXXXXX:
319 //                case YYYYYYYYYYYY:
320 //                case ZZZZZZZZZZZZ:
321 //                    return true;
322 //                break;
323 //            }
324 //        break;
325 //
326 //        case ICMPv6_TIMXCEED:
327 //
328 //        break;
329 //
330 //        case ICMPv6_PARAMPROB:
331 //
332 //        break;
333 //
334 //        case ICMPv6_ECHO:
335 //
336 //        break;
337 //
338 //        case ICMPv6_ECHOREPLY:
339 //
340 //        break;
341 //
342 //        case ICMPv6_ROUTERSOLICIT:
343 //        case ICMPv6_ROUTERADVERT:
344 //        case ICMPv6_NGHBRSOLICIT:
345 //        case ICMPv6_NGHBRADVERT:
346 //        case ICMPv6_REDIRECT:
347 //        break;
348 //
349 //        default:
350 //            return false;
351 //        break;
352 //    }
353     return false;
354 } /* End of validateCode() */
355 
356 
357 /** Computes the ICMP header checksum and sets the checksum field to the right
358  *  value.
359  * @warning  This method requires the ICMPv6Object to be linked to an IPv6Header
360  * object, so make sure setNextElement() has been called like this:
361  *
362  * IPv6Header ip6;
363  * ICMPv6Header icmp6;
364  * [...] # Set header fields
365  * ip6.setNextElement(&icmp6);
366  * icmp6.setSum();
367  *
368  * Note that there can be a number of extension headers between the ICMPv6
369  * header and the IPv6 one, but all of them need to be linked in order for this
370  * method to traverse the list of headers and find the IPv6 source and
371  * destination address, required to compute the checksum. So things like the
372  * following are OK:
373  *
374  * IPv6Header ip6;
375  * HopByHopHeader hop;
376  * RoutingHeader rte;
377  * FragmentHeader frg;
378  * ICMPv6Header icmp6;
379  * [...] # Set whatever header fields you need
380  * ip6.setNextElement(&hop);
381  * hop.setNextElement(&rte);
382  * rte.setNextElement(&frg);
383  * frg.setNextElement(&icmp6);
384  * icmp6.setSum(); # setSum() will be able to reach the IPv6Header.
385  *
386  */
setSum()387 int ICMPv6Header::setSum(){
388   PacketElement *hdr;
389   hdr=this->getPrevElement();
390   /* Traverse the list of headers backwards until we find the IPv6 header */
391   while(hdr!=NULL){
392       if (hdr->protocol_id()==HEADER_TYPE_IPv6){
393             IPv6Header *v6hdr=(IPv6Header *)hdr;
394             struct in6_addr i6src, i6dst;
395             this->h.checksum=0;
396             memcpy(i6src.s6_addr, v6hdr->getSourceAddress(), 16);
397             memcpy(i6dst.s6_addr, v6hdr->getDestinationAddress(), 16);
398             u8 *buff=(u8 *)safe_malloc(this->getLen());
399             this->dumpToBinaryBuffer(buff, this->getLen());
400             this->h.checksum=ipv6_pseudoheader_cksum(&i6src, &i6dst, this->protocol_id(), this->getLen(), buff);
401             free(buff);
402           return OP_SUCCESS;
403       }else{
404           hdr=hdr->getPrevElement();
405       }
406   }
407   return OP_FAILURE;
408 } /* End of setSum() */
409 
410 
411 /** @warning Sum is set to supplied value with NO byte ordering conversion
412  *  performed.
413  *  @warning If sum is supplied this way, no error checks are made. Caller is
414  *  responsible for the correctness of the value. */
setSum(u16 s)415 int ICMPv6Header::setSum(u16 s){
416   this->h.checksum=s;
417   return OP_SUCCESS;
418 } /* End of setSum() */
419 
420 
421 /** Returns the value of the checksum field.
422  *  @warning The returned value is in NETWORK byte order, no conversion is
423  *  performed */
getSum() const424 u16 ICMPv6Header::getSum() const{
425   return this->h.checksum;
426 } /* End of getSum() */
427 
428 
429 /** @warning Supplied value MUST be in host byte order because it will get
430  *  converted by this method using htonl() */
setReserved(u32 val)431 int ICMPv6Header::setReserved(u32 val){
432   u32 aux32=0;
433   u8 *auxpnt=(u8 *)&aux32;
434 
435   switch(this->h.type){
436 
437     case ICMPv6_UNREACH:
438         this->h_du->unused=htonl(val);
439     break;
440 
441     case ICMPv6_TIMXCEED:
442         this->h_te->unused=htonl(val);
443     break;
444 
445     case ICMPv6_ROUTERSOLICIT:
446         this->h_rs->reserved=htonl(val);
447     break;
448 
449     case ICMPv6_NGHBRSOLICIT:
450         this->h_ns->reserved=htonl(val);
451     break;
452 
453     case ICMPv6_REDIRECT:
454         this->h_r->reserved=htonl(val);
455     break;
456 
457 
458     case ICMPv6_NGHBRADVERT:
459         /* The reserved field in Neighbor Advertisement messages is only
460          * 24-bits long so we convert the supplied value to big endian and
461          * use only the 24 least significant bits. */
462         aux32=htonl(val);
463         this->h_na->reserved[0]=auxpnt[1];
464         this->h_na->reserved[1]=auxpnt[2];
465         this->h_na->reserved[2]=auxpnt[3];
466     break;
467 
468     case ICMPv6_RTRRENUM:
469         this->h_rr->reserved=htonl(val);
470     break;
471 
472     /* Types that don't have a reserved field */
473     case ICMPv6_ROUTERADVERT:
474     case ICMPv6_ECHO:
475     case ICMPv6_ECHOREPLY:
476     case ICMPv6_PARAMPROB:
477     case ICMPv6_PKTTOOBIG:
478     default:
479         return OP_FAILURE;
480     break;
481   }
482   return OP_SUCCESS;
483 } /* End of setReserved() */
484 
485 
486 /** @warning Returned value is in host byte order */
getReserved() const487 u32 ICMPv6Header::getReserved() const {
488   u32 aux32=0;
489   u8 *auxpnt=(u8 *)&aux32;
490 
491   switch(this->h.type){
492 
493     case ICMPv6_UNREACH:
494         return ntohl(this->h_du->unused);
495     break;
496 
497     case ICMPv6_TIMXCEED:
498         return ntohl(this->h_te->unused);
499     break;
500 
501     case ICMPv6_ROUTERSOLICIT:
502         return ntohl(this->h_rs->reserved);
503     break;
504 
505     case ICMPv6_NGHBRSOLICIT:
506         return ntohl(this->h_ns->reserved);
507     break;
508 
509     case ICMPv6_REDIRECT:
510         return ntohl(this->h_r->reserved);
511     break;
512 
513     case ICMPv6_NGHBRADVERT:
514         /* The reserved field in Neighbor Advertisement messages is only
515          * 24-bits long so we extract the stored value and convert it to host
516          * byte order. */
517         auxpnt[0]=0;
518         auxpnt[1]=this->h_na->reserved[0];
519         auxpnt[2]=this->h_na->reserved[1];
520         auxpnt[3]=this->h_na->reserved[2];
521         return ntohl(aux32);
522     break;
523 
524     case ICMPv6_RTRRENUM:
525         return ntohl(this->h_rr->reserved);
526     break;
527 
528     /* Types that don't have a reserved field */
529     case ICMPv6_ROUTERADVERT:
530     case ICMPv6_ECHO:
531     case ICMPv6_ECHOREPLY:
532     case ICMPv6_PARAMPROB:
533     case ICMPv6_PKTTOOBIG:
534     default:
535         return 0;
536     break;
537   }
538 } /* End of setReserved() */
539 
setUnused(u32 val)540 int ICMPv6Header::setUnused(u32 val){
541   return this->setReserved(val);
542 } /* End of setUnused() */
543 
544 
getUnused() const545 u32 ICMPv6Header::getUnused() const {
546   return this->getReserved();
547 } /* End of getUnused() */
548 
549 
setFlags(u8 val)550 int ICMPv6Header::setFlags(u8 val){
551   switch(this->h.type){
552 
553     case ICMPv6_ROUTERADVERT:
554         this->h_ra->autoconfig_flags=val;
555     break;
556 
557     case ICMPv6_NGHBRADVERT:
558         this->h_na->flags=val;
559     break;
560 
561     case ICMPv6_RTRRENUM:
562         this->h_rr->flags=val;
563     break;
564 
565     case ICMPv6_NODEINFOQUERY:
566     case ICMPv6_NODEINFORESP:
567         netutil_fatal("setFlags() cannot be used in NI, use setNodeInfoFlags() instead\n");
568     break;
569 
570     /* Types that don't have a flags field */
571     case ICMPv6_TIMXCEED:
572     case ICMPv6_UNREACH:
573     case ICMPv6_ROUTERSOLICIT:
574     case ICMPv6_NGHBRSOLICIT:
575     case ICMPv6_REDIRECT:
576     case ICMPv6_ECHO:
577     case ICMPv6_ECHOREPLY:
578     case ICMPv6_PARAMPROB:
579     case ICMPv6_PKTTOOBIG:
580     default:
581         return OP_FAILURE;
582     break;
583   }
584   return OP_SUCCESS;
585 } /* End of setFlags() */
586 
587 
getFlags() const588 u8 ICMPv6Header::getFlags() const {
589   switch(this->h.type){
590 
591     case ICMPv6_ROUTERADVERT:
592         return this->h_ra->autoconfig_flags;
593     break;
594 
595     case ICMPv6_NGHBRADVERT:
596         return this->h_na->flags;
597     break;
598 
599     case ICMPv6_RTRRENUM:
600         return this->h_rr->flags;
601     break;
602 
603     case ICMPv6_NODEINFOQUERY:
604     case ICMPv6_NODEINFORESP:
605         netutil_fatal("getFlags() cannot be used in NI, use getNodeInfoFlags() instead\n");
606         return 0;
607     break;
608 
609     /* Types that don't have a flags field */
610     case ICMPv6_TIMXCEED:
611     case ICMPv6_UNREACH:
612     case ICMPv6_ROUTERSOLICIT:
613     case ICMPv6_NGHBRSOLICIT:
614     case ICMPv6_REDIRECT:
615     case ICMPv6_ECHO:
616     case ICMPv6_ECHOREPLY:
617     case ICMPv6_PARAMPROB:
618     case ICMPv6_PKTTOOBIG:
619     default:
620         return 0;
621     break;
622   }
623 } /* End of getFlags() */
624 
625 /******************************************************************************/
626 /* ICMPv6 DESTINATION UNREACHABLE                                             */
627 /******************************************************************************/
628 
629 /******************************************************************************/
630 /* ICMPv6 PACKET TOO BIG                                                      */
631 /******************************************************************************/
setMTU(u32 mtu)632 int ICMPv6Header::setMTU(u32 mtu){
633   this->h_ptb->mtu=htonl(mtu);
634   return OP_SUCCESS;
635 } /* End of setMTU() */
636 
getMTU() const637 u32 ICMPv6Header::getMTU() const {
638   return ntohl(this->h_ptb->mtu);
639 } /* End of getMTU() */
640 
641 /******************************************************************************/
642 /* ICMPv6 TIME EXCEEDED                                                       */
643 /******************************************************************************/
644 
645 /******************************************************************************/
646 /* ICMPv6 PARAMETER PROBLEM                                                   */
647 /******************************************************************************/
setPointer(u32 pnt)648 int ICMPv6Header::setPointer(u32 pnt){
649   this->h_pp->pointer=htonl(pnt);
650   return OP_SUCCESS;
651 } /* End of setPointer() */
652 
653 
getPointer() const654 u32 ICMPv6Header::getPointer() const {
655   return ntohl(this->h_pp->pointer);
656 } /* End of getPointer() */
657 
658 /******************************************************************************/
659 /* ICMPv6 ECHO                                                                */
660 /******************************************************************************/
setIdentifier(u16 val)661 int ICMPv6Header::setIdentifier(u16 val){
662   this->h_e->id=htons(val);
663   return OP_SUCCESS;
664 } /* End of setIdentifier() */
665 
666 
getIdentifier() const667 u16 ICMPv6Header::getIdentifier() const{
668   return ntohs(this->h_e->id);
669 } /* End of getIdentifier() */
670 
671 
setSequence(u16 val)672 int ICMPv6Header::setSequence(u16 val){
673   switch(this->h.type){
674     case ICMPv6_RTRRENUM:
675         this->h_rr->seq=htonl( ((u32)val) );
676     break;
677 
678     case ICMPv6_ECHO:
679     case ICMPv6_ECHOREPLY:
680         this->h_e->seq=htons(val);
681     break;
682 
683     default:
684         return OP_FAILURE;
685     break;
686   }
687   return OP_SUCCESS;
688 } /* End of setSequence() */
689 
690 
setSequence(u32 val)691 int ICMPv6Header::setSequence(u32 val){
692   switch(this->h.type){
693     case ICMPv6_RTRRENUM:
694         this->h_rr->seq=htonl(val);
695     break;
696 
697     case ICMPv6_ECHO:
698     case ICMPv6_ECHOREPLY:
699         this->h_e->seq=htons( ((u16)val) );
700     break;
701 
702     default:
703         return OP_FAILURE;
704     break;
705   }
706   return OP_SUCCESS;
707 } /* End of setSequence() */
708 
709 
getSequence() const710 u32 ICMPv6Header::getSequence() const{
711   switch(this->h.type){
712     case ICMPv6_RTRRENUM:
713         return ntohl(this->h_rr->seq);
714     break;
715 
716     case ICMPv6_ECHO:
717     case ICMPv6_ECHOREPLY:
718         return (u32)ntohs(this->h_e->seq);
719     break;
720   }
721   return 0;
722 } /* End of getSequence() */
723 
724 
725 /******************************************************************************/
726 /* ICMPv6 ROUTER ADVERTISEMENT                                                */
727 /******************************************************************************/
setCurrentHopLimit(u8 val)728 int ICMPv6Header::setCurrentHopLimit(u8 val){
729   this->h_ra->current_hop_limit=val;
730   return OP_SUCCESS;
731 } /* End of setCurrentHopLimit() */
732 
getCurrentHopLimit() const733 u8 ICMPv6Header::getCurrentHopLimit() const {
734   return this->h_ra->current_hop_limit;
735 } /* End of getCurrentHopLimit() */
736 
setRouterLifetime(u16 val)737 int ICMPv6Header::setRouterLifetime(u16 val){
738   this->h_ra->router_lifetime=val;
739   return OP_SUCCESS;
740 } /* End of setRouterLifetime() */
741 
getRouterLifetime() const742 u16 ICMPv6Header::getRouterLifetime() const {
743   return this->h_ra->router_lifetime;
744 } /* End of getRouterLifetime() */
745 
setReachableTime(u32 val)746 int ICMPv6Header::setReachableTime(u32 val){
747   this->h_ra->reachable_time=val;
748   return OP_SUCCESS;
749 } /* End of setReachableTime() */
750 
getReachableTime() const751 u32 ICMPv6Header::getReachableTime() const {
752     return this->h_ra->reachable_time;
753 } /* End of getReachableTime() */
754 
setRetransmissionTimer(u32 val)755 int ICMPv6Header::setRetransmissionTimer(u32 val){
756   this->h_ra->retransmission_timer=val;
757   return OP_SUCCESS;
758 } /* End of setRetransmissionTimer() */
759 
getRetransmissionTimer() const760 u32 ICMPv6Header::getRetransmissionTimer() const {
761   return this->h_ra->retransmission_timer;
762 } /* End of getRetransmissionTimer() */
763 
764 /******************************************************************************/
765 /* ICMPv6 ROUTER SOLICITATION                                                 */
766 /******************************************************************************/
767 
768 /******************************************************************************/
769 /* ICMPv6 NEIGHBOR ADVERTISEMENT                                              */
770 /******************************************************************************/
771 
setTargetAddress(struct in6_addr addr)772 int ICMPv6Header::setTargetAddress(struct in6_addr addr){
773   switch(this->h.type){
774     case ICMPv6_NGHBRADVERT:
775         memcpy(this->h_na->target_address, addr.s6_addr, 16);
776     break;
777 
778     case ICMPv6_NGHBRSOLICIT:
779         memcpy(this->h_ns->target_address, addr.s6_addr, 16);
780     break;
781 
782     case ICMPv6_REDIRECT:
783          memcpy(this->h_r->target_address, addr.s6_addr, 16);
784     break;
785 
786     default:
787         return OP_FAILURE;
788     break;
789   }
790   return OP_SUCCESS;
791 } /* End of setTargetAddress() */
792 
793 
getTargetAddress() const794 struct in6_addr ICMPv6Header::getTargetAddress() const {
795   struct in6_addr addr;
796   memset(&addr, 0, sizeof(struct in6_addr));
797 
798   switch(this->h.type){
799     case ICMPv6_NGHBRADVERT:
800         memcpy(addr.s6_addr, this->h_na->target_address, 16);
801     break;
802 
803     case ICMPv6_NGHBRSOLICIT:
804         memcpy(addr.s6_addr, this->h_ns->target_address, 16);
805     break;
806 
807     case ICMPv6_REDIRECT:
808          memcpy(addr.s6_addr, this->h_r->target_address, 16);
809     break;
810   }
811   return addr;
812 } /* End of setTargetAddress() */
813 
814 
setDestinationAddress(struct in6_addr addr)815 int ICMPv6Header::setDestinationAddress(struct in6_addr addr){
816   switch(this->h.type){
817     case ICMPv6_REDIRECT:
818          memcpy(this->h_r->destination_address, addr.s6_addr, 16);
819     break;
820 
821     default:
822         return OP_FAILURE;
823     break;
824   }
825   return OP_SUCCESS;
826 } /* End of setDestinationAddress() */
827 
828 
getDestinationAddress() const829 struct in6_addr ICMPv6Header::getDestinationAddress() const {
830   struct in6_addr addr;
831   memset(&addr, 0, sizeof(struct in6_addr));
832 
833   switch(this->h.type){
834     case ICMPv6_REDIRECT:
835          memcpy(addr.s6_addr, this->h_r->destination_address, 16);
836     break;
837   }
838   return addr;
839 } /* End of setTargetAddress() */
840 
841 
842 /******************************************************************************/
843 /* ICMPv6 NEIGHBOR SOLICITATION                                               */
844 /******************************************************************************/
845 
846 /******************************************************************************/
847 /* ICMPv6 REDIRECT                                                            */
848 /******************************************************************************/
849 
850 /******************************************************************************/
851 /* ICMPv6 ROUTER RENUMBERING                                                  */
852 /******************************************************************************/
setSegmentNumber(u8 val)853 int ICMPv6Header::setSegmentNumber(u8 val){
854   this->h_rr->segment_number=val;
855   return OP_SUCCESS;
856 } /* End of setSegmentNumber() */
857 
getSegmentNumber() const858 u8 ICMPv6Header::getSegmentNumber() const {
859   return this->h_rr->segment_number;
860 } /* End of getSegmentNumber() */
861 
setMaxDelay(u16 val)862 int ICMPv6Header::setMaxDelay(u16 val){
863   switch(this->h.type){
864     case ICMPv6_RTRRENUM:
865       this->h_rr->max_delay=htons(val);
866       return OP_SUCCESS;
867     break;
868 
869     case ICMPv6_GRPMEMBQUERY:
870     case ICMPv6_GRPMEMBREP:
871     case ICMPv6_GRPMEMBRED:
872       this->h_mld->max_response_delay=htons(val);
873       return OP_SUCCESS;
874     break;
875 
876     default:
877       return OP_FAILURE;
878     break;
879   }
880 } /* End of setMaxDelay() */
881 
882 
getMaxDelay() const883 u16 ICMPv6Header::getMaxDelay() const {
884   switch(this->h.type){
885     case ICMPv6_RTRRENUM:
886       return ntohs(this->h_rr->max_delay);
887     break;
888 
889     case ICMPv6_GRPMEMBQUERY:
890     case ICMPv6_GRPMEMBREP:
891     case ICMPv6_GRPMEMBRED:
892       return ntohs(this->h_mld->max_response_delay);
893     break;
894 
895     default:
896       return 0;
897     break;
898   }
899 } /* End of getMaxDelay() */
900 
901 
902 
903 /******************************************************************************/
904 /* ICMPv6 NODE INFORMATION QUERIES                                            */
905 /******************************************************************************/
906 /** Set NI Qtype */
setQtype(u16 val)907 int ICMPv6Header::setQtype(u16 val){
908   this->h_ni->qtype = htons(val);
909   return OP_SUCCESS;
910 } /* End of setQtype() */
911 
912 
913 /** Returns NI Qtype */
getQtype() const914 u16 ICMPv6Header::getQtype() const {
915   return ntohs(this->h_ni->qtype);
916 } /* End of getQtype() */
917 
918 
919 /** Set NI Flags */
setNodeInfoFlags(u16 val)920 int ICMPv6Header::setNodeInfoFlags(u16 val){
921   this->h_ni->flags = htons(val);
922   return OP_SUCCESS;
923 } /* End of setNodeInfoFlags() */
924 
925 
926 /** Returns NI Flags */
getNodeInfoFlags() const927 u16 ICMPv6Header::getNodeInfoFlags() const {
928   return ntohs(this->h_ni->flags);
929 } /* End of getNodeInfoFlags() */
930 
931 
932 /*  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
933    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
934    |       unused      |G|S|L|C|A|T|
935    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
936 
937 /* Set NI Flag G */
setG(bool flag_value)938 int ICMPv6Header::setG(bool flag_value){
939   u16 current_flags = this->getNodeInfoFlags();
940   if(flag_value)
941     current_flags = current_flags | 0x0020;
942   else
943     current_flags = current_flags & ~0x0020;
944   this->setNodeInfoFlags(current_flags);
945   return OP_SUCCESS;
946 } /* End of setG() */
947 
948 
949 /* Get NI Flag G */
getG() const950 bool ICMPv6Header::getG() const {
951   return this->getNodeInfoFlags() & 0x0020;
952 } /* End of getG() */
953 
954 
955 /* Set NI Flag S */
setS(bool flag_value)956 int ICMPv6Header::setS(bool flag_value){
957   u16 current_flags = this->getNodeInfoFlags();
958   if(flag_value)
959     current_flags = current_flags | 0x0010;
960   else
961     current_flags = current_flags & ~0x0010;
962   this->setNodeInfoFlags(current_flags);
963   return OP_SUCCESS;
964 } /* End of setS() */
965 
966 
967 /* Get NI Flag  S */
getS() const968 bool ICMPv6Header::getS() const {
969   return this->getNodeInfoFlags() & 0x0010;
970 } /* End of getS() */
971 
972 
973 /* Set NI Flag L */
setL(bool flag_value)974 int ICMPv6Header::setL(bool flag_value){
975   u16 current_flags = this->getNodeInfoFlags();
976   if(flag_value)
977     current_flags = current_flags | 0x0008;
978   else
979     current_flags = current_flags & ~0x0008;
980   this->setNodeInfoFlags(current_flags);
981   return OP_SUCCESS;
982 } /* End of setL() */
983 
984 
985 /* Get NI Flag L */
getL() const986 bool ICMPv6Header::getL() const {
987   return this->getNodeInfoFlags() & 0x0008;
988 } /* End of getL() */
989 
990 
991 /* Set NI Flag C */
setC(bool flag_value)992 int ICMPv6Header::setC(bool flag_value){
993   u16 current_flags = this->getNodeInfoFlags();
994   if(flag_value)
995     current_flags = current_flags | 0x0004;
996   else
997     current_flags = current_flags & ~0x0004;
998   this->setNodeInfoFlags(current_flags);
999   return OP_SUCCESS;
1000 } /* End of setC() */
1001 
1002 
1003 /* Get NI Flag C */
getC() const1004 bool ICMPv6Header::getC() const {
1005   return this->getNodeInfoFlags() & 0x0004;
1006 } /* End of getC() */
1007 
1008 
1009 /* Set NI Flag A */
setA(bool flag_value)1010 int ICMPv6Header::setA(bool flag_value){
1011   u16 current_flags = this->getNodeInfoFlags();
1012   if(flag_value)
1013     current_flags = current_flags | 0x0002;
1014   else
1015     current_flags = current_flags & ~0x0002;
1016   this->setNodeInfoFlags(current_flags);
1017   return OP_SUCCESS;
1018 } /* End of setA() */
1019 
1020 
1021 /* Get NI Flag A */
getA() const1022 bool ICMPv6Header::getA() const {
1023   return this->getNodeInfoFlags() & 0x0002;
1024 } /* End of getA() */
1025 
1026 
1027 /* Set NI Flag T */
setT(bool flag_value)1028 int ICMPv6Header::setT(bool flag_value){
1029   u16 current_flags = this->getNodeInfoFlags();
1030   if(flag_value)
1031     current_flags = current_flags | 0x0001;
1032   else
1033     current_flags = current_flags & ~0x0001;
1034   this->setNodeInfoFlags(current_flags);
1035   return OP_SUCCESS;
1036 } /* End of setT() */
1037 
1038 
1039 /* Get NI Flag T */
getT() const1040 bool ICMPv6Header::getT() const {
1041   return this->getNodeInfoFlags() & 0x0001;
1042 } /* End of getT() */
1043 
1044 
1045 /* Set the Nonce field. */
setNonce(u64 nonce_value)1046 int ICMPv6Header::setNonce(u64 nonce_value){
1047   this->h_ni->nonce=nonce_value;
1048   return OP_SUCCESS;
1049 } /* End of setNonce() */
1050 
1051 
1052 /* Set the Nonce field.
1053  * @warning: Supplied buffer must contain 8 bytes. */
setNonce(const u8 * nonce)1054 int ICMPv6Header::setNonce(const u8 *nonce){
1055   if(nonce==NULL)
1056     return OP_FAILURE;
1057   memcpy(&(this->h_ni->nonce), nonce, NI_NONCE_LEN);
1058   return OP_SUCCESS;
1059 } /* End of setNonce() */
1060 
1061 
1062 /* Returns a pointer to the nonce buffer.
1063  * @warning: The returned pointer is guaranteed to point to an 8-byte buffer.
1064  * However, what comes after the 8th byte is unspecified. */
getNonce() const1065 u64 ICMPv6Header::getNonce() const {
1066   return this->h_ni->nonce;
1067 } /* End of getNonce() */
1068 
1069 
1070 /******************************************************************************/
1071 /* MULTICAST LISTENER DISCOVERY                                               */
1072 /******************************************************************************/
1073 
setMulticastAddress(struct in6_addr addr)1074 int ICMPv6Header::setMulticastAddress(struct in6_addr addr){
1075   switch(this->h.type){
1076     case ICMPv6_GRPMEMBQUERY:
1077     case ICMPv6_GRPMEMBREP:
1078     case ICMPv6_GRPMEMBRED:
1079        memcpy(this->h_mld->mcast_address, addr.s6_addr, 16);
1080     break;
1081 
1082     default:
1083         return OP_FAILURE;
1084     break;
1085   }
1086 
1087   return OP_SUCCESS;
1088 } /* End of setMulticastAddress() */
1089 
1090 
getMulticastAddress() const1091 struct in6_addr ICMPv6Header::getMulticastAddress() const {
1092   struct in6_addr addr;
1093   memset(&addr, 0, sizeof(struct in6_addr));
1094 
1095   switch(this->h.type){
1096     case ICMPv6_GRPMEMBQUERY:
1097     case ICMPv6_GRPMEMBREP:
1098     case ICMPv6_GRPMEMBRED:
1099        memcpy(addr.s6_addr, this->h_mld->mcast_address, 16);
1100     break;
1101   }
1102   return addr;
1103 } /* End of setMulticastAddress() */
1104 
1105 
1106 /******************************************************************************/
1107 /* MISCELLANEOUS STUFF                                                        */
1108 /******************************************************************************/
1109 
1110 /** Returns the standard ICMPv6 header length for the supplied ICMP message type.
1111   * @warning Return value corresponds strictly to the ICMP header, this is,
1112   * the minimum length of the ICMP header, variable length payload is never
1113   * included. For example, an ICMPv6 Redirect has a fixed header of 40
1114   * bytes but then the packet may contain ICMPv6 options. We only return 40
1115   * because we don't know in advance the total number of bytes for the message.
1116   * Same applies to the rest of types. */
getHeaderLengthFromType(u8 type) const1117 int ICMPv6Header::getHeaderLengthFromType(u8 type) const {
1118 
1119   switch( type ){
1120     case ICMPv6_UNREACH:
1121         return ICMPv6_UNREACH_LEN;
1122     break;
1123     case ICMPv6_PKTTOOBIG:
1124         return ICMPv6_PKTTOOBIG_LEN;
1125     break;
1126 
1127     case ICMPv6_TIMXCEED:
1128         return ICMPv6_TIMXCEED_LEN;
1129     break;
1130 
1131     case ICMPv6_PARAMPROB:
1132         return ICMPv6_PARAMPROB_LEN;
1133     break;
1134 
1135     case ICMPv6_ECHO:
1136         return ICMPv6_ECHO_LEN;
1137     break;
1138 
1139     case ICMPv6_ECHOREPLY:
1140         return ICMPv6_ECHOREPLY_LEN;
1141     break;
1142 
1143     case ICMPv6_ROUTERSOLICIT:
1144         return ICMPv6_ROUTERSOLICIT_LEN;
1145     break;
1146 
1147     case ICMPv6_ROUTERADVERT:
1148         return ICMPv6_ROUTERADVERT_LEN;
1149     break;
1150 
1151     case ICMPv6_NGHBRSOLICIT:
1152         return ICMPv6_NGHBRSOLICIT_LEN;
1153     break;
1154 
1155     case ICMPv6_NGHBRADVERT:
1156         return ICMPv6_NGHBRADVERT_LEN;
1157     break;
1158 
1159     case ICMPv6_REDIRECT:
1160         return ICMPv6_REDIRECT_LEN;
1161     break;
1162 
1163     case ICMPv6_RTRRENUM:
1164         return ICMPv6_RTRRENUM_LEN;
1165     break;
1166 
1167     case ICMPv6_NODEINFOQUERY:
1168     case ICMPv6_NODEINFORESP:
1169         return ICMPv6_NODEINFO_LEN;
1170     break;
1171 
1172     case ICMPv6_GRPMEMBQUERY:
1173     case ICMPv6_GRPMEMBREP:
1174     case ICMPv6_GRPMEMBRED:
1175         return ICMPv6_MLD_LEN;
1176     break;
1177 
1178     /* Packets with non RFC-Compliant types will be represented as an 8-byte
1179      * ICMPv6 header, just like the types that don't include additional info */
1180     default:
1181         return ICMPv6_MIN_HEADER_LEN;
1182     break;
1183   }
1184 } /* End of getHeaderLengthFromType() */
1185 
1186 
1187 /* Returns true if the packet is an ICMPv6 error message. */
isError() const1188 bool ICMPv6Header::isError() const {
1189   switch( this->getType() ){
1190     case ICMPv6_UNREACH:
1191     case ICMPv6_PKTTOOBIG:
1192     case ICMPv6_TIMXCEED:
1193     case ICMPv6_PARAMPROB:
1194       return true;
1195     break;
1196 
1197     default:
1198       return false;
1199     break;
1200   }
1201 } /* End of isError() */
1202 
1203 
type2string(int type,int code) const1204 const char *ICMPv6Header::type2string(int type, int code) const {
1205   switch(type) {
1206 
1207     case ICMPv6_UNREACH:
1208       switch(code) {
1209         case ICMPv6_UNREACH_NO_ROUTE: return "Network unreachable"; break;
1210         case ICMPv6_UNREACH_PROHIBITED: return "Comm prohibited"; break;
1211         case ICMPv6_UNREACH_BEYOND_SCOPE: return "Beyond scope"; break;
1212         case ICMPv6_UNREACH_ADDR_UNREACH: return "Address unreachable"; break;
1213         case ICMPv6_UNREACH_PORT_UNREACH: return "Port unreachable"; break;
1214         case ICMPv6_UNREACH_SRC_ADDR_FAILED: return "Source address failed"; break;
1215         case ICMPv6_UNREACH_REJECT_ROUTE: return "Reject route"; break;
1216         default: return "Destination unreachable (unknown code)"; break;
1217       }
1218     break;
1219 
1220     case ICMPv6_PKTTOOBIG:
1221       return "Packet too big";
1222     break;
1223 
1224     case ICMPv6_TIMXCEED:
1225       switch(code){
1226         case ICMPv6_TIMXCEED_HOP_EXCEEDED: return "HopLimit=0 in transit"; break;
1227         case ICMPv6_TIMXCEED_REASS_EXCEEDED: return "Reassembly time exceeded"; break;
1228         default: return "Time exceeded (unknown code)"; break;
1229       }
1230     break;
1231 
1232     case ICMPv6_PARAMPROB:
1233       switch(code){
1234         case ICMPv6_PARAMPROB_FIELD: return "Parameter problem (bad field)"; break;
1235         case ICMPv6_PARAMPROB_NEXT_HDR: return "Parameter problem (next header unknown)"; break;
1236         case ICMPv6_PARAMPROB_OPTION: return "Parameter problem (bad option)"; break;
1237         default: return "Parameter problem (unknown code)"; break;
1238       }
1239     break;
1240 
1241     case ICMPv6_ECHO:
1242       return "Echo request";
1243     break;
1244     case ICMPv6_ECHOREPLY:
1245       return "Echo reply";
1246     break;
1247     case ICMPv6_GRPMEMBQUERY:
1248       return "Group membership query";
1249     break;
1250     case ICMPv6_GRPMEMBREP:
1251       return "Group membership report";
1252     break;
1253     case ICMPv6_GRPMEMBRED:
1254       return "Group membership reduction";
1255     break;
1256     case ICMPv6_ROUTERSOLICIT:
1257       return "Router sol";
1258     break;
1259     case ICMPv6_ROUTERADVERT:
1260       return "Router advert";
1261     break;
1262     case ICMPv6_NGHBRSOLICIT:
1263       return "Neighbor sol";
1264     break;
1265     case ICMPv6_NGHBRADVERT:
1266       return "Neighbor advert";
1267     break;
1268     case ICMPv6_REDIRECT:
1269       return "Redirect";
1270     break;
1271     case ICMPv6_RTRRENUM:
1272       switch(code){
1273         case ICMPv6_RTRRENUM_COMMAND: return "Renumbering command"; break;
1274         case ICMPv6_RTRRENUM_RESULT: return "Renumbering result"; break;
1275         case ICMPv6_RTRRENUM_SEQ_RESET: return "Renumbering reset"; break;
1276         default: return "Router Renumbering (unknown code)"; break;
1277       }
1278     break;
1279     case ICMPv6_NODEINFOQUERY:
1280       switch(code){
1281         case ICMPv6_NODEINFOQUERY_IPv6ADDR: return "Node info query (IPv6 addr)"; break;
1282         case ICMPv6_NODEINFOQUERY_NAME: return "Node info query (name)"; break;
1283         case ICMPv6_NODEINFOQUERY_IPv4ADDR: return "Node info query (IPv4 addr)"; break;
1284         default: return "Node info query (unknown code)"; break;
1285       }
1286     break;
1287 
1288     case ICMPv6_NODEINFORESP:
1289       switch(code){
1290         case ICMPv6_NODEINFORESP_SUCCESS: return "Node info reply (success)"; break;
1291         case ICMPv6_NODEINFORESP_REFUSED: return "Node info reply (refused)"; break;
1292         case ICMPv6_NODEINFORESP_UNKNOWN: return "Node info reply (qtype unknown)"; break;
1293         default: return "Node info reply (unknown code)"; break;
1294       }
1295     break;
1296 
1297     case ICMPv6_INVNGHBRSOLICIT:
1298       return "Inverse neighbor sol";
1299     break;
1300 
1301     case ICMPv6_INVNGHBRADVERT:
1302       return "Inverse neighbor advert";
1303     break;
1304 
1305     case ICMPv6_MLDV2:
1306       return "MLDv2 report";
1307     break;
1308 
1309     case ICMPv6_AGENTDISCOVREQ:
1310       return "Home agent request";
1311     break;
1312 
1313     case ICMPv6_AGENTDISCOVREPLY:
1314       return "Home agent reply";
1315     break;
1316 
1317     case ICMPv6_MOBPREFIXSOLICIT:
1318       return "Prefix sol";
1319     break;
1320 
1321     case ICMPv6_MOBPREFIXADVERT:
1322       return "Prefix advert";
1323     break;
1324 
1325     case ICMPv6_CERTPATHSOLICIT:
1326       return "Cert path sol";
1327     break;
1328 
1329     case ICMPv6_CERTPATHADVERT:
1330       return "Cert path advert";
1331     break;
1332 
1333     case ICMPv6_EXPMOBILITY:
1334       return "Experimental mobility";
1335     break;
1336 
1337     case ICMPv6_MRDADVERT:
1338       return "Multicast router advert";
1339     break;
1340 
1341     case ICMPv6_MRDSOLICIT:
1342       return "Multicast router sol";
1343     break;
1344 
1345     case ICMPv6_MRDTERMINATE:
1346       return "Multicast router term";
1347     break;
1348 
1349     case ICMPv6_FMIPV6:
1350       return "FMIPv6";
1351     break;
1352 
1353     default:
1354       return "Unknown ICMPv6 type";
1355     break;
1356   } /* End of ICMP Type switch */
1357   return "Unknown ICMPv6 type";
1358 } /* End of type2string() */
1359 
1360 
1361 
1362