1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2018-05-18 ChenYong First version 9 */ 10 11 #include <sal_ipaddr.h> 12 #include <rtthread.h> 13 14 /* Here for now until needed in other places in lwIP */ 15 #ifndef isprint 16 #define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) 17 #define isprint(c) in_range(c, 0x20, 0x7f) 18 #define isdigit(c) in_range(c, '0', '9') 19 #define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) 20 #define islower(c) in_range(c, 'a', 'z') 21 #define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') 22 #endif 23 24 25 /** 26 * Check whether "cp" is a valid ascii representation 27 * of an Internet address and convert to a binary address. 28 * Returns 1 if the address is valid, 0 if not. 29 * This replaces inet_addr, the return value from which 30 * cannot distinguish between failure and a local broadcast address. 31 * 32 * @param cp IP address in ascii representation (e.g. "127.0.0.1") 33 * @param addr pointer to which to save the ip address in network order 34 * @return 1 if cp could be converted to addr, 0 on failure 35 */ 36 int sal_ip4addr_aton(const char *cp, ip4_addr_t *addr) 37 { 38 u32_t val; 39 u8_t base; 40 char c; 41 u32_t parts[4]; 42 u32_t *pp = parts; 43 44 c = *cp; 45 for (;;) 46 { 47 /* 48 * Collect number up to ``.''. 49 * Values are specified as for C: 50 * 0x=hex, 0=octal, 1-9=decimal. 51 */ 52 if (!isdigit(c)) 53 { 54 return 0; 55 } 56 val = 0; 57 base = 10; 58 if (c == '0') 59 { 60 c = *++cp; 61 if (c == 'x' || c == 'X') 62 { 63 base = 16; 64 c = *++cp; 65 } 66 else 67 { 68 base = 8; 69 } 70 } 71 for (;;) 72 { 73 if (isdigit(c)) 74 { 75 val = (val * base) + (u32_t) (c - '0'); 76 c = *++cp; 77 } 78 else if (base == 16 && isxdigit(c)) 79 { 80 val = (val << 4) | (u32_t) (c + 10 - (islower(c) ? 'a' : 'A')); 81 c = *++cp; 82 } 83 else 84 { 85 break; 86 } 87 } 88 if (c == '.') 89 { 90 /* 91 * Internet format: 92 * a.b.c.d 93 * a.b.c (with c treated as 16 bits) 94 * a.b (with b treated as 24 bits) 95 */ 96 if (pp >= parts + 3) 97 { 98 return 0; 99 } 100 *pp++ = val; 101 c = *++cp; 102 } 103 else 104 { 105 break; 106 } 107 } 108 /* 109 * Check for trailing characters. 110 */ 111 if (c != '\0' && !isspace(c)) 112 { 113 return 0; 114 } 115 /* 116 * Concoct the address according to 117 * the number of parts specified. 118 */ 119 switch (pp - parts + 1) 120 { 121 122 case 0: 123 return 0; /* initial nondigit */ 124 125 case 1: /* a -- 32 bits */ 126 break; 127 128 case 2: /* a.b -- 8.24 bits */ 129 if (val > 0xffffffUL) 130 { 131 return 0; 132 } 133 if (parts[0] > 0xff) 134 { 135 return 0; 136 } 137 val |= parts[0] << 24; 138 break; 139 140 case 3: /* a.b.c -- 8.8.16 bits */ 141 if (val > 0xffff) 142 { 143 return 0; 144 } 145 if ((parts[0] > 0xff) || (parts[1] > 0xff)) 146 { 147 return 0; 148 } 149 val |= (parts[0] << 24) | (parts[1] << 16); 150 break; 151 152 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 153 if (val > 0xff) 154 { 155 return 0; 156 } 157 if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) 158 { 159 return 0; 160 } 161 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 162 break; 163 default: 164 RT_ASSERT(0); 165 break; 166 } 167 if (addr) 168 { 169 ip4_addr_set_u32(addr, htonl(val)); 170 } 171 return 1; 172 } 173 174 /** 175 * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. 176 * 177 * @param addr ip address in network order to convert 178 * @param buf target buffer where the string is stored 179 * @param buflen length of buf 180 * @return either pointer to buf which now holds the ASCII 181 * representation of addr or NULL if buf was too small 182 */ 183 char *sal_ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen) 184 { 185 u32_t s_addr; 186 char inv[3]; 187 char *rp; 188 u8_t *ap; 189 u8_t rem; 190 u8_t n; 191 u8_t i; 192 int len = 0; 193 194 s_addr = ip4_addr_get_u32(addr); 195 196 rp = buf; 197 ap = (u8_t *) &s_addr; 198 for (n = 0; n < 4; n++) 199 { 200 i = 0; 201 do 202 { 203 rem = *ap % (u8_t) 10; 204 *ap /= (u8_t) 10; 205 inv[i++] = (char) ('0' + rem); 206 } while (*ap); 207 while (i--) 208 { 209 if (len++ >= buflen) 210 { 211 return NULL; 212 } 213 *rp++ = inv[i]; 214 } 215 if (len++ >= buflen) 216 { 217 return NULL; 218 } 219 *rp++ = '.'; 220 ap++; 221 } 222 *--rp = 0; 223 return buf; 224 } 225 226 227 /** 228 * Convert numeric IP address into decimal dotted ASCII representation. 229 * returns ptr to static buffer; not reentrant! 230 * 231 * @param addr ip address in network order to convert 232 * @return pointer to a global static (!) buffer that holds the ASCII 233 * representation of addr 234 */ 235 char *sal_ip4addr_ntoa(const ip4_addr_t *addr) 236 { 237 static char str[IP4ADDR_STRLEN_MAX]; 238 return sal_ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX); 239 } 240 241 242 /** 243 * Ascii internet address interpretation routine. 244 * The value returned is in network order. 245 * 246 * @param cp IP address in ascii representation (e.g. "127.0.0.1") 247 * @return ip address in network order 248 */ 249 in_addr_t sal_ipaddr_addr(const char *cp) 250 { 251 ip4_addr_t val; 252 253 if (sal_ip4addr_aton(cp, &val)) { 254 return ip4_addr_get_u32(&val); 255 } 256 return (IPADDR_NONE); 257 } 258