A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ip6addr.c Source File

ip6addr.c

00001 #include <stdbool.h>
00002 #include <string.h>
00003 
00004 #include     "log.h"
00005 #include "ip6addr.h"
00006 #include    "http.h"
00007 #include  "action.h"
00008 #include     "ndp.h"
00009 #include "ntpclient.h"
00010 #include   "slaac.h"
00011 #include    "tftp.h"
00012 
00013 void Ip6AddrClear(char* ip)
00014 {
00015     ip[ 0] = 0; //Just set the first byte to zero
00016 }
00017 bool Ip6AddrIsEmpty(const char* ip)
00018 {
00019     return !ip[0]; //Check for the first byte being non zero
00020 }
00021 static void addHexNibble(bool* pAdded, int number, int index, char** pp)
00022 {
00023     int nibble = number;
00024     if (index) nibble >>= 4;
00025     nibble &= 0xF;
00026     
00027     if (nibble || *pAdded)
00028     {
00029         **pp = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
00030         *pp += 1;
00031         *pAdded = true;
00032     }
00033 }
00034 int Ip6AddrToString(const char* pIp, int size, char* pText)
00035 {
00036     const char* pIpE = pIp + 16;
00037     char* p = pText;
00038     while (true)
00039     {
00040         bool added = false;
00041         if (*pIp || *(pIp + 1))
00042         {
00043             if (p > pText + size - 2) break;  addHexNibble(&added, *(pIp + 0), 1, &p);
00044             if (p > pText + size - 2) break;  addHexNibble(&added, *(pIp + 0), 0, &p);
00045             if (p > pText + size - 2) break;  addHexNibble(&added, *(pIp + 1), 1, &p);
00046             if (p > pText + size - 2) break;  addHexNibble(&added, *(pIp + 1), 0, &p);
00047         }
00048         
00049         pIp += 2;
00050         if (pIp >= pIpE) break;
00051         
00052         if (p > pText + size - 2) break; *p++ = ':';
00053     }
00054     *p = 0;
00055     return p - pText;
00056 }
00057 void Ip6AddrParse(const char *pText, char *address) //Contains an empty address if invalid
00058 {
00059     int field = 0;
00060     int word = 0;
00061     while(true)
00062     {
00063         switch (*pText)
00064         {
00065             case ':':
00066                 address[field] = (word >> 8) & 0xFF;
00067                 field++;
00068                 if (field > 15) { address[0] = 0; return; }
00069                 address[field] = word & 0xFF;
00070                 field++;
00071                 if (field > 15) { address[0] = 0; return; }
00072                 word = 0;
00073                 break;
00074             case '0': word <<= 4; word |= 0; break;
00075             case '1': word <<= 4; word |= 1; break;
00076             case '2': word <<= 4; word |= 2; break;
00077             case '3': word <<= 4; word |= 3; break;
00078             case '4': word <<= 4; word |= 4; break;
00079             case '5': word <<= 4; word |= 5; break;
00080             case '6': word <<= 4; word |= 6; break;
00081             case '7': word <<= 4; word |= 7; break;
00082             case '8': word <<= 4; word |= 8; break;
00083             case '9': word <<= 4; word |= 9; break;
00084             case 'a':
00085             case 'A': word <<= 4; word |= 10; break;
00086             case 'b':
00087             case 'B': word <<= 4; word |= 11; break;
00088             case 'c':
00089             case 'C': word <<= 4; word |= 12; break;
00090             case 'd':
00091             case 'D': word <<= 4; word |= 13; break;
00092             case 'e':
00093             case 'E': word <<= 4; word |= 14; break;
00094             case 'f':
00095             case 'F': word <<= 4; word |= 15; break;
00096             case 0:
00097                 address[field] = (word >> 8) & 0xFF;
00098                 field++;
00099                 if (field != 15) { address[0] = 0; return; }
00100                 address[field] = word & 0xFF;
00101                 return;
00102             default: 
00103                 address[0] = 0;
00104                 return;
00105         }
00106         pText++;
00107     }
00108 }
00109 static void logHexNibble(bool* pAdded, int number, int index)
00110 {
00111     int nibble = number;
00112     if (index) nibble >>= 4;
00113     nibble &= 0xF;
00114     
00115     if (nibble || *pAdded)
00116     {
00117         LogChar(nibble < 10 ? nibble + '0' : nibble - 10 + 'a');
00118         *pAdded = true;
00119     }
00120 }
00121 int Ip6AddrLog(const char* pIp)
00122 {
00123     int count = 0;
00124     const char* pIpE = pIp + 16;
00125     while (true)
00126     {
00127         bool added = false;
00128         if (*pIp || *(pIp + 1))
00129         {
00130             logHexNibble(&added, *(pIp + 0), 1); if (added) count++;
00131             logHexNibble(&added, *(pIp + 0), 0); if (added) count++;
00132             logHexNibble(&added, *(pIp + 1), 1); if (added) count++;
00133             logHexNibble(&added, *(pIp + 1), 0); if (added) count++;
00134         }
00135         
00136         pIp += 2;
00137         if (pIp >= pIpE) break;
00138         
00139         LogChar(':'); count++;
00140     }
00141     return count;
00142 }
00143 static void httpHexNibble(bool* pAdded, int number, int index)
00144 {
00145     int nibble = number;
00146     if (index) nibble >>= 4;
00147     nibble &= 0xF;
00148     
00149     if (nibble || *pAdded)
00150     {
00151         HttpAddChar(nibble < 10 ? nibble + '0' : nibble - 10 + 'a');
00152         *pAdded = true;
00153     }
00154 }
00155 int Ip6AddrHttp(const char* pIp)
00156 {
00157     int count = 0;
00158     const char* pIpE = pIp + 16;
00159     while (true)
00160     {
00161         bool added = false;
00162         if (*pIp || *(pIp + 1))
00163         {
00164             httpHexNibble(&added, *(pIp + 0), 1); if (added) count++;
00165             httpHexNibble(&added, *(pIp + 0), 0); if (added) count++;
00166             httpHexNibble(&added, *(pIp + 1), 1); if (added) count++;
00167             httpHexNibble(&added, *(pIp + 1), 0); if (added) count++;
00168         }
00169         
00170         pIp += 2;
00171         if (pIp >= pIpE) break;
00172         
00173         HttpAddChar(':'); count++;
00174     }
00175     return count;
00176 }
00177 bool Ip6AddrIsSame(const char* ipA, const char* ipB)
00178 {
00179     return !memcmp(ipA, ipB, 16); //Though about optimising by doing a reverse loop but unlikely to be faster than an optimised assembly coded library function
00180 }
00181 void Ip6AddrCopy(char* ipTo, const char* ipFrom)
00182 {
00183     memcpy(ipTo, ipFrom, 16);
00184 }
00185 
00186 bool Ip6AddrIsLinkLocal(const char* p)
00187 {
00188     if (p[0] != 0xFE) return false;
00189     if (p[1] != 0x80) return false;
00190     return true;
00191 }
00192 bool Ip6AddrIsUniqueLocal(const char* p)
00193 {
00194     if (p[0] != 0xFD) return false;
00195     if (p[1] != 0x00) return false;
00196     return true;
00197 }
00198 bool Ip6AddrIsGlobal(const char* p)
00199 {
00200     //[RFC 4291] designates 2000::/3 to be global unicast address space that the Internet Assigned Numbers Authority (IANA) may allocate to the RIRs.
00201     //The top byte AND 0b11100000 (0xE0)must be 0x20
00202     return (p[0] & 0xE0) == 0x20;
00203 }
00204 bool Ip6AddrIsExternal(const char* p)
00205 {
00206     //Logic is address must be global and not have the global prefix
00207     if (!Ip6AddrIsGlobal(p)) return false;
00208     if (!NdpGlobalPrefixLength) return false;
00209     if (memcmp(NdpGlobalPrefix, p, NdpGlobalPrefixLength) != 0) return false; //Only 0 if the same
00210     return true;
00211     
00212 }
00213 bool Ip6AddrIsSolicited(const char* p)
00214 {
00215     if (*p++ != 0xff) return false;
00216     if (*p++ != 0x02) return false;
00217     
00218     if (*p++ != 0x00) return false;
00219     if (*p++ != 0x00) return false;
00220     
00221     if (*p++ != 0x00) return false;
00222     if (*p++ != 0x00) return false;
00223     
00224     if (*p++ != 0x00) return false;
00225     if (*p++ != 0x00) return false;
00226     
00227     if (*p++ != 0x00) return false;
00228     if (*p++ != 0x00) return false;
00229     
00230     if (*p++ != 0x00) return false;
00231     if (*p++ != 0x01) return false;
00232     
00233     if (*p++ != 0xff) return false;
00234     
00235     return true;
00236 }
00237 bool Ip6AddrIsMulticast(const char *p)
00238 {
00239     return *p == 0xFF;
00240 }
00241 bool Ip6AddrIsSameGroup(const char* pA, const char* pB)
00242 {
00243     pA += 13;
00244     pB += 13;
00245     if (*pA++ != *pB++) return false;
00246     if (*pA++ != *pB++) return false;
00247     return *pA == *pB;
00248 }
00249 
00250 const char Ip6AddrAllNodes  [] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
00251 const char Ip6AddrAllRouters[] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
00252 const char Ip6AddrMdns      [] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb};
00253 const char Ip6AddrLlmnr     [] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03};
00254 const char Ip6AddrNtp       [] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01};
00255 
00256 void Ip6AddrFromDest(int dest, char* pDstIp)
00257 {
00258     switch (dest)
00259     {
00260         case   UNICAST:        /*No change*/                                    break;
00261         case   UNICAST_DNS:    Ip6AddrCopy(pDstIp, NdpDnsServer           ); break;
00262         case   UNICAST_NTP:    Ip6AddrCopy(pDstIp, NtpClientQueryServerIp6); break;
00263         case   UNICAST_TFTP:   Ip6AddrCopy(pDstIp, TftpServerIp6          ); break;
00264         case MULTICAST_NODE:   Ip6AddrCopy(pDstIp, Ip6AddrAllNodes     ); break;
00265         case MULTICAST_ROUTER: Ip6AddrCopy(pDstIp, Ip6AddrAllRouters   ); break;
00266         case MULTICAST_MDNS:   Ip6AddrCopy(pDstIp, Ip6AddrMdns         ); break;
00267         case MULTICAST_LLMNR:  Ip6AddrCopy(pDstIp, Ip6AddrLlmnr        ); break;
00268         case MULTICAST_NTP:    Ip6AddrCopy(pDstIp, Ip6AddrNtp          ); break;
00269         default:
00270             LogTimeF("Ip6AddressFromDest unknown destination %d\r\n", dest);
00271             break;           
00272     }
00273 }