Hermes/Dyforge is a program written in c++ allows you to inject a dll that can analyze all processes in a program, can be used for mod and reverse engeneering
| 1 | // Copyright (c) 2004-2013 Sergey Lyubka |
| 2 | // Copyright (c) 2013-2025 Cesanta Software Limited |
| 3 | // All rights reserved |
| 4 | // |
| 5 | // This software is dual-licensed: you can redistribute it and/or modify |
| 6 | // it under the terms of the GNU General Public License version 2 as |
| 7 | // published by the Free Software Foundation. For the terms of this |
| 8 | // license, see http://www.gnu.org/licenses/ |
| 9 | // |
| 10 | // You are free to use this software under the terms of the GNU General |
| 11 | // Public License, but WITHOUT ANY WARRANTY; without even the implied |
| 12 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| 13 | // See the GNU General Public License for more details. |
| 14 | // |
| 15 | // Alternatively, you can license this software under a commercial |
| 16 | // license, as set out in https://www.mongoose.ws/licensing/ |
| 17 | // |
| 18 | // SPDX-License-Identifier: GPL-2.0-only or commercial |
| 19 | |
| 20 | #include "mongoose.h" |
| 21 | |
| 22 | #ifdef MG_ENABLE_LINES |
| 23 | #line 1 "src/base64.c" |
| 24 | #endif |
| 25 | |
| 26 | |
| 27 | static int mg_base64_encode_single(int c) { |
| 28 | if (c < 26) { |
| 29 | return c + 'A'; |
| 30 | } else if (c < 52) { |
| 31 | return c - 26 + 'a'; |
| 32 | } else if (c < 62) { |
| 33 | return c - 52 + '0'; |
| 34 | } else { |
| 35 | return c == 62 ? '+' : '/'; |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | static int mg_base64_decode_single(int c) { |
| 40 | if (c >= 'A' && c <= 'Z') { |
| 41 | return c - 'A'; |
| 42 | } else if (c >= 'a' && c <= 'z') { |
| 43 | return c + 26 - 'a'; |
| 44 | } else if (c >= '0' && c <= '9') { |
| 45 | return c + 52 - '0'; |
| 46 | } else if (c == '+') { |
| 47 | return 62; |
| 48 | } else if (c == '/') { |
| 49 | return 63; |
| 50 | } else if (c == '=') { |
| 51 | return 64; |
| 52 | } else { |
| 53 | return -1; |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | size_t mg_base64_update(unsigned char ch, char *to, size_t n) { |
| 58 | unsigned long rem = (n & 3) % 3; |
| 59 | if (rem == 0) { |
| 60 | to[n] = (char) mg_base64_encode_single(ch >> 2); |
| 61 | to[++n] = (char) ((ch & 3) << 4); |
| 62 | } else if (rem == 1) { |
| 63 | to[n] = (char) mg_base64_encode_single(to[n] | (ch >> 4)); |
| 64 | to[++n] = (char) ((ch & 15) << 2); |
| 65 | } else { |
| 66 | to[n] = (char) mg_base64_encode_single(to[n] | (ch >> 6)); |
| 67 | to[++n] = (char) mg_base64_encode_single(ch & 63); |
| 68 | n++; |
| 69 | } |
| 70 | return n; |
| 71 | } |
| 72 | |
| 73 | size_t mg_base64_final(char *to, size_t n) { |
| 74 | size_t saved = n; |
| 75 | // printf("---[%.*s]\n", n, to); |
| 76 | if (n & 3) n = mg_base64_update(0, to, n); |
| 77 | if ((saved & 3) == 2) n--; |
| 78 | // printf(" %d[%.*s]\n", n, n, to); |
| 79 | while (n & 3) to[n++] = '='; |
| 80 | to[n] = '\0'; |
| 81 | return n; |
| 82 | } |
| 83 | |
| 84 | size_t mg_base64_encode(const unsigned char *p, size_t n, char *to, size_t dl) { |
| 85 | size_t i, len = 0; |
| 86 | if (dl > 0) to[0] = '\0'; |
| 87 | if (dl < ((n / 3) + (n % 3 ? 1 : 0)) * 4 + 1) return 0; |
| 88 | for (i = 0; i < n; i++) len = mg_base64_update(p[i], to, len); |
| 89 | len = mg_base64_final(to, len); |
| 90 | return len; |
| 91 | } |
| 92 | |
| 93 | size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t dl) { |
| 94 | const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL |
| 95 | size_t len = 0; |
| 96 | if (dl < n / 4 * 3 + 1) goto fail; |
| 97 | while (src != NULL && src + 3 < end) { |
| 98 | int a = mg_base64_decode_single(src[0]), |
| 99 | b = mg_base64_decode_single(src[1]), |
| 100 | c = mg_base64_decode_single(src[2]), |
| 101 | d = mg_base64_decode_single(src[3]); |
| 102 | if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) { |
| 103 | goto fail; |
| 104 | } |
| 105 | dst[len++] = (char) ((a << 2) | (b >> 4)); |
| 106 | if (src[2] != '=') { |
| 107 | dst[len++] = (char) ((b << 4) | (c >> 2)); |
| 108 | if (src[3] != '=') dst[len++] = (char) ((c << 6) | d); |
| 109 | } |
| 110 | src += 4; |
| 111 | } |
| 112 | dst[len] = '\0'; |
| 113 | return len; |
| 114 | fail: |
| 115 | if (dl > 0) dst[0] = '\0'; |
| 116 | return 0; |
| 117 | } |
| 118 | |
| 119 | #ifdef MG_ENABLE_LINES |
| 120 | #line 1 "src/dns.c" |
| 121 | #endif |
| 122 | |
| 123 | |
| 124 | |
| 125 | |
| 126 | |
| 127 | |
| 128 | |
| 129 | |
| 130 | struct dns_data { |
| 131 | struct dns_data *next; |
| 132 | struct mg_connection *c; |
| 133 | uint64_t expire; |
| 134 | uint16_t txnid; |
| 135 | }; |
| 136 | |
| 137 | static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int, |
| 138 | struct mg_dns *, bool); |
| 139 | |
| 140 | static void mg_dns_free(struct dns_data **head, struct dns_data *d) { |
| 141 | LIST_DELETE(struct dns_data, head, d); |
| 142 | free(d); |
| 143 | } |
| 144 | |
| 145 | void mg_resolve_cancel(struct mg_connection *c) { |
| 146 | struct dns_data *tmp, *d; |
| 147 | struct dns_data **head = (struct dns_data **) &c->mgr->active_dns_requests; |
| 148 | for (d = *head; d != NULL; d = tmp) { |
| 149 | tmp = d->next; |
| 150 | if (d->c == c) mg_dns_free(head, d); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs, |
| 155 | char *to, size_t tolen, size_t j, |
| 156 | int depth) { |
| 157 | size_t i = 0; |
| 158 | if (tolen > 0 && depth == 0) to[0] = '\0'; |
| 159 | if (depth > 5) return 0; |
| 160 | // MG_INFO(("ofs %lx %x %x", (unsigned long) ofs, s[ofs], s[ofs + 1])); |
| 161 | while (ofs + i + 1 < len) { |
| 162 | size_t n = s[ofs + i]; |
| 163 | if (n == 0) { |
| 164 | i++; |
| 165 | break; |
| 166 | } |
| 167 | if (n & 0xc0) { |
| 168 | size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len |
| 169 | // MG_INFO(("PTR %lx", (unsigned long) ptr)); |
| 170 | if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 && |
| 171 | mg_dns_parse_name_depth(s, len, ptr, to, tolen, j, depth + 1) == 0) |
| 172 | return 0; |
| 173 | i += 2; |
| 174 | break; |
| 175 | } |
| 176 | if (ofs + i + n + 1 >= len) return 0; |
| 177 | if (j > 0) { |
| 178 | if (j < tolen) to[j] = '.'; |
| 179 | j++; |
| 180 | } |
| 181 | if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n); |
| 182 | j += n; |
| 183 | i += n + 1; |
| 184 | if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk |
| 185 | // MG_INFO(("--> [%s]", to)); |
| 186 | } |
| 187 | if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term |
| 188 | return i; |
| 189 | } |
| 190 | |
| 191 | static size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs, |
| 192 | char *dst, size_t dstlen) { |
| 193 | return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0, 0); |
| 194 | } |
| 195 | |
| 196 | size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, |
| 197 | bool is_question, struct mg_dns_rr *rr) { |
| 198 | const uint8_t *s = buf + ofs, *e = &buf[len]; |
| 199 | |
| 200 | memset(rr, 0, sizeof(*rr)); |
| 201 | if (len < sizeof(struct mg_dns_header)) return 0; // Too small |
| 202 | if (len > 512) return 0; // Too large, we don't expect that |
| 203 | if (s >= e) return 0; // Overflow |
| 204 | |
| 205 | if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0) |
| 206 | return 0; |
| 207 | s += rr->nlen + 4; |
| 208 | if (s > e) return 0; |
| 209 | rr->atype = (uint16_t) (((uint16_t) s[-4] << 8) | s[-3]); |
| 210 | rr->aclass = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]); |
| 211 | if (is_question) return (size_t) (rr->nlen + 4); |
| 212 | |
| 213 | s += 6; |
| 214 | if (s > e) return 0; |
| 215 | rr->alen = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]); |
| 216 | if (s + rr->alen > e) return 0; |
| 217 | return (size_t) (rr->nlen + rr->alen + 10); |
| 218 | } |
| 219 | |
| 220 | bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) { |
| 221 | const struct mg_dns_header *h = (struct mg_dns_header *) buf; |
| 222 | struct mg_dns_rr rr; |
| 223 | size_t i, n, num_answers, ofs = sizeof(*h); |
| 224 | bool is_response; |
| 225 | memset(dm, 0, sizeof(*dm)); |
| 226 | |
| 227 | if (len < sizeof(*h)) return 0; // Too small, headers dont fit |
| 228 | if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity |
| 229 | num_answers = mg_ntohs(h->num_answers); |
| 230 | if (num_answers > 10) { |
| 231 | MG_DEBUG(("Got %u answers, ignoring beyond 10th one", num_answers)); |
| 232 | num_answers = 10; // Sanity cap |
| 233 | } |
| 234 | dm->txnid = mg_ntohs(h->txnid); |
| 235 | is_response = mg_ntohs(h->flags) & 0x8000; |
| 236 | |
| 237 | for (i = 0; i < mg_ntohs(h->num_questions); i++) { |
| 238 | if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false; |
| 239 | // MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass)); |
| 240 | mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name)); |
| 241 | ofs += n; |
| 242 | } |
| 243 | |
| 244 | if (!is_response) { |
| 245 | // For queries, there is no need to parse the answers. In this way, |
| 246 | // we also ensure the domain name (dm->name) is parsed from |
| 247 | // the question field. |
| 248 | return true; |
| 249 | } |
| 250 | |
| 251 | for (i = 0; i < num_answers; i++) { |
| 252 | if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false; |
| 253 | // MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass, |
| 254 | // dm->name)); |
| 255 | mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name)); |
| 256 | ofs += n; |
| 257 | |
| 258 | if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) { |
| 259 | dm->addr.is_ip6 = false; |
| 260 | memcpy(&dm->addr.ip, &buf[ofs - 4], 4); |
| 261 | dm->resolved = true; |
| 262 | break; // Return success |
| 263 | } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) { |
| 264 | dm->addr.is_ip6 = true; |
| 265 | memcpy(&dm->addr.ip, &buf[ofs - 16], 16); |
| 266 | dm->resolved = true; |
| 267 | break; // Return success |
| 268 | } |
| 269 | } |
| 270 | return true; |
| 271 | } |
| 272 | |
| 273 | static void dns_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 274 | struct dns_data *d, *tmp; |
| 275 | struct dns_data **head = (struct dns_data **) &c->mgr->active_dns_requests; |
| 276 | if (ev == MG_EV_POLL) { |
| 277 | uint64_t now = *(uint64_t *) ev_data; |
| 278 | for (d = *head; d != NULL; d = tmp) { |
| 279 | tmp = d->next; |
| 280 | // MG_DEBUG ("%lu %lu dns poll", d->expire, now)); |
| 281 | if (now > d->expire) mg_error(d->c, "DNS timeout"); |
| 282 | } |
| 283 | } else if (ev == MG_EV_READ) { |
| 284 | struct mg_dns_message dm; |
| 285 | int resolved = 0; |
| 286 | if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) { |
| 287 | MG_ERROR(("Unexpected DNS response:")); |
| 288 | mg_hexdump(c->recv.buf, c->recv.len); |
| 289 | } else { |
| 290 | // MG_VERBOSE(("%s %d", dm.name, dm.resolved)); |
| 291 | for (d = *head; d != NULL; d = tmp) { |
| 292 | tmp = d->next; |
| 293 | // MG_INFO(("d %p %hu %hu", d, d->txnid, dm.txnid)); |
| 294 | if (dm.txnid != d->txnid) continue; |
| 295 | if (d->c->is_resolving) { |
| 296 | if (dm.resolved) { |
| 297 | dm.addr.port = d->c->rem.port; // Save port |
| 298 | d->c->rem = dm.addr; // Copy resolved address |
| 299 | MG_DEBUG( |
| 300 | ("%lu %s is %M", d->c->id, dm.name, mg_print_ip, &d->c->rem)); |
| 301 | mg_connect_resolved(d->c); |
| 302 | #if MG_ENABLE_IPV6 |
| 303 | } else if (dm.addr.is_ip6 == false && dm.name[0] != '\0' && |
| 304 | c->mgr->use_dns6 == false) { |
| 305 | struct mg_str x = mg_str(dm.name); |
| 306 | mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true); |
| 307 | #endif |
| 308 | } else { |
| 309 | mg_error(d->c, "%s DNS lookup failed", dm.name); |
| 310 | } |
| 311 | } else { |
| 312 | MG_ERROR(("%lu already resolved", d->c->id)); |
| 313 | } |
| 314 | mg_dns_free(head, d); |
| 315 | resolved = 1; |
| 316 | } |
| 317 | } |
| 318 | if (!resolved) MG_ERROR(("stray DNS reply")); |
| 319 | c->recv.len = 0; |
| 320 | } else if (ev == MG_EV_CLOSE) { |
| 321 | for (d = *head; d != NULL; d = tmp) { |
| 322 | tmp = d->next; |
| 323 | mg_error(d->c, "DNS error"); |
| 324 | mg_dns_free(head, d); |
| 325 | } |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name, |
| 330 | uint16_t txnid, bool ipv6) { |
| 331 | struct { |
| 332 | struct mg_dns_header header; |
| 333 | uint8_t data[256]; |
| 334 | } pkt; |
| 335 | size_t i, n; |
| 336 | memset(&pkt, 0, sizeof(pkt)); |
| 337 | pkt.header.txnid = mg_htons(txnid); |
| 338 | pkt.header.flags = mg_htons(0x100); |
| 339 | pkt.header.num_questions = mg_htons(1); |
| 340 | for (i = n = 0; i < sizeof(pkt.data) - 5; i++) { |
| 341 | if (name->buf[i] == '.' || i >= name->len) { |
| 342 | pkt.data[n] = (uint8_t) (i - n); |
| 343 | memcpy(&pkt.data[n + 1], name->buf + n, i - n); |
| 344 | n = i + 1; |
| 345 | } |
| 346 | if (i >= name->len) break; |
| 347 | } |
| 348 | memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query |
| 349 | n += 5; |
| 350 | if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query |
| 351 | // memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query |
| 352 | // n += 6; |
| 353 | return mg_send(c, &pkt, sizeof(pkt.header) + n); |
| 354 | } |
| 355 | |
| 356 | static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, |
| 357 | struct mg_dns *dnsc, bool ipv6) { |
| 358 | struct dns_data *d = NULL; |
| 359 | if (dnsc->url == NULL) { |
| 360 | mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()"); |
| 361 | } else if (dnsc->c == NULL) { |
| 362 | dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL); |
| 363 | if (dnsc->c != NULL) { |
| 364 | dnsc->c->pfn = dns_cb; |
| 365 | // dnsc->c->is_hexdumping = 1; |
| 366 | } |
| 367 | } |
| 368 | if (dnsc->c == NULL) { |
| 369 | mg_error(c, "resolver"); |
| 370 | } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) { |
| 371 | mg_error(c, "resolve OOM"); |
| 372 | } else { |
| 373 | struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; |
| 374 | d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1; |
| 375 | d->next = (struct dns_data *) c->mgr->active_dns_requests; |
| 376 | c->mgr->active_dns_requests = d; |
| 377 | d->expire = mg_millis() + (uint64_t) ms; |
| 378 | d->c = c; |
| 379 | c->is_resolving = 1; |
| 380 | MG_VERBOSE(("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len, |
| 381 | name->buf, dnsc->url, d->txnid)); |
| 382 | if (!mg_dns_send(dnsc->c, name, d->txnid, ipv6)) { |
| 383 | mg_error(dnsc->c, "DNS send"); |
| 384 | } |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | void mg_resolve(struct mg_connection *c, const char *url) { |
| 389 | struct mg_str host = mg_url_host(url); |
| 390 | c->rem.port = mg_htons(mg_url_port(url)); |
| 391 | if (mg_aton(host, &c->rem)) { |
| 392 | // host is an IP address, do not fire name resolution |
| 393 | mg_connect_resolved(c); |
| 394 | } else { |
| 395 | // host is not an IP, send DNS resolution request |
| 396 | struct mg_dns *dns = c->mgr->use_dns6 ? &c->mgr->dns6 : &c->mgr->dns4; |
| 397 | mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6); |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | static const uint8_t mdns_answer[] = { |
| 402 | 0, 1, // 2 bytes - record type, A |
| 403 | 0, 1, // 2 bytes - address class, INET |
| 404 | 0, 0, 0, 120, // 4 bytes - TTL |
| 405 | 0, 4 // 2 bytes - address length |
| 406 | }; |
| 407 | |
| 408 | static void mdns_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 409 | if (ev == MG_EV_READ) { |
| 410 | struct mg_dns_header *qh = (struct mg_dns_header *) c->recv.buf; |
| 411 | if (c->recv.len > 12 && (qh->flags & mg_htons(0xF800)) == 0) { |
| 412 | // flags -> !resp, opcode=0 => query; ignore other opcodes and responses |
| 413 | struct mg_dns_rr rr; // Parse first question, offset 12 is header size |
| 414 | size_t n = mg_dns_parse_rr(c->recv.buf, c->recv.len, 12, true, &rr); |
| 415 | MG_VERBOSE(("mDNS request parsed, result=%d", (int) n)); |
| 416 | if (n > 0) { |
| 417 | // RFC-6762 Appendix C, RFC2181 11: m(n + 1-63), max 255 + 0x0 |
| 418 | // buf and h declared here to ease future expansion to DNS-SD |
| 419 | uint8_t buf[sizeof(struct mg_dns_header) + 256 + sizeof(mdns_answer) + 4]; |
| 420 | struct mg_dns_header *h = (struct mg_dns_header *) buf; |
| 421 | char local_name[63 + 7]; // name label + '.' + local label + '\0' |
| 422 | uint8_t name_len = (uint8_t) strlen((char *)c->fn_data); |
| 423 | struct mg_dns_message dm; |
| 424 | bool unicast = (rr.aclass & MG_BIT(15)) != 0; // QU |
| 425 | // uint16_t q = mg_ntohs(qh->num_questions); |
| 426 | rr.aclass &= (uint16_t) ~MG_BIT(15); // remove "QU" (unicast response) |
| 427 | qh->num_questions = mg_htons(1); // parser sanity |
| 428 | mg_dns_parse(c->recv.buf, c->recv.len, &dm); |
| 429 | if (name_len > (sizeof(local_name) - 7)) // leave room for .local\0 |
| 430 | name_len = sizeof(local_name) - 7; |
| 431 | memcpy(local_name, c->fn_data, name_len); |
| 432 | strcpy(local_name + name_len, ".local"); // ensure proper name.local\0 |
| 433 | if (strcmp(local_name, dm.name) == 0) { |
| 434 | uint8_t *p = &buf[sizeof(*h)]; |
| 435 | memset(h, 0, sizeof(*h)); // clear header |
| 436 | h->txnid = unicast ? qh->txnid : 0; // RFC-6762 18.1 |
| 437 | // RFC-6762 6: 0 questions, 1 Answer, 0 Auth, 0 Additional RRs |
| 438 | h->num_answers = mg_htons(1); // only one answer |
| 439 | h->flags = mg_htons(0x8400); // Authoritative response |
| 440 | *p++ = name_len; // label 1 |
| 441 | memcpy(p, c->fn_data, name_len), p += name_len; |
| 442 | *p++ = 5; // label 2 |
| 443 | memcpy(p, "local", 5), p += 5; |
| 444 | *p++ = 0; // no more labels |
| 445 | memcpy(p, mdns_answer, sizeof(mdns_answer)), p += sizeof(mdns_answer); |
| 446 | #if MG_ENABLE_TCPIP |
| 447 | memcpy(p, &c->mgr->ifp->ip, 4), p += 4; |
| 448 | #else |
| 449 | memcpy(p, c->data, 4), p += 4; |
| 450 | #endif |
| 451 | if (!unicast) memcpy(&c->rem, &c->loc, sizeof(c->rem)); |
| 452 | mg_send(c, buf, (size_t)(p - buf)); // And send it! |
| 453 | MG_DEBUG(("mDNS %c response sent", unicast ? 'U' : 'M')); |
| 454 | } |
| 455 | } |
| 456 | } |
| 457 | mg_iobuf_del(&c->recv, 0, c->recv.len); |
| 458 | } |
| 459 | (void) ev_data; |
| 460 | } |
| 461 | |
| 462 | void mg_multicast_add(struct mg_connection *c, char *ip); |
| 463 | struct mg_connection *mg_mdns_listen(struct mg_mgr *mgr, char *name) { |
| 464 | struct mg_connection *c = |
| 465 | mg_listen(mgr, "udp://224.0.0.251:5353", mdns_cb, name); |
| 466 | if (c != NULL) mg_multicast_add(c, (char *)"224.0.0.251"); |
| 467 | return c; |
| 468 | } |
| 469 | |
| 470 | #ifdef MG_ENABLE_LINES |
| 471 | #line 1 "src/event.c" |
| 472 | #endif |
| 473 | |
| 474 | |
| 475 | |
| 476 | |
| 477 | |
| 478 | |
| 479 | void mg_call(struct mg_connection *c, int ev, void *ev_data) { |
| 480 | #if MG_ENABLE_PROFILE |
| 481 | const char *names[] = { |
| 482 | "EV_ERROR", "EV_OPEN", "EV_POLL", "EV_RESOLVE", |
| 483 | "EV_CONNECT", "EV_ACCEPT", "EV_TLS_HS", "EV_READ", |
| 484 | "EV_WRITE", "EV_CLOSE", "EV_HTTP_MSG", "EV_HTTP_CHUNK", |
| 485 | "EV_WS_OPEN", "EV_WS_MSG", "EV_WS_CTL", "EV_MQTT_CMD", |
| 486 | "EV_MQTT_MSG", "EV_MQTT_OPEN", "EV_SNTP_TIME", "EV_USER"}; |
| 487 | if (ev != MG_EV_POLL && ev < (int) (sizeof(names) / sizeof(names[0]))) { |
| 488 | MG_PROF_ADD(c, names[ev]); |
| 489 | } |
| 490 | #endif |
| 491 | // Fire protocol handler first, user handler second. See #2559 |
| 492 | if (c->pfn != NULL) c->pfn(c, ev, ev_data); |
| 493 | if (c->fn != NULL) c->fn(c, ev, ev_data); |
| 494 | } |
| 495 | |
| 496 | void mg_error(struct mg_connection *c, const char *fmt, ...) { |
| 497 | char buf[64]; |
| 498 | va_list ap; |
| 499 | va_start(ap, fmt); |
| 500 | mg_vsnprintf(buf, sizeof(buf), fmt, &ap); |
| 501 | va_end(ap); |
| 502 | MG_ERROR(("%lu %ld %s", c->id, c->fd, buf)); |
| 503 | c->is_closing = 1; // Set is_closing before sending MG_EV_CALL |
| 504 | mg_call(c, MG_EV_ERROR, buf); // Let user handler override it |
| 505 | } |
| 506 | |
| 507 | #ifdef MG_ENABLE_LINES |
| 508 | #line 1 "src/flash.c" |
| 509 | #endif |
| 510 | |
| 511 | |
| 512 | |
| 513 | |
| 514 | |
| 515 | #if MG_OTA != MG_OTA_NONE && MG_OTA != MG_OTA_CUSTOM |
| 516 | |
| 517 | static char *s_addr; // Current address to write to |
| 518 | static size_t s_size; // Firmware size to flash. In-progress indicator |
| 519 | static uint32_t s_crc32; // Firmware checksum |
| 520 | |
| 521 | bool mg_ota_flash_begin(size_t new_firmware_size, struct mg_flash *flash) { |
| 522 | bool ok = false; |
| 523 | if (s_size) { |
| 524 | MG_ERROR(("OTA already in progress. Call mg_ota_end()")); |
| 525 | } else { |
| 526 | size_t half = flash->size / 2; |
| 527 | s_crc32 = 0; |
| 528 | s_addr = (char *) flash->start + half; |
| 529 | MG_DEBUG(("FW %lu bytes, max %lu", new_firmware_size, half)); |
| 530 | if (new_firmware_size < half) { |
| 531 | ok = true; |
| 532 | s_size = new_firmware_size; |
| 533 | MG_INFO(("Starting OTA, firmware size %lu", s_size)); |
| 534 | } else { |
| 535 | MG_ERROR(("Firmware %lu is too big to fit %lu", new_firmware_size, half)); |
| 536 | } |
| 537 | } |
| 538 | return ok; |
| 539 | } |
| 540 | |
| 541 | bool mg_ota_flash_write(const void *buf, size_t len, struct mg_flash *flash) { |
| 542 | bool ok = false; |
| 543 | if (s_size == 0) { |
| 544 | MG_ERROR(("OTA is not started, call mg_ota_begin()")); |
| 545 | } else { |
| 546 | size_t len_aligned_down = MG_ROUND_DOWN(len, flash->align); |
| 547 | if (len_aligned_down) ok = flash->write_fn(s_addr, buf, len_aligned_down); |
| 548 | if (len_aligned_down < len) { |
| 549 | size_t left = len - len_aligned_down; |
| 550 | char tmp[flash->align]; |
| 551 | memset(tmp, 0xff, sizeof(tmp)); |
| 552 | memcpy(tmp, (char *) buf + len_aligned_down, left); |
| 553 | ok = flash->write_fn(s_addr + len_aligned_down, tmp, sizeof(tmp)); |
| 554 | } |
| 555 | s_crc32 = mg_crc32(s_crc32, (char *) buf, len); // Update CRC |
| 556 | MG_DEBUG(("%#x %p %lu -> %d", s_addr - len, buf, len, ok)); |
| 557 | s_addr += len; |
| 558 | } |
| 559 | return ok; |
| 560 | } |
| 561 | |
| 562 | bool mg_ota_flash_end(struct mg_flash *flash) { |
| 563 | char *base = (char *) flash->start + flash->size / 2; |
| 564 | bool ok = false; |
| 565 | if (s_size) { |
| 566 | size_t size = (size_t) (s_addr - base); |
| 567 | uint32_t crc32 = mg_crc32(0, base, s_size); |
| 568 | if (size == s_size && crc32 == s_crc32) ok = true; |
| 569 | MG_DEBUG(("CRC: %x/%x, size: %lu/%lu, status: %s", s_crc32, crc32, s_size, |
| 570 | size, ok ? "ok" : "fail")); |
| 571 | s_size = 0; |
| 572 | if (ok) ok = flash->swap_fn(); |
| 573 | } |
| 574 | MG_INFO(("Finishing OTA: %s", ok ? "ok" : "fail")); |
| 575 | return ok; |
| 576 | } |
| 577 | |
| 578 | #endif |
| 579 | |
| 580 | #ifdef MG_ENABLE_LINES |
| 581 | #line 1 "src/fmt.c" |
| 582 | #endif |
| 583 | |
| 584 | |
| 585 | |
| 586 | |
| 587 | static bool is_digit(int c) { |
| 588 | return c >= '0' && c <= '9'; |
| 589 | } |
| 590 | |
| 591 | static int addexp(char *buf, int e, int sign) { |
| 592 | int n = 0; |
| 593 | buf[n++] = 'e'; |
| 594 | buf[n++] = (char) sign; |
| 595 | if (e > 400) return 0; |
| 596 | if (e < 10) buf[n++] = '0'; |
| 597 | if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); |
| 598 | if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); |
| 599 | buf[n++] = (char) (e + '0'); |
| 600 | return n; |
| 601 | } |
| 602 | |
| 603 | static int xisinf(double x) { |
| 604 | union { |
| 605 | double f; |
| 606 | uint64_t u; |
| 607 | } ieee754 = {x}; |
| 608 | return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && |
| 609 | ((unsigned) ieee754.u == 0); |
| 610 | } |
| 611 | |
| 612 | static int xisnan(double x) { |
| 613 | union { |
| 614 | double f; |
| 615 | uint64_t u; |
| 616 | } ieee754 = {x}; |
| 617 | return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + |
| 618 | ((unsigned) ieee754.u != 0) > |
| 619 | 0x7ff00000; |
| 620 | } |
| 621 | |
| 622 | static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) { |
| 623 | char buf[40]; |
| 624 | int i, s = 0, n = 0, e = 0; |
| 625 | double t, mul, saved; |
| 626 | if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); |
| 627 | if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); |
| 628 | if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); |
| 629 | if (d < 0.0) d = -d, buf[s++] = '-'; |
| 630 | |
| 631 | // Round |
| 632 | saved = d; |
| 633 | if (tz) { |
| 634 | mul = 1.0; |
| 635 | while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0; |
| 636 | } else { |
| 637 | mul = 0.1; |
| 638 | } |
| 639 | |
| 640 | while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0; |
| 641 | for (i = 0, t = mul * 5; i < width; i++) t /= 10.0; |
| 642 | |
| 643 | d += t; |
| 644 | |
| 645 | // Calculate exponent, and 'mul' for scientific representation |
| 646 | mul = 1.0; |
| 647 | while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++; |
| 648 | while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; |
| 649 | // printf(" --> %g %d %g %g\n", saved, e, t, mul); |
| 650 | |
| 651 | if (tz && e >= width && width > 1) { |
| 652 | n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); |
| 653 | // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); |
| 654 | n += addexp(buf + s + n, e, '+'); |
| 655 | return mg_snprintf(dst, dstlen, "%.*s", n, buf); |
| 656 | } else if (tz && e <= -width && width > 1) { |
| 657 | n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); |
| 658 | // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); |
| 659 | n += addexp(buf + s + n, -e, '-'); |
| 660 | return mg_snprintf(dst, dstlen, "%.*s", n, buf); |
| 661 | } else { |
| 662 | int targ_width = width; |
| 663 | for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { |
| 664 | int ch = (int) (d / t); |
| 665 | if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); |
| 666 | d -= ch * t; |
| 667 | t /= 10.0; |
| 668 | } |
| 669 | // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); |
| 670 | if (n == 0) buf[s++] = '0'; |
| 671 | while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0; |
| 672 | if (s + n < (int) sizeof(buf)) buf[n + s++] = '.'; |
| 673 | // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); |
| 674 | if (!tz && n > 0) targ_width = width + n; |
| 675 | for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < targ_width; i++) { |
| 676 | int ch = (int) (d / t); |
| 677 | buf[s + n++] = (char) (ch + '0'); |
| 678 | d -= ch * t; |
| 679 | t /= 10.0; |
| 680 | } |
| 681 | } |
| 682 | |
| 683 | while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes |
| 684 | if (tz && n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot |
| 685 | n += s; |
| 686 | if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; |
| 687 | buf[n] = '\0'; |
| 688 | return mg_snprintf(dst, dstlen, "%s", buf); |
| 689 | } |
| 690 | |
| 691 | static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) { |
| 692 | const char *letters = "0123456789abcdef"; |
| 693 | uint64_t v = (uint64_t) val; |
| 694 | size_t s = 0, n, i; |
| 695 | if (is_signed && val < 0) buf[s++] = '-', v = (uint64_t) (-val); |
| 696 | // This loop prints a number in reverse order. I guess this is because we |
| 697 | // write numbers from right to left: least significant digit comes last. |
| 698 | // Maybe because we use Arabic numbers, and Arabs write RTL? |
| 699 | if (is_hex) { |
| 700 | for (n = 0; v; v >>= 4) buf[s + n++] = letters[v & 15]; |
| 701 | } else { |
| 702 | for (n = 0; v; v /= 10) buf[s + n++] = letters[v % 10]; |
| 703 | } |
| 704 | // Reverse a string |
| 705 | for (i = 0; i < n / 2; i++) { |
| 706 | char t = buf[s + i]; |
| 707 | buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t; |
| 708 | } |
| 709 | if (val == 0) buf[n++] = '0'; // Handle special case |
| 710 | return n + s; |
| 711 | } |
| 712 | |
| 713 | static size_t scpy(void (*out)(char, void *), void *ptr, char *buf, |
| 714 | size_t len) { |
| 715 | size_t i = 0; |
| 716 | while (i < len && buf[i] != '\0') out(buf[i++], ptr); |
| 717 | return i; |
| 718 | } |
| 719 | |
| 720 | size_t mg_xprintf(void (*out)(char, void *), void *ptr, const char *fmt, ...) { |
| 721 | size_t len = 0; |
| 722 | va_list ap; |
| 723 | va_start(ap, fmt); |
| 724 | len = mg_vxprintf(out, ptr, fmt, &ap); |
| 725 | va_end(ap); |
| 726 | return len; |
| 727 | } |
| 728 | |
| 729 | size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt, |
| 730 | va_list *ap) { |
| 731 | size_t i = 0, n = 0; |
| 732 | while (fmt[i] != '\0') { |
| 733 | if (fmt[i] == '%') { |
| 734 | size_t j, k, x = 0, is_long = 0, w = 0 /* width */, pr = ~0U /* prec */; |
| 735 | char pad = ' ', minus = 0, c = fmt[++i]; |
| 736 | if (c == '#') x++, c = fmt[++i]; |
| 737 | if (c == '-') minus++, c = fmt[++i]; |
| 738 | if (c == '0') pad = '0', c = fmt[++i]; |
| 739 | while (is_digit(c)) w *= 10, w += (size_t) (c - '0'), c = fmt[++i]; |
| 740 | if (c == '.') { |
| 741 | c = fmt[++i]; |
| 742 | if (c == '*') { |
| 743 | pr = (size_t) va_arg(*ap, int); |
| 744 | c = fmt[++i]; |
| 745 | } else { |
| 746 | pr = 0; |
| 747 | while (is_digit(c)) pr *= 10, pr += (size_t) (c - '0'), c = fmt[++i]; |
| 748 | } |
| 749 | } |
| 750 | while (c == 'h') c = fmt[++i]; // Treat h and hh as int |
| 751 | if (c == 'l') { |
| 752 | is_long++, c = fmt[++i]; |
| 753 | if (c == 'l') is_long++, c = fmt[++i]; |
| 754 | } |
| 755 | if (c == 'p') x = 1, is_long = 1; |
| 756 | if (c == 'd' || c == 'u' || c == 'x' || c == 'X' || c == 'p' || |
| 757 | c == 'g' || c == 'f') { |
| 758 | bool s = (c == 'd'), h = (c == 'x' || c == 'X' || c == 'p'); |
| 759 | char tmp[40]; |
| 760 | size_t xl = x ? 2 : 0; |
| 761 | if (c == 'g' || c == 'f') { |
| 762 | double v = va_arg(*ap, double); |
| 763 | if (pr == ~0U) pr = 6; |
| 764 | k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr, c == 'g'); |
| 765 | } else if (is_long == 2) { |
| 766 | int64_t v = va_arg(*ap, int64_t); |
| 767 | k = mg_lld(tmp, v, s, h); |
| 768 | } else if (is_long == 1) { |
| 769 | long v = va_arg(*ap, long); |
| 770 | k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned long) v, s, h); |
| 771 | } else { |
| 772 | int v = va_arg(*ap, int); |
| 773 | k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned) v, s, h); |
| 774 | } |
| 775 | for (j = 0; j < xl && w > 0; j++) w--; |
| 776 | for (j = 0; pad == ' ' && !minus && k < w && j + k < w; j++) |
| 777 | n += scpy(out, param, &pad, 1); |
| 778 | n += scpy(out, param, (char *) "0x", xl); |
| 779 | for (j = 0; pad == '0' && k < w && j + k < w; j++) |
| 780 | n += scpy(out, param, &pad, 1); |
| 781 | n += scpy(out, param, tmp, k); |
| 782 | for (j = 0; pad == ' ' && minus && k < w && j + k < w; j++) |
| 783 | n += scpy(out, param, &pad, 1); |
| 784 | } else if (c == 'm' || c == 'M') { |
| 785 | mg_pm_t f = va_arg(*ap, mg_pm_t); |
| 786 | if (c == 'm') out('"', param); |
| 787 | n += f(out, param, ap); |
| 788 | if (c == 'm') n += 2, out('"', param); |
| 789 | } else if (c == 'c') { |
| 790 | int ch = va_arg(*ap, int); |
| 791 | out((char) ch, param); |
| 792 | n++; |
| 793 | } else if (c == 's') { |
| 794 | char *p = va_arg(*ap, char *); |
| 795 | if (pr == ~0U) pr = p == NULL ? 0 : strlen(p); |
| 796 | for (j = 0; !minus && pr < w && j + pr < w; j++) |
| 797 | n += scpy(out, param, &pad, 1); |
| 798 | n += scpy(out, param, p, pr); |
| 799 | for (j = 0; minus && pr < w && j + pr < w; j++) |
| 800 | n += scpy(out, param, &pad, 1); |
| 801 | } else if (c == '%') { |
| 802 | out('%', param); |
| 803 | n++; |
| 804 | } else { |
| 805 | out('%', param); |
| 806 | out(c, param); |
| 807 | n += 2; |
| 808 | } |
| 809 | i++; |
| 810 | } else { |
| 811 | out(fmt[i], param), n++, i++; |
| 812 | } |
| 813 | } |
| 814 | return n; |
| 815 | } |
| 816 | |
| 817 | #ifdef MG_ENABLE_LINES |
| 818 | #line 1 "src/fs.c" |
| 819 | #endif |
| 820 | |
| 821 | |
| 822 | |
| 823 | |
| 824 | struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { |
| 825 | struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); |
| 826 | if (fd != NULL) { |
| 827 | fd->fd = fs->op(path, flags); |
| 828 | fd->fs = fs; |
| 829 | if (fd->fd == NULL) { |
| 830 | free(fd); |
| 831 | fd = NULL; |
| 832 | } |
| 833 | } |
| 834 | return fd; |
| 835 | } |
| 836 | |
| 837 | void mg_fs_close(struct mg_fd *fd) { |
| 838 | if (fd != NULL) { |
| 839 | fd->fs->cl(fd->fd); |
| 840 | free(fd); |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | struct mg_str mg_file_read(struct mg_fs *fs, const char *path) { |
| 845 | struct mg_str result = {NULL, 0}; |
| 846 | void *fp; |
| 847 | fs->st(path, &result.len, NULL); |
| 848 | if ((fp = fs->op(path, MG_FS_READ)) != NULL) { |
| 849 | result.buf = (char *) calloc(1, result.len + 1); |
| 850 | if (result.buf != NULL && |
| 851 | fs->rd(fp, (void *) result.buf, result.len) != result.len) { |
| 852 | free((void *) result.buf); |
| 853 | result.buf = NULL; |
| 854 | } |
| 855 | fs->cl(fp); |
| 856 | } |
| 857 | if (result.buf == NULL) result.len = 0; |
| 858 | return result; |
| 859 | } |
| 860 | |
| 861 | bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, |
| 862 | size_t len) { |
| 863 | bool result = false; |
| 864 | struct mg_fd *fd; |
| 865 | char tmp[MG_PATH_MAX]; |
| 866 | mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); |
| 867 | if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { |
| 868 | result = fs->wr(fd->fd, buf, len) == len; |
| 869 | mg_fs_close(fd); |
| 870 | if (result) { |
| 871 | fs->rm(path); |
| 872 | fs->mv(tmp, path); |
| 873 | } else { |
| 874 | fs->rm(tmp); |
| 875 | } |
| 876 | } |
| 877 | return result; |
| 878 | } |
| 879 | |
| 880 | bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) { |
| 881 | va_list ap; |
| 882 | char *data; |
| 883 | bool result = false; |
| 884 | va_start(ap, fmt); |
| 885 | data = mg_vmprintf(fmt, &ap); |
| 886 | va_end(ap); |
| 887 | result = mg_file_write(fs, path, data, strlen(data)); |
| 888 | free(data); |
| 889 | return result; |
| 890 | } |
| 891 | |
| 892 | // This helper function allows to scan a filesystem in a sequential way, |
| 893 | // without using callback function: |
| 894 | // char buf[100] = ""; |
| 895 | // while (mg_fs_ls(&mg_fs_posix, "./", buf, sizeof(buf))) { |
| 896 | // ... |
| 897 | static void mg_fs_ls_fn(const char *filename, void *param) { |
| 898 | struct mg_str *s = (struct mg_str *) param; |
| 899 | if (s->buf[0] == '\0') { |
| 900 | mg_snprintf((char *) s->buf, s->len, "%s", filename); |
| 901 | } else if (strcmp(s->buf, filename) == 0) { |
| 902 | ((char *) s->buf)[0] = '\0'; // Fetch next file |
| 903 | } |
| 904 | } |
| 905 | |
| 906 | bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len) { |
| 907 | struct mg_str s = {buf, len}; |
| 908 | fs->ls(path, mg_fs_ls_fn, &s); |
| 909 | return buf[0] != '\0'; |
| 910 | } |
| 911 | |
| 912 | #ifdef MG_ENABLE_LINES |
| 913 | #line 1 "src/fs_fat.c" |
| 914 | #endif |
| 915 | |
| 916 | |
| 917 | |
| 918 | #if MG_ENABLE_FATFS |
| 919 | #include <ff.h> |
| 920 | |
| 921 | static int mg_days_from_epoch(int y, int m, int d) { |
| 922 | y -= m <= 2; |
| 923 | int era = y / 400; |
| 924 | int yoe = y - era * 400; |
| 925 | int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; |
| 926 | int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; |
| 927 | return era * 146097 + doe - 719468; |
| 928 | } |
| 929 | |
| 930 | static time_t mg_timegm(const struct tm *t) { |
| 931 | int year = t->tm_year + 1900; |
| 932 | int month = t->tm_mon; // 0-11 |
| 933 | if (month > 11) { |
| 934 | year += month / 12; |
| 935 | month %= 12; |
| 936 | } else if (month < 0) { |
| 937 | int years_diff = (11 - month) / 12; |
| 938 | year -= years_diff; |
| 939 | month += 12 * years_diff; |
| 940 | } |
| 941 | int x = mg_days_from_epoch(year, month + 1, t->tm_mday); |
| 942 | return 60 * (60 * (24L * x + t->tm_hour) + t->tm_min) + t->tm_sec; |
| 943 | } |
| 944 | |
| 945 | static time_t ff_time_to_epoch(uint16_t fdate, uint16_t ftime) { |
| 946 | struct tm tm; |
| 947 | memset(&tm, 0, sizeof(struct tm)); |
| 948 | tm.tm_sec = (ftime << 1) & 0x3e; |
| 949 | tm.tm_min = ((ftime >> 5) & 0x3f); |
| 950 | tm.tm_hour = ((ftime >> 11) & 0x1f); |
| 951 | tm.tm_mday = (fdate & 0x1f); |
| 952 | tm.tm_mon = ((fdate >> 5) & 0x0f) - 1; |
| 953 | tm.tm_year = ((fdate >> 9) & 0x7f) + 80; |
| 954 | return mg_timegm(&tm); |
| 955 | } |
| 956 | |
| 957 | static int ff_stat(const char *path, size_t *size, time_t *mtime) { |
| 958 | FILINFO fi; |
| 959 | if (path[0] == '\0') { |
| 960 | if (size) *size = 0; |
| 961 | if (mtime) *mtime = 0; |
| 962 | return MG_FS_DIR; |
| 963 | } else if (f_stat(path, &fi) == 0) { |
| 964 | if (size) *size = (size_t) fi.fsize; |
| 965 | if (mtime) *mtime = ff_time_to_epoch(fi.fdate, fi.ftime); |
| 966 | return MG_FS_READ | MG_FS_WRITE | ((fi.fattrib & AM_DIR) ? MG_FS_DIR : 0); |
| 967 | } else { |
| 968 | return 0; |
| 969 | } |
| 970 | } |
| 971 | |
| 972 | static void ff_list(const char *dir, void (*fn)(const char *, void *), |
| 973 | void *userdata) { |
| 974 | DIR d; |
| 975 | FILINFO fi; |
| 976 | if (f_opendir(&d, dir) == FR_OK) { |
| 977 | while (f_readdir(&d, &fi) == FR_OK && fi.fname[0] != '\0') { |
| 978 | if (!strcmp(fi.fname, ".") || !strcmp(fi.fname, "..")) continue; |
| 979 | fn(fi.fname, userdata); |
| 980 | } |
| 981 | f_closedir(&d); |
| 982 | } |
| 983 | } |
| 984 | |
| 985 | static void *ff_open(const char *path, int flags) { |
| 986 | FIL f; |
| 987 | unsigned char mode = FA_READ; |
| 988 | if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND; |
| 989 | if (f_open(&f, path, mode) == 0) { |
| 990 | FIL *fp; |
| 991 | if ((fp = calloc(1, sizeof(*fp))) != NULL) { |
| 992 | memcpy(fp, &f, sizeof(*fp)); |
| 993 | return fp; |
| 994 | } |
| 995 | } |
| 996 | return NULL; |
| 997 | } |
| 998 | |
| 999 | static void ff_close(void *fp) { |
| 1000 | if (fp != NULL) { |
| 1001 | f_close((FIL *) fp); |
| 1002 | free(fp); |
| 1003 | } |
| 1004 | } |
| 1005 | |
| 1006 | static size_t ff_read(void *fp, void *buf, size_t len) { |
| 1007 | UINT n = 0, misalign = ((size_t) buf) & 3; |
| 1008 | if (misalign) { |
| 1009 | char aligned[4]; |
| 1010 | f_read((FIL *) fp, aligned, len > misalign ? misalign : len, &n); |
| 1011 | memcpy(buf, aligned, n); |
| 1012 | } else { |
| 1013 | f_read((FIL *) fp, buf, len, &n); |
| 1014 | } |
| 1015 | return n; |
| 1016 | } |
| 1017 | |
| 1018 | static size_t ff_write(void *fp, const void *buf, size_t len) { |
| 1019 | UINT n = 0; |
| 1020 | return f_write((FIL *) fp, (char *) buf, len, &n) == FR_OK ? n : 0; |
| 1021 | } |
| 1022 | |
| 1023 | static size_t ff_seek(void *fp, size_t offset) { |
| 1024 | f_lseek((FIL *) fp, offset); |
| 1025 | return offset; |
| 1026 | } |
| 1027 | |
| 1028 | static bool ff_rename(const char *from, const char *to) { |
| 1029 | return f_rename(from, to) == FR_OK; |
| 1030 | } |
| 1031 | |
| 1032 | static bool ff_remove(const char *path) { |
| 1033 | return f_unlink(path) == FR_OK; |
| 1034 | } |
| 1035 | |
| 1036 | static bool ff_mkdir(const char *path) { |
| 1037 | return f_mkdir(path) == FR_OK; |
| 1038 | } |
| 1039 | |
| 1040 | struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, |
| 1041 | ff_write, ff_seek, ff_rename, ff_remove, ff_mkdir}; |
| 1042 | #endif |
| 1043 | |
| 1044 | #ifdef MG_ENABLE_LINES |
| 1045 | #line 1 "src/fs_packed.c" |
| 1046 | #endif |
| 1047 | |
| 1048 | |
| 1049 | |
| 1050 | |
| 1051 | struct packed_file { |
| 1052 | const char *data; |
| 1053 | size_t size; |
| 1054 | size_t pos; |
| 1055 | }; |
| 1056 | |
| 1057 | #if MG_ENABLE_PACKED_FS |
| 1058 | #else |
| 1059 | const char *mg_unpack(const char *path, size_t *size, time_t *mtime) { |
| 1060 | if (size != NULL) *size = 0; |
| 1061 | if (mtime != NULL) *mtime = 0; |
| 1062 | (void) path; |
| 1063 | return NULL; |
| 1064 | } |
| 1065 | const char *mg_unlist(size_t no) { |
| 1066 | (void) no; |
| 1067 | return NULL; |
| 1068 | } |
| 1069 | #endif |
| 1070 | |
| 1071 | struct mg_str mg_unpacked(const char *path) { |
| 1072 | size_t len = 0; |
| 1073 | const char *buf = mg_unpack(path, &len, NULL); |
| 1074 | return mg_str_n(buf, len); |
| 1075 | } |
| 1076 | |
| 1077 | static int is_dir_prefix(const char *prefix, size_t n, const char *path) { |
| 1078 | // MG_INFO(("[%.*s] [%s] %c", (int) n, prefix, path, path[n])); |
| 1079 | return n < strlen(path) && strncmp(prefix, path, n) == 0 && |
| 1080 | (n == 0 || path[n] == '/' || path[n - 1] == '/'); |
| 1081 | } |
| 1082 | |
| 1083 | static int packed_stat(const char *path, size_t *size, time_t *mtime) { |
| 1084 | const char *p; |
| 1085 | size_t i, n = strlen(path); |
| 1086 | if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file |
| 1087 | // Scan all files. If `path` is a dir prefix for any of them, it's a dir |
| 1088 | for (i = 0; (p = mg_unlist(i)) != NULL; i++) { |
| 1089 | if (is_dir_prefix(path, n, p)) return MG_FS_DIR; |
| 1090 | } |
| 1091 | return 0; |
| 1092 | } |
| 1093 | |
| 1094 | static void packed_list(const char *dir, void (*fn)(const char *, void *), |
| 1095 | void *userdata) { |
| 1096 | char buf[MG_PATH_MAX], tmp[sizeof(buf)]; |
| 1097 | const char *path, *begin, *end; |
| 1098 | size_t i, n = strlen(dir); |
| 1099 | tmp[0] = '\0'; // Previously listed entry |
| 1100 | for (i = 0; (path = mg_unlist(i)) != NULL; i++) { |
| 1101 | if (!is_dir_prefix(dir, n, path)) continue; |
| 1102 | begin = &path[n + 1]; |
| 1103 | end = strchr(begin, '/'); |
| 1104 | if (end == NULL) end = begin + strlen(begin); |
| 1105 | mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); |
| 1106 | buf[sizeof(buf) - 1] = '\0'; |
| 1107 | // If this entry has been already listed, skip |
| 1108 | // NOTE: we're assuming that file list is sorted alphabetically |
| 1109 | if (strcmp(buf, tmp) == 0) continue; |
| 1110 | fn(buf, userdata); // Not yet listed, call user function |
| 1111 | strcpy(tmp, buf); // And save this entry as listed |
| 1112 | } |
| 1113 | } |
| 1114 | |
| 1115 | static void *packed_open(const char *path, int flags) { |
| 1116 | size_t size = 0; |
| 1117 | const char *data = mg_unpack(path, &size, NULL); |
| 1118 | struct packed_file *fp = NULL; |
| 1119 | if (data == NULL) return NULL; |
| 1120 | if (flags & MG_FS_WRITE) return NULL; |
| 1121 | if ((fp = (struct packed_file *) calloc(1, sizeof(*fp))) != NULL) { |
| 1122 | fp->size = size; |
| 1123 | fp->data = data; |
| 1124 | } |
| 1125 | return (void *) fp; |
| 1126 | } |
| 1127 | |
| 1128 | static void packed_close(void *fp) { |
| 1129 | if (fp != NULL) free(fp); |
| 1130 | } |
| 1131 | |
| 1132 | static size_t packed_read(void *fd, void *buf, size_t len) { |
| 1133 | struct packed_file *fp = (struct packed_file *) fd; |
| 1134 | if (fp->pos + len > fp->size) len = fp->size - fp->pos; |
| 1135 | memcpy(buf, &fp->data[fp->pos], len); |
| 1136 | fp->pos += len; |
| 1137 | return len; |
| 1138 | } |
| 1139 | |
| 1140 | static size_t packed_write(void *fd, const void *buf, size_t len) { |
| 1141 | (void) fd, (void) buf, (void) len; |
| 1142 | return 0; |
| 1143 | } |
| 1144 | |
| 1145 | static size_t packed_seek(void *fd, size_t offset) { |
| 1146 | struct packed_file *fp = (struct packed_file *) fd; |
| 1147 | fp->pos = offset; |
| 1148 | if (fp->pos > fp->size) fp->pos = fp->size; |
| 1149 | return fp->pos; |
| 1150 | } |
| 1151 | |
| 1152 | static bool packed_rename(const char *from, const char *to) { |
| 1153 | (void) from, (void) to; |
| 1154 | return false; |
| 1155 | } |
| 1156 | |
| 1157 | static bool packed_remove(const char *path) { |
| 1158 | (void) path; |
| 1159 | return false; |
| 1160 | } |
| 1161 | |
| 1162 | static bool packed_mkdir(const char *path) { |
| 1163 | (void) path; |
| 1164 | return false; |
| 1165 | } |
| 1166 | |
| 1167 | struct mg_fs mg_fs_packed = { |
| 1168 | packed_stat, packed_list, packed_open, packed_close, packed_read, |
| 1169 | packed_write, packed_seek, packed_rename, packed_remove, packed_mkdir}; |
| 1170 | |
| 1171 | #ifdef MG_ENABLE_LINES |
| 1172 | #line 1 "src/fs_posix.c" |
| 1173 | #endif |
| 1174 | |
| 1175 | |
| 1176 | #if MG_ENABLE_POSIX_FS |
| 1177 | |
| 1178 | #ifndef MG_STAT_STRUCT |
| 1179 | #define MG_STAT_STRUCT stat |
| 1180 | #endif |
| 1181 | |
| 1182 | #ifndef MG_STAT_FUNC |
| 1183 | #define MG_STAT_FUNC stat |
| 1184 | #endif |
| 1185 | |
| 1186 | static int p_stat(const char *path, size_t *size, time_t *mtime) { |
| 1187 | #if !defined(S_ISDIR) |
| 1188 | MG_ERROR(("stat() API is not supported. %p %p %p", path, size, mtime)); |
| 1189 | return 0; |
| 1190 | #else |
| 1191 | #if MG_ARCH == MG_ARCH_WIN32 |
| 1192 | struct _stati64 st; |
| 1193 | wchar_t tmp[MG_PATH_MAX]; |
| 1194 | MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0])); |
| 1195 | if (_wstati64(tmp, &st) != 0) return 0; |
| 1196 | // If path is a symlink, windows reports 0 in st.st_size. |
| 1197 | // Get a real file size by opening it and jumping to the end |
| 1198 | if (st.st_size == 0 && (st.st_mode & _S_IFREG)) { |
| 1199 | FILE *fp = _wfopen(tmp, L"rb"); |
| 1200 | if (fp != NULL) { |
| 1201 | fseek(fp, 0, SEEK_END); |
| 1202 | if (ftell(fp) > 0) st.st_size = ftell(fp); // Use _ftelli64 on win10+ |
| 1203 | fclose(fp); |
| 1204 | } |
| 1205 | } |
| 1206 | #else |
| 1207 | struct MG_STAT_STRUCT st; |
| 1208 | if (MG_STAT_FUNC(path, &st) != 0) return 0; |
| 1209 | #endif |
| 1210 | if (size) *size = (size_t) st.st_size; |
| 1211 | if (mtime) *mtime = st.st_mtime; |
| 1212 | return MG_FS_READ | MG_FS_WRITE | (S_ISDIR(st.st_mode) ? MG_FS_DIR : 0); |
| 1213 | #endif |
| 1214 | } |
| 1215 | |
| 1216 | #if MG_ARCH == MG_ARCH_WIN32 |
| 1217 | struct dirent { |
| 1218 | char d_name[MAX_PATH]; |
| 1219 | }; |
| 1220 | |
| 1221 | typedef struct win32_dir { |
| 1222 | HANDLE handle; |
| 1223 | WIN32_FIND_DATAW info; |
| 1224 | struct dirent result; |
| 1225 | } DIR; |
| 1226 | |
| 1227 | #if 0 |
| 1228 | int gettimeofday(struct timeval *tv, void *tz) { |
| 1229 | FILETIME ft; |
| 1230 | unsigned __int64 tmpres = 0; |
| 1231 | |
| 1232 | if (tv != NULL) { |
| 1233 | GetSystemTimeAsFileTime(&ft); |
| 1234 | tmpres |= ft.dwHighDateTime; |
| 1235 | tmpres <<= 32; |
| 1236 | tmpres |= ft.dwLowDateTime; |
| 1237 | tmpres /= 10; // convert into microseconds |
| 1238 | tmpres -= (int64_t) 11644473600000000; |
| 1239 | tv->tv_sec = (long) (tmpres / 1000000UL); |
| 1240 | tv->tv_usec = (long) (tmpres % 1000000UL); |
| 1241 | } |
| 1242 | (void) tz; |
| 1243 | return 0; |
| 1244 | } |
| 1245 | #endif |
| 1246 | |
| 1247 | static int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) { |
| 1248 | int ret; |
| 1249 | char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p; |
| 1250 | strncpy(buf, path, sizeof(buf)); |
| 1251 | buf[sizeof(buf) - 1] = '\0'; |
| 1252 | // Trim trailing slashes. Leave backslash for paths like "X:\" |
| 1253 | p = buf + strlen(buf) - 1; |
| 1254 | while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0'; |
| 1255 | memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); |
| 1256 | ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); |
| 1257 | // Convert back to Unicode. If doubly-converted string does not match the |
| 1258 | // original, something is fishy, reject. |
| 1259 | WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), |
| 1260 | NULL, NULL); |
| 1261 | if (strcmp(buf, buf2) != 0) { |
| 1262 | wbuf[0] = L'\0'; |
| 1263 | ret = 0; |
| 1264 | } |
| 1265 | return ret; |
| 1266 | } |
| 1267 | |
| 1268 | DIR *opendir(const char *name) { |
| 1269 | DIR *d = NULL; |
| 1270 | wchar_t wpath[MAX_PATH]; |
| 1271 | DWORD attrs; |
| 1272 | |
| 1273 | if (name == NULL) { |
| 1274 | SetLastError(ERROR_BAD_ARGUMENTS); |
| 1275 | } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) { |
| 1276 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| 1277 | } else { |
| 1278 | to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); |
| 1279 | attrs = GetFileAttributesW(wpath); |
| 1280 | if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { |
| 1281 | (void) wcscat(wpath, L"\\*"); |
| 1282 | d->handle = FindFirstFileW(wpath, &d->info); |
| 1283 | d->result.d_name[0] = '\0'; |
| 1284 | } else { |
| 1285 | free(d); |
| 1286 | d = NULL; |
| 1287 | } |
| 1288 | } |
| 1289 | return d; |
| 1290 | } |
| 1291 | |
| 1292 | int closedir(DIR *d) { |
| 1293 | int result = 0; |
| 1294 | if (d != NULL) { |
| 1295 | if (d->handle != INVALID_HANDLE_VALUE) |
| 1296 | result = FindClose(d->handle) ? 0 : -1; |
| 1297 | free(d); |
| 1298 | } else { |
| 1299 | result = -1; |
| 1300 | SetLastError(ERROR_BAD_ARGUMENTS); |
| 1301 | } |
| 1302 | return result; |
| 1303 | } |
| 1304 | |
| 1305 | struct dirent *readdir(DIR *d) { |
| 1306 | struct dirent *result = NULL; |
| 1307 | if (d != NULL) { |
| 1308 | memset(&d->result, 0, sizeof(d->result)); |
| 1309 | if (d->handle != INVALID_HANDLE_VALUE) { |
| 1310 | result = &d->result; |
| 1311 | WideCharToMultiByte(CP_UTF8, 0, d->info.cFileName, -1, result->d_name, |
| 1312 | sizeof(result->d_name), NULL, NULL); |
| 1313 | if (!FindNextFileW(d->handle, &d->info)) { |
| 1314 | FindClose(d->handle); |
| 1315 | d->handle = INVALID_HANDLE_VALUE; |
| 1316 | } |
| 1317 | } else { |
| 1318 | SetLastError(ERROR_FILE_NOT_FOUND); |
| 1319 | } |
| 1320 | } else { |
| 1321 | SetLastError(ERROR_BAD_ARGUMENTS); |
| 1322 | } |
| 1323 | return result; |
| 1324 | } |
| 1325 | #endif |
| 1326 | |
| 1327 | static void p_list(const char *dir, void (*fn)(const char *, void *), |
| 1328 | void *userdata) { |
| 1329 | #if MG_ENABLE_DIRLIST |
| 1330 | struct dirent *dp; |
| 1331 | DIR *dirp; |
| 1332 | if ((dirp = (opendir(dir))) == NULL) return; |
| 1333 | while ((dp = readdir(dirp)) != NULL) { |
| 1334 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; |
| 1335 | fn(dp->d_name, userdata); |
| 1336 | } |
| 1337 | closedir(dirp); |
| 1338 | #else |
| 1339 | (void) dir, (void) fn, (void) userdata; |
| 1340 | #endif |
| 1341 | } |
| 1342 | |
| 1343 | static void *p_open(const char *path, int flags) { |
| 1344 | #if MG_ARCH == MG_ARCH_WIN32 |
| 1345 | const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; |
| 1346 | wchar_t b1[MG_PATH_MAX], b2[10]; |
| 1347 | MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); |
| 1348 | MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0])); |
| 1349 | return (void *) _wfopen(b1, b2); |
| 1350 | #else |
| 1351 | const char *mode = flags == MG_FS_READ ? "rbe" : "a+be"; // e for CLOEXEC |
| 1352 | return (void *) fopen(path, mode); |
| 1353 | #endif |
| 1354 | } |
| 1355 | |
| 1356 | static void p_close(void *fp) { |
| 1357 | fclose((FILE *) fp); |
| 1358 | } |
| 1359 | |
| 1360 | static size_t p_read(void *fp, void *buf, size_t len) { |
| 1361 | return fread(buf, 1, len, (FILE *) fp); |
| 1362 | } |
| 1363 | |
| 1364 | static size_t p_write(void *fp, const void *buf, size_t len) { |
| 1365 | return fwrite(buf, 1, len, (FILE *) fp); |
| 1366 | } |
| 1367 | |
| 1368 | static size_t p_seek(void *fp, size_t offset) { |
| 1369 | #if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || \ |
| 1370 | (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ |
| 1371 | (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) |
| 1372 | if (fseeko((FILE *) fp, (off_t) offset, SEEK_SET) != 0) (void) 0; |
| 1373 | #else |
| 1374 | if (fseek((FILE *) fp, (long) offset, SEEK_SET) != 0) (void) 0; |
| 1375 | #endif |
| 1376 | return (size_t) ftell((FILE *) fp); |
| 1377 | } |
| 1378 | |
| 1379 | static bool p_rename(const char *from, const char *to) { |
| 1380 | return rename(from, to) == 0; |
| 1381 | } |
| 1382 | |
| 1383 | static bool p_remove(const char *path) { |
| 1384 | return remove(path) == 0; |
| 1385 | } |
| 1386 | |
| 1387 | static bool p_mkdir(const char *path) { |
| 1388 | return mkdir(path, 0775) == 0; |
| 1389 | } |
| 1390 | |
| 1391 | #else |
| 1392 | |
| 1393 | static int p_stat(const char *path, size_t *size, time_t *mtime) { |
| 1394 | (void) path, (void) size, (void) mtime; |
| 1395 | return 0; |
| 1396 | } |
| 1397 | static void p_list(const char *path, void (*fn)(const char *, void *), |
| 1398 | void *userdata) { |
| 1399 | (void) path, (void) fn, (void) userdata; |
| 1400 | } |
| 1401 | static void *p_open(const char *path, int flags) { |
| 1402 | (void) path, (void) flags; |
| 1403 | return NULL; |
| 1404 | } |
| 1405 | static void p_close(void *fp) { |
| 1406 | (void) fp; |
| 1407 | } |
| 1408 | static size_t p_read(void *fd, void *buf, size_t len) { |
| 1409 | (void) fd, (void) buf, (void) len; |
| 1410 | return 0; |
| 1411 | } |
| 1412 | static size_t p_write(void *fd, const void *buf, size_t len) { |
| 1413 | (void) fd, (void) buf, (void) len; |
| 1414 | return 0; |
| 1415 | } |
| 1416 | static size_t p_seek(void *fd, size_t offset) { |
| 1417 | (void) fd, (void) offset; |
| 1418 | return (size_t) ~0; |
| 1419 | } |
| 1420 | static bool p_rename(const char *from, const char *to) { |
| 1421 | (void) from, (void) to; |
| 1422 | return false; |
| 1423 | } |
| 1424 | static bool p_remove(const char *path) { |
| 1425 | (void) path; |
| 1426 | return false; |
| 1427 | } |
| 1428 | static bool p_mkdir(const char *path) { |
| 1429 | (void) path; |
| 1430 | return false; |
| 1431 | } |
| 1432 | #endif |
| 1433 | |
| 1434 | struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, |
| 1435 | p_write, p_seek, p_rename, p_remove, p_mkdir}; |
| 1436 | |
| 1437 | #ifdef MG_ENABLE_LINES |
| 1438 | #line 1 "src/http.c" |
| 1439 | #endif |
| 1440 | |
| 1441 | |
| 1442 | |
| 1443 | |
| 1444 | |
| 1445 | |
| 1446 | |
| 1447 | |
| 1448 | |
| 1449 | |
| 1450 | |
| 1451 | |
| 1452 | |
| 1453 | static int mg_ncasecmp(const char *s1, const char *s2, size_t len) { |
| 1454 | int diff = 0; |
| 1455 | if (len > 0) do { |
| 1456 | int c = *s1++, d = *s2++; |
| 1457 | if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; |
| 1458 | if (d >= 'A' && d <= 'Z') d += 'a' - 'A'; |
| 1459 | diff = c - d; |
| 1460 | } while (diff == 0 && s1[-1] != '\0' && --len > 0); |
| 1461 | return diff; |
| 1462 | } |
| 1463 | |
| 1464 | bool mg_to_size_t(struct mg_str str, size_t *val); |
| 1465 | bool mg_to_size_t(struct mg_str str, size_t *val) { |
| 1466 | size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0; |
| 1467 | while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++; |
| 1468 | if (i < str.len && str.buf[i] == '-') return false; |
| 1469 | while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') { |
| 1470 | size_t digit = (size_t) (str.buf[i] - '0'); |
| 1471 | if (result > max2) return false; // Overflow |
| 1472 | result *= 10; |
| 1473 | if (result > max - digit) return false; // Overflow |
| 1474 | result += digit; |
| 1475 | i++, ndigits++; |
| 1476 | } |
| 1477 | while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++; |
| 1478 | if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT |
| 1479 | if (i != str.len) return false; // Ditto |
| 1480 | *val = (size_t) result; |
| 1481 | return true; |
| 1482 | } |
| 1483 | |
| 1484 | // Chunk deletion marker is the MSB in the "processed" counter |
| 1485 | #define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1)) |
| 1486 | |
| 1487 | // Multipart POST example: |
| 1488 | // --xyz |
| 1489 | // Content-Disposition: form-data; name="val" |
| 1490 | // |
| 1491 | // abcdef |
| 1492 | // --xyz |
| 1493 | // Content-Disposition: form-data; name="foo"; filename="a.txt" |
| 1494 | // Content-Type: text/plain |
| 1495 | // |
| 1496 | // hello world |
| 1497 | // |
| 1498 | // --xyz-- |
| 1499 | size_t mg_http_next_multipart(struct mg_str body, size_t ofs, |
| 1500 | struct mg_http_part *part) { |
| 1501 | struct mg_str cd = mg_str_n("Content-Disposition", 19); |
| 1502 | const char *s = body.buf; |
| 1503 | size_t b = ofs, h1, h2, b1, b2, max = body.len; |
| 1504 | |
| 1505 | // Init part params |
| 1506 | if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0); |
| 1507 | |
| 1508 | // Skip boundary |
| 1509 | while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++; |
| 1510 | if (b <= ofs || b + 2 >= max) return 0; |
| 1511 | // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s)); |
| 1512 | |
| 1513 | // Skip headers |
| 1514 | h1 = h2 = b + 2; |
| 1515 | for (;;) { |
| 1516 | while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++; |
| 1517 | if (h2 == h1) break; |
| 1518 | if (h2 + 2 >= max) return 0; |
| 1519 | // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1])); |
| 1520 | if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' && |
| 1521 | mg_ncasecmp(&s[h1], cd.buf, cd.len) == 0) { |
| 1522 | struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2)); |
| 1523 | part->name = mg_http_get_header_var(v, mg_str_n("name", 4)); |
| 1524 | part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8)); |
| 1525 | } |
| 1526 | h1 = h2 = h2 + 2; |
| 1527 | } |
| 1528 | b1 = b2 = h2 + 2; |
| 1529 | while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' && |
| 1530 | memcmp(&s[b2 + 2], s, b - ofs) == 0)) |
| 1531 | b2++; |
| 1532 | |
| 1533 | if (b2 + 2 >= max) return 0; |
| 1534 | if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1); |
| 1535 | // MG_INFO(("Body: [%.*s]", (int) (b2 - b1), &s[b1])); |
| 1536 | return b2 + 2; |
| 1537 | } |
| 1538 | |
| 1539 | void mg_http_bauth(struct mg_connection *c, const char *user, |
| 1540 | const char *pass) { |
| 1541 | struct mg_str u = mg_str(user), p = mg_str(pass); |
| 1542 | size_t need = c->send.len + 36 + (u.len + p.len) * 2; |
| 1543 | if (c->send.size < need) mg_iobuf_resize(&c->send, need); |
| 1544 | if (c->send.size >= need) { |
| 1545 | size_t i, n = 0; |
| 1546 | char *buf = (char *) &c->send.buf[c->send.len]; |
| 1547 | memcpy(buf, "Authorization: Basic ", 21); // DON'T use mg_send! |
| 1548 | for (i = 0; i < u.len; i++) { |
| 1549 | n = mg_base64_update(((unsigned char *) u.buf)[i], buf + 21, n); |
| 1550 | } |
| 1551 | if (p.len > 0) { |
| 1552 | n = mg_base64_update(':', buf + 21, n); |
| 1553 | for (i = 0; i < p.len; i++) { |
| 1554 | n = mg_base64_update(((unsigned char *) p.buf)[i], buf + 21, n); |
| 1555 | } |
| 1556 | } |
| 1557 | n = mg_base64_final(buf + 21, n); |
| 1558 | c->send.len += 21 + (size_t) n + 2; |
| 1559 | memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2); |
| 1560 | } else { |
| 1561 | MG_ERROR(("%lu oom %d->%d ", c->id, (int) c->send.size, (int) need)); |
| 1562 | } |
| 1563 | } |
| 1564 | |
| 1565 | struct mg_str mg_http_var(struct mg_str buf, struct mg_str name) { |
| 1566 | struct mg_str entry, k, v, result = mg_str_n(NULL, 0); |
| 1567 | while (mg_span(buf, &entry, &buf, '&')) { |
| 1568 | if (mg_span(entry, &k, &v, '=') && name.len == k.len && |
| 1569 | mg_ncasecmp(name.buf, k.buf, k.len) == 0) { |
| 1570 | result = v; |
| 1571 | break; |
| 1572 | } |
| 1573 | } |
| 1574 | return result; |
| 1575 | } |
| 1576 | |
| 1577 | int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst, |
| 1578 | size_t dst_len) { |
| 1579 | int len; |
| 1580 | if (dst != NULL && dst_len > 0) { |
| 1581 | dst[0] = '\0'; // If destination buffer is valid, always nul-terminate it |
| 1582 | } |
| 1583 | if (dst == NULL || dst_len == 0) { |
| 1584 | len = -2; // Bad destination |
| 1585 | } else if (buf->buf == NULL || name == NULL || buf->len == 0) { |
| 1586 | len = -1; // Bad source |
| 1587 | } else { |
| 1588 | struct mg_str v = mg_http_var(*buf, mg_str(name)); |
| 1589 | if (v.buf == NULL) { |
| 1590 | len = -4; // Name does not exist |
| 1591 | } else { |
| 1592 | len = mg_url_decode(v.buf, v.len, dst, dst_len, 1); |
| 1593 | if (len < 0) len = -3; // Failed to decode |
| 1594 | } |
| 1595 | } |
| 1596 | return len; |
| 1597 | } |
| 1598 | |
| 1599 | static bool isx(int c) { |
| 1600 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || |
| 1601 | (c >= 'A' && c <= 'F'); |
| 1602 | } |
| 1603 | |
| 1604 | int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, |
| 1605 | int is_form_url_encoded) { |
| 1606 | size_t i, j; |
| 1607 | for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) { |
| 1608 | if (src[i] == '%') { |
| 1609 | // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len |
| 1610 | if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) { |
| 1611 | mg_str_to_num(mg_str_n(src + i + 1, 2), 16, &dst[j], sizeof(uint8_t)); |
| 1612 | i += 2; |
| 1613 | } else { |
| 1614 | return -1; |
| 1615 | } |
| 1616 | } else if (is_form_url_encoded && src[i] == '+') { |
| 1617 | dst[j] = ' '; |
| 1618 | } else { |
| 1619 | dst[j] = src[i]; |
| 1620 | } |
| 1621 | } |
| 1622 | if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination |
| 1623 | return i >= src_len && j < dst_len ? (int) j : -1; |
| 1624 | } |
| 1625 | |
| 1626 | static bool isok(uint8_t c) { |
| 1627 | return c == '\n' || c == '\r' || c == '\t' || c >= ' '; |
| 1628 | } |
| 1629 | |
| 1630 | int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) { |
| 1631 | size_t i; |
| 1632 | for (i = 0; i < buf_len; i++) { |
| 1633 | if (!isok(buf[i])) return -1; |
| 1634 | if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') || |
| 1635 | (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n')) |
| 1636 | return (int) i + 1; |
| 1637 | } |
| 1638 | return 0; |
| 1639 | } |
| 1640 | struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) { |
| 1641 | size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]); |
| 1642 | for (i = 0; i < max && h->headers[i].name.len > 0; i++) { |
| 1643 | struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value; |
| 1644 | if (n == k->len && mg_ncasecmp(k->buf, name, n) == 0) return v; |
| 1645 | } |
| 1646 | return NULL; |
| 1647 | } |
| 1648 | |
| 1649 | // Is it a valid utf-8 continuation byte |
| 1650 | static bool vcb(uint8_t c) { |
| 1651 | return (c & 0xc0) == 0x80; |
| 1652 | } |
| 1653 | |
| 1654 | // Get character length (valid utf-8). Used to parse method, URI, headers |
| 1655 | static size_t clen(const char *s, const char *end) { |
| 1656 | const unsigned char *u = (unsigned char *) s, c = *u; |
| 1657 | long n = (long) (end - s); |
| 1658 | if (c > ' ' && c < '~') return 1; // Usual ascii printed char |
| 1659 | if ((c & 0xe0) == 0xc0 && n > 1 && vcb(u[1])) return 2; // 2-byte UTF8 |
| 1660 | if ((c & 0xf0) == 0xe0 && n > 2 && vcb(u[1]) && vcb(u[2])) return 3; |
| 1661 | if ((c & 0xf8) == 0xf0 && n > 3 && vcb(u[1]) && vcb(u[2]) && vcb(u[3])) |
| 1662 | return 4; |
| 1663 | return 0; |
| 1664 | } |
| 1665 | |
| 1666 | // Skip until the newline. Return advanced `s`, or NULL on error |
| 1667 | static const char *skiptorn(const char *s, const char *end, struct mg_str *v) { |
| 1668 | v->buf = (char *) s; |
| 1669 | while (s < end && s[0] != '\n' && s[0] != '\r') s++, v->len++; // To newline |
| 1670 | if (s >= end || (s[0] == '\r' && s[1] != '\n')) return NULL; // Stray \r |
| 1671 | if (s < end && s[0] == '\r') s++; // Skip \r |
| 1672 | if (s >= end || *s++ != '\n') return NULL; // Skip \n |
| 1673 | return s; |
| 1674 | } |
| 1675 | |
| 1676 | static bool mg_http_parse_headers(const char *s, const char *end, |
| 1677 | struct mg_http_header *h, size_t max_hdrs) { |
| 1678 | size_t i, n; |
| 1679 | for (i = 0; i < max_hdrs; i++) { |
| 1680 | struct mg_str k = {NULL, 0}, v = {NULL, 0}; |
| 1681 | if (s >= end) return false; |
| 1682 | if (s[0] == '\n' || (s[0] == '\r' && s[1] == '\n')) break; |
| 1683 | k.buf = (char *) s; |
| 1684 | while (s < end && s[0] != ':' && (n = clen(s, end)) > 0) s += n, k.len += n; |
| 1685 | if (k.len == 0) return false; // Empty name |
| 1686 | if (s >= end || clen(s, end) == 0) return false; // Invalid UTF-8 |
| 1687 | if (*s++ != ':') return false; // Invalid, not followed by : |
| 1688 | // if (clen(s, end) == 0) return false; // Invalid UTF-8 |
| 1689 | while (s < end && (s[0] == ' ' || s[0] == '\t')) s++; // Skip spaces |
| 1690 | if ((s = skiptorn(s, end, &v)) == NULL) return false; |
| 1691 | while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) { |
| 1692 | v.len--; // Trim spaces |
| 1693 | } |
| 1694 | // MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf)); |
| 1695 | h[i].name = k, h[i].value = v; // Success. Assign values |
| 1696 | } |
| 1697 | return true; |
| 1698 | } |
| 1699 | |
| 1700 | int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { |
| 1701 | int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len); |
| 1702 | const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL |
| 1703 | const struct mg_str *cl; |
| 1704 | size_t n; |
| 1705 | bool version_prefix_valid; |
| 1706 | |
| 1707 | memset(hm, 0, sizeof(*hm)); |
| 1708 | if (req_len <= 0) return req_len; |
| 1709 | |
| 1710 | hm->message.buf = hm->head.buf = (char *) s; |
| 1711 | hm->body.buf = (char *) end; |
| 1712 | hm->head.len = (size_t) req_len; |
| 1713 | hm->message.len = hm->body.len = (size_t) -1; // Set body length to infinite |
| 1714 | |
| 1715 | // Parse request line |
| 1716 | hm->method.buf = (char *) s; |
| 1717 | while (s < end && (n = clen(s, end)) > 0) s += n, hm->method.len += n; |
| 1718 | while (s < end && s[0] == ' ') s++; // Skip spaces |
| 1719 | hm->uri.buf = (char *) s; |
| 1720 | while (s < end && (n = clen(s, end)) > 0) s += n, hm->uri.len += n; |
| 1721 | while (s < end && s[0] == ' ') s++; // Skip spaces |
| 1722 | is_response = hm->method.len > 5 && |
| 1723 | (mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0); |
| 1724 | if ((s = skiptorn(s, end, &hm->proto)) == NULL) return false; |
| 1725 | // If we're given a version, check that it is HTTP/x.x |
| 1726 | version_prefix_valid = hm->proto.len > 5 && |
| 1727 | (mg_ncasecmp(hm->proto.buf, "HTTP/", 5) == 0); |
| 1728 | if (!is_response && hm->proto.len > 0 && |
| 1729 | (!version_prefix_valid || hm->proto.len != 8 || |
| 1730 | (hm->proto.buf[5] < '0' || hm->proto.buf[5] > '9') || |
| 1731 | (hm->proto.buf[6] != '.') || |
| 1732 | (hm->proto.buf[7] < '0' || hm->proto.buf[7] > '9'))) { |
| 1733 | return -1; |
| 1734 | } |
| 1735 | |
| 1736 | // If URI contains '?' character, setup query string |
| 1737 | if ((qs = (const char *) memchr(hm->uri.buf, '?', hm->uri.len)) != NULL) { |
| 1738 | hm->query.buf = (char *) qs + 1; |
| 1739 | hm->query.len = (size_t) (&hm->uri.buf[hm->uri.len] - (qs + 1)); |
| 1740 | hm->uri.len = (size_t) (qs - hm->uri.buf); |
| 1741 | } |
| 1742 | |
| 1743 | // Sanity check. Allow protocol/reason to be empty |
| 1744 | // Do this check after hm->method.len and hm->uri.len are finalised |
| 1745 | if (hm->method.len == 0 || hm->uri.len == 0) return -1; |
| 1746 | |
| 1747 | if (!mg_http_parse_headers(s, end, hm->headers, |
| 1748 | sizeof(hm->headers) / sizeof(hm->headers[0]))) |
| 1749 | return -1; // error when parsing |
| 1750 | if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { |
| 1751 | if (mg_to_size_t(*cl, &hm->body.len) == false) return -1; |
| 1752 | hm->message.len = (size_t) req_len + hm->body.len; |
| 1753 | } |
| 1754 | |
| 1755 | // mg_http_parse() is used to parse both HTTP requests and HTTP |
| 1756 | // responses. If HTTP response does not have Content-Length set, then |
| 1757 | // body is read until socket is closed, i.e. body.len is infinite (~0). |
| 1758 | // |
| 1759 | // For HTTP requests though, according to |
| 1760 | // http://tools.ietf.org/html/rfc7231#section-8.1.3, |
| 1761 | // only POST and PUT methods have defined body semantics. |
| 1762 | // Therefore, if Content-Length is not specified and methods are |
| 1763 | // not one of PUT or POST, set body length to 0. |
| 1764 | // |
| 1765 | // So, if it is HTTP request, and Content-Length is not set, |
| 1766 | // and method is not (PUT or POST) then reset body length to zero. |
| 1767 | if (hm->body.len == (size_t) ~0 && !is_response && |
| 1768 | mg_strcasecmp(hm->method, mg_str("PUT")) != 0 && |
| 1769 | mg_strcasecmp(hm->method, mg_str("POST")) != 0) { |
| 1770 | hm->body.len = 0; |
| 1771 | hm->message.len = (size_t) req_len; |
| 1772 | } |
| 1773 | |
| 1774 | // The 204 (No content) responses also have 0 body length |
| 1775 | if (hm->body.len == (size_t) ~0 && is_response && |
| 1776 | mg_strcasecmp(hm->uri, mg_str("204")) == 0) { |
| 1777 | hm->body.len = 0; |
| 1778 | hm->message.len = (size_t) req_len; |
| 1779 | } |
| 1780 | if (hm->message.len < (size_t) req_len) return -1; // Overflow protection |
| 1781 | |
| 1782 | return req_len; |
| 1783 | } |
| 1784 | |
| 1785 | static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt, |
| 1786 | va_list *ap) { |
| 1787 | size_t len = c->send.len; |
| 1788 | mg_send(c, " \r\n", 10); |
| 1789 | mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); |
| 1790 | if (c->send.len >= len + 10) { |
| 1791 | mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10); |
| 1792 | c->send.buf[len + 8] = '\r'; |
| 1793 | if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker |
| 1794 | } |
| 1795 | mg_send(c, "\r\n", 2); |
| 1796 | } |
| 1797 | |
| 1798 | void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) { |
| 1799 | va_list ap; |
| 1800 | va_start(ap, fmt); |
| 1801 | mg_http_vprintf_chunk(c, fmt, &ap); |
| 1802 | va_end(ap); |
| 1803 | } |
| 1804 | |
| 1805 | void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) { |
| 1806 | mg_printf(c, "%lx\r\n", (unsigned long) len); |
| 1807 | mg_send(c, buf, len); |
| 1808 | mg_send(c, "\r\n", 2); |
| 1809 | if (len == 0) c->is_resp = 0; |
| 1810 | } |
| 1811 | |
| 1812 | // clang-format off |
| 1813 | static const char *mg_http_status_code_str(int status_code) { |
| 1814 | switch (status_code) { |
| 1815 | case 100: return "Continue"; |
| 1816 | case 101: return "Switching Protocols"; |
| 1817 | case 102: return "Processing"; |
| 1818 | case 200: return "OK"; |
| 1819 | case 201: return "Created"; |
| 1820 | case 202: return "Accepted"; |
| 1821 | case 203: return "Non-authoritative Information"; |
| 1822 | case 204: return "No Content"; |
| 1823 | case 205: return "Reset Content"; |
| 1824 | case 206: return "Partial Content"; |
| 1825 | case 207: return "Multi-Status"; |
| 1826 | case 208: return "Already Reported"; |
| 1827 | case 226: return "IM Used"; |
| 1828 | case 300: return "Multiple Choices"; |
| 1829 | case 301: return "Moved Permanently"; |
| 1830 | case 302: return "Found"; |
| 1831 | case 303: return "See Other"; |
| 1832 | case 304: return "Not Modified"; |
| 1833 | case 305: return "Use Proxy"; |
| 1834 | case 307: return "Temporary Redirect"; |
| 1835 | case 308: return "Permanent Redirect"; |
| 1836 | case 400: return "Bad Request"; |
| 1837 | case 401: return "Unauthorized"; |
| 1838 | case 402: return "Payment Required"; |
| 1839 | case 403: return "Forbidden"; |
| 1840 | case 404: return "Not Found"; |
| 1841 | case 405: return "Method Not Allowed"; |
| 1842 | case 406: return "Not Acceptable"; |
| 1843 | case 407: return "Proxy Authentication Required"; |
| 1844 | case 408: return "Request Timeout"; |
| 1845 | case 409: return "Conflict"; |
| 1846 | case 410: return "Gone"; |
| 1847 | case 411: return "Length Required"; |
| 1848 | case 412: return "Precondition Failed"; |
| 1849 | case 413: return "Payload Too Large"; |
| 1850 | case 414: return "Request-URI Too Long"; |
| 1851 | case 415: return "Unsupported Media Type"; |
| 1852 | case 416: return "Requested Range Not Satisfiable"; |
| 1853 | case 417: return "Expectation Failed"; |
| 1854 | case 418: return "I'm a teapot"; |
| 1855 | case 421: return "Misdirected Request"; |
| 1856 | case 422: return "Unprocessable Entity"; |
| 1857 | case 423: return "Locked"; |
| 1858 | case 424: return "Failed Dependency"; |
| 1859 | case 426: return "Upgrade Required"; |
| 1860 | case 428: return "Precondition Required"; |
| 1861 | case 429: return "Too Many Requests"; |
| 1862 | case 431: return "Request Header Fields Too Large"; |
| 1863 | case 444: return "Connection Closed Without Response"; |
| 1864 | case 451: return "Unavailable For Legal Reasons"; |
| 1865 | case 499: return "Client Closed Request"; |
| 1866 | case 500: return "Internal Server Error"; |
| 1867 | case 501: return "Not Implemented"; |
| 1868 | case 502: return "Bad Gateway"; |
| 1869 | case 503: return "Service Unavailable"; |
| 1870 | case 504: return "Gateway Timeout"; |
| 1871 | case 505: return "HTTP Version Not Supported"; |
| 1872 | case 506: return "Variant Also Negotiates"; |
| 1873 | case 507: return "Insufficient Storage"; |
| 1874 | case 508: return "Loop Detected"; |
| 1875 | case 510: return "Not Extended"; |
| 1876 | case 511: return "Network Authentication Required"; |
| 1877 | case 599: return "Network Connect Timeout Error"; |
| 1878 | default: return ""; |
| 1879 | } |
| 1880 | } |
| 1881 | // clang-format on |
| 1882 | |
| 1883 | void mg_http_reply(struct mg_connection *c, int code, const char *headers, |
| 1884 | const char *fmt, ...) { |
| 1885 | va_list ap; |
| 1886 | size_t len; |
| 1887 | mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: \r\n\r\n", code, |
| 1888 | mg_http_status_code_str(code), headers == NULL ? "" : headers); |
| 1889 | len = c->send.len; |
| 1890 | va_start(ap, fmt); |
| 1891 | mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap); |
| 1892 | va_end(ap); |
| 1893 | if (c->send.len > 16) { |
| 1894 | size_t n = mg_snprintf((char *) &c->send.buf[len - 15], 11, "%-10lu", |
| 1895 | (unsigned long) (c->send.len - len)); |
| 1896 | c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space |
| 1897 | } |
| 1898 | c->is_resp = 0; |
| 1899 | } |
| 1900 | |
| 1901 | static void http_cb(struct mg_connection *, int, void *); |
| 1902 | static void restore_http_cb(struct mg_connection *c) { |
| 1903 | mg_fs_close((struct mg_fd *) c->pfn_data); |
| 1904 | c->pfn_data = NULL; |
| 1905 | c->pfn = http_cb; |
| 1906 | c->is_resp = 0; |
| 1907 | } |
| 1908 | |
| 1909 | char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime); |
| 1910 | char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) { |
| 1911 | mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size); |
| 1912 | return buf; |
| 1913 | } |
| 1914 | |
| 1915 | static void static_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 1916 | if (ev == MG_EV_WRITE || ev == MG_EV_POLL) { |
| 1917 | struct mg_fd *fd = (struct mg_fd *) c->pfn_data; |
| 1918 | // Read to send IO buffer directly, avoid extra on-stack buffer |
| 1919 | size_t n, max = MG_IO_SIZE, space; |
| 1920 | size_t *cl = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) / |
| 1921 | sizeof(size_t) * sizeof(size_t)]; |
| 1922 | if (c->send.size < max) mg_iobuf_resize(&c->send, max); |
| 1923 | if (c->send.len >= c->send.size) return; // Rate limit |
| 1924 | if ((space = c->send.size - c->send.len) > *cl) space = *cl; |
| 1925 | n = fd->fs->rd(fd->fd, c->send.buf + c->send.len, space); |
| 1926 | c->send.len += n; |
| 1927 | *cl -= n; |
| 1928 | if (n == 0) restore_http_cb(c); |
| 1929 | } else if (ev == MG_EV_CLOSE) { |
| 1930 | restore_http_cb(c); |
| 1931 | } |
| 1932 | (void) ev_data; |
| 1933 | } |
| 1934 | |
| 1935 | // Known mime types. Keep it outside guess_content_type() function, since |
| 1936 | // some environments don't like it defined there. |
| 1937 | // clang-format off |
| 1938 | #define MG_C_STR(a) { (char *) (a), sizeof(a) - 1 } |
| 1939 | static struct mg_str s_known_types[] = { |
| 1940 | MG_C_STR("html"), MG_C_STR("text/html; charset=utf-8"), |
| 1941 | MG_C_STR("htm"), MG_C_STR("text/html; charset=utf-8"), |
| 1942 | MG_C_STR("css"), MG_C_STR("text/css; charset=utf-8"), |
| 1943 | MG_C_STR("js"), MG_C_STR("text/javascript; charset=utf-8"), |
| 1944 | MG_C_STR("mjs"), MG_C_STR("text/javascript; charset=utf-8"), |
| 1945 | MG_C_STR("gif"), MG_C_STR("image/gif"), |
| 1946 | MG_C_STR("png"), MG_C_STR("image/png"), |
| 1947 | MG_C_STR("jpg"), MG_C_STR("image/jpeg"), |
| 1948 | MG_C_STR("jpeg"), MG_C_STR("image/jpeg"), |
| 1949 | MG_C_STR("woff"), MG_C_STR("font/woff"), |
| 1950 | MG_C_STR("ttf"), MG_C_STR("font/ttf"), |
| 1951 | MG_C_STR("svg"), MG_C_STR("image/svg+xml"), |
| 1952 | MG_C_STR("txt"), MG_C_STR("text/plain; charset=utf-8"), |
| 1953 | MG_C_STR("avi"), MG_C_STR("video/x-msvideo"), |
| 1954 | MG_C_STR("csv"), MG_C_STR("text/csv"), |
| 1955 | MG_C_STR("doc"), MG_C_STR("application/msword"), |
| 1956 | MG_C_STR("exe"), MG_C_STR("application/octet-stream"), |
| 1957 | MG_C_STR("gz"), MG_C_STR("application/gzip"), |
| 1958 | MG_C_STR("ico"), MG_C_STR("image/x-icon"), |
| 1959 | MG_C_STR("json"), MG_C_STR("application/json"), |
| 1960 | MG_C_STR("mov"), MG_C_STR("video/quicktime"), |
| 1961 | MG_C_STR("mp3"), MG_C_STR("audio/mpeg"), |
| 1962 | MG_C_STR("mp4"), MG_C_STR("video/mp4"), |
| 1963 | MG_C_STR("mpeg"), MG_C_STR("video/mpeg"), |
| 1964 | MG_C_STR("pdf"), MG_C_STR("application/pdf"), |
| 1965 | MG_C_STR("shtml"), MG_C_STR("text/html; charset=utf-8"), |
| 1966 | MG_C_STR("tgz"), MG_C_STR("application/tar-gz"), |
| 1967 | MG_C_STR("wav"), MG_C_STR("audio/wav"), |
| 1968 | MG_C_STR("webp"), MG_C_STR("image/webp"), |
| 1969 | MG_C_STR("zip"), MG_C_STR("application/zip"), |
| 1970 | MG_C_STR("3gp"), MG_C_STR("video/3gpp"), |
| 1971 | {0, 0}, |
| 1972 | }; |
| 1973 | // clang-format on |
| 1974 | |
| 1975 | static struct mg_str guess_content_type(struct mg_str path, const char *extra) { |
| 1976 | struct mg_str entry, k, v, s = mg_str(extra), asterisk = mg_str_n("*", 1); |
| 1977 | size_t i = 0; |
| 1978 | |
| 1979 | // Shrink path to its extension only |
| 1980 | while (i < path.len && path.buf[path.len - i - 1] != '.') i++; |
| 1981 | path.buf += path.len - i; |
| 1982 | path.len = i; |
| 1983 | |
| 1984 | // Process user-provided mime type overrides, if any |
| 1985 | while (mg_span(s, &entry, &s, ',')) { |
| 1986 | if (mg_span(entry, &k, &v, '=') && |
| 1987 | (mg_strcmp(asterisk, k) == 0 || mg_strcmp(path, k) == 0)) |
| 1988 | return v; |
| 1989 | } |
| 1990 | |
| 1991 | // Process built-in mime types |
| 1992 | for (i = 0; s_known_types[i].buf != NULL; i += 2) { |
| 1993 | if (mg_strcmp(path, s_known_types[i]) == 0) return s_known_types[i + 1]; |
| 1994 | } |
| 1995 | |
| 1996 | return mg_str("text/plain; charset=utf-8"); |
| 1997 | } |
| 1998 | |
| 1999 | static int getrange(struct mg_str *s, size_t *a, size_t *b) { |
| 2000 | size_t i, numparsed = 0; |
| 2001 | for (i = 0; i + 6 < s->len; i++) { |
| 2002 | struct mg_str k, v = mg_str_n(s->buf + i + 6, s->len - i - 6); |
| 2003 | if (memcmp(&s->buf[i], "bytes=", 6) != 0) continue; |
| 2004 | if (mg_span(v, &k, &v, '-')) { |
| 2005 | if (mg_to_size_t(k, a)) numparsed++; |
| 2006 | if (v.len > 0 && mg_to_size_t(v, b)) numparsed++; |
| 2007 | } else { |
| 2008 | if (mg_to_size_t(v, a)) numparsed++; |
| 2009 | } |
| 2010 | break; |
| 2011 | } |
| 2012 | return (int) numparsed; |
| 2013 | } |
| 2014 | |
| 2015 | void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, |
| 2016 | const char *path, |
| 2017 | const struct mg_http_serve_opts *opts) { |
| 2018 | char etag[64], tmp[MG_PATH_MAX]; |
| 2019 | struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; |
| 2020 | struct mg_fd *fd = NULL; |
| 2021 | size_t size = 0; |
| 2022 | time_t mtime = 0; |
| 2023 | struct mg_str *inm = NULL; |
| 2024 | struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types); |
| 2025 | bool gzip = false; |
| 2026 | |
| 2027 | if (path != NULL) { |
| 2028 | // If a browser sends us "Accept-Encoding: gzip", try to open .gz first |
| 2029 | struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding"); |
| 2030 | if (ae != NULL) { |
| 2031 | char *ae_ = mg_mprintf("%.*s", ae->len, ae->buf); |
| 2032 | if (ae_ != NULL && strstr(ae_, "gzip") != NULL) { |
| 2033 | mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); |
| 2034 | fd = mg_fs_open(fs, tmp, MG_FS_READ); |
| 2035 | if (fd != NULL) gzip = true, path = tmp; |
| 2036 | } |
| 2037 | free(ae_); |
| 2038 | } |
| 2039 | // No luck opening .gz? Open what we've told to open |
| 2040 | if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ); |
| 2041 | } |
| 2042 | |
| 2043 | // Failed to open, and page404 is configured? Open it, then |
| 2044 | if (fd == NULL && opts->page404 != NULL) { |
| 2045 | fd = mg_fs_open(fs, opts->page404, MG_FS_READ); |
| 2046 | path = opts->page404; |
| 2047 | mime = guess_content_type(mg_str(path), opts->mime_types); |
| 2048 | } |
| 2049 | |
| 2050 | if (fd == NULL || fs->st(path, &size, &mtime) == 0) { |
| 2051 | mg_http_reply(c, 404, opts->extra_headers, "Not found\n"); |
| 2052 | mg_fs_close(fd); |
| 2053 | // NOTE: mg_http_etag() call should go first! |
| 2054 | } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL && |
| 2055 | (inm = mg_http_get_header(hm, "If-None-Match")) != NULL && |
| 2056 | mg_strcasecmp(*inm, mg_str(etag)) == 0) { |
| 2057 | mg_fs_close(fd); |
| 2058 | mg_http_reply(c, 304, opts->extra_headers, ""); |
| 2059 | } else { |
| 2060 | int n, status = 200; |
| 2061 | char range[100]; |
| 2062 | size_t r1 = 0, r2 = 0, cl = size; |
| 2063 | |
| 2064 | // Handle Range header |
| 2065 | struct mg_str *rh = mg_http_get_header(hm, "Range"); |
| 2066 | range[0] = '\0'; |
| 2067 | if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) { |
| 2068 | // If range is specified like "400-", set second limit to content len |
| 2069 | if (n == 1) r2 = cl - 1; |
| 2070 | if (r1 > r2 || r2 >= cl) { |
| 2071 | status = 416; |
| 2072 | cl = 0; |
| 2073 | mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n", |
| 2074 | (int64_t) size); |
| 2075 | } else { |
| 2076 | status = 206; |
| 2077 | cl = r2 - r1 + 1; |
| 2078 | mg_snprintf(range, sizeof(range), |
| 2079 | "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1, |
| 2080 | (uint64_t) (r1 + cl - 1), (uint64_t) size); |
| 2081 | fs->sk(fd->fd, r1); |
| 2082 | } |
| 2083 | } |
| 2084 | mg_printf(c, |
| 2085 | "HTTP/1.1 %d %s\r\n" |
| 2086 | "Content-Type: %.*s\r\n" |
| 2087 | "Etag: %s\r\n" |
| 2088 | "Content-Length: %llu\r\n" |
| 2089 | "%s%s%s\r\n", |
| 2090 | status, mg_http_status_code_str(status), (int) mime.len, mime.buf, |
| 2091 | etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", |
| 2092 | range, opts->extra_headers ? opts->extra_headers : ""); |
| 2093 | if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) { |
| 2094 | c->is_resp = 0; |
| 2095 | mg_fs_close(fd); |
| 2096 | } else { |
| 2097 | // Track to-be-sent content length at the end of c->data, aligned |
| 2098 | size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) / |
| 2099 | sizeof(size_t) * sizeof(size_t)]; |
| 2100 | c->pfn = static_cb; |
| 2101 | c->pfn_data = fd; |
| 2102 | *clp = cl; |
| 2103 | } |
| 2104 | } |
| 2105 | } |
| 2106 | |
| 2107 | struct printdirentrydata { |
| 2108 | struct mg_connection *c; |
| 2109 | struct mg_http_message *hm; |
| 2110 | const struct mg_http_serve_opts *opts; |
| 2111 | const char *dir; |
| 2112 | }; |
| 2113 | |
| 2114 | #if MG_ENABLE_DIRLIST |
| 2115 | static void printdirentry(const char *name, void *userdata) { |
| 2116 | struct printdirentrydata *d = (struct printdirentrydata *) userdata; |
| 2117 | struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs; |
| 2118 | size_t size = 0; |
| 2119 | time_t t = 0; |
| 2120 | char path[MG_PATH_MAX], sz[40], mod[40]; |
| 2121 | int flags, n = 0; |
| 2122 | |
| 2123 | // MG_DEBUG(("[%s] [%s]", d->dir, name)); |
| 2124 | if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) > |
| 2125 | sizeof(path)) { |
| 2126 | MG_ERROR(("%s truncated", name)); |
| 2127 | } else if ((flags = fs->st(path, &size, &t)) == 0) { |
| 2128 | MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno)); |
| 2129 | } else { |
| 2130 | const char *slash = flags & MG_FS_DIR ? "/" : ""; |
| 2131 | if (flags & MG_FS_DIR) { |
| 2132 | mg_snprintf(sz, sizeof(sz), "%s", "[DIR]"); |
| 2133 | } else { |
| 2134 | mg_snprintf(sz, sizeof(sz), "%lld", (uint64_t) size); |
| 2135 | } |
| 2136 | #if defined(MG_HTTP_DIRLIST_TIME_FMT) |
| 2137 | { |
| 2138 | char time_str[40]; |
| 2139 | struct tm *time_info = localtime(&t); |
| 2140 | strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info); |
| 2141 | mg_snprintf(mod, sizeof(mod), "%s", time_str); |
| 2142 | } |
| 2143 | #else |
| 2144 | mg_snprintf(mod, sizeof(mod), "%lu", (unsigned long) t); |
| 2145 | #endif |
| 2146 | n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); |
| 2147 | mg_printf(d->c, |
| 2148 | " <tr><td><a href=\"%.*s%s\">%s%s</a></td>" |
| 2149 | "<td name=%lu>%s</td><td name=%lld>%s</td></tr>\n", |
| 2150 | n, path, slash, name, slash, (unsigned long) t, mod, |
| 2151 | flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz); |
| 2152 | } |
| 2153 | } |
| 2154 | |
| 2155 | static void listdir(struct mg_connection *c, struct mg_http_message *hm, |
| 2156 | const struct mg_http_serve_opts *opts, char *dir) { |
| 2157 | const char *sort_js_code = |
| 2158 | "<script>function srt(tb, sc, so, d) {" |
| 2159 | "var tr = Array.prototype.slice.call(tb.rows, 0)," |
| 2160 | "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc]," |
| 2161 | "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), " |
| 2162 | "t1 = a.cells[2].getAttribute('name'), " |
| 2163 | "t2 = b.cells[2].getAttribute('name'); " |
| 2164 | "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : " |
| 2165 | "n1 ? parseInt(n2) - parseInt(n1) : " |
| 2166 | "c1.textContent.trim().localeCompare(c2.textContent.trim())); });"; |
| 2167 | const char *sort_js_code2 = |
| 2168 | "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); " |
| 2169 | "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); " |
| 2170 | "};" |
| 2171 | "window.onload = function() {" |
| 2172 | "var tb = document.getElementById('tb');" |
| 2173 | "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];" |
| 2174 | "var sc = m[1], so = m[2]; document.onclick = function(ev) { " |
| 2175 | "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); " |
| 2176 | "sc = c; ev.preventDefault();}};" |
| 2177 | "srt(tb, sc, so, true);" |
| 2178 | "}" |
| 2179 | "</script>"; |
| 2180 | struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; |
| 2181 | struct printdirentrydata d = {c, hm, opts, dir}; |
| 2182 | char tmp[10], buf[MG_PATH_MAX]; |
| 2183 | size_t off, n; |
| 2184 | int len = mg_url_decode(hm->uri.buf, hm->uri.len, buf, sizeof(buf), 0); |
| 2185 | struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri; |
| 2186 | |
| 2187 | mg_printf(c, |
| 2188 | "HTTP/1.1 200 OK\r\n" |
| 2189 | "Content-Type: text/html; charset=utf-8\r\n" |
| 2190 | "%s" |
| 2191 | "Content-Length: \r\n\r\n", |
| 2192 | opts->extra_headers == NULL ? "" : opts->extra_headers); |
| 2193 | off = c->send.len; // Start of body |
| 2194 | mg_printf(c, |
| 2195 | "<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s" |
| 2196 | "<style>th,td {text-align: left; padding-right: 1em; " |
| 2197 | "font-family: monospace; }</style></head>" |
| 2198 | "<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>" |
| 2199 | "<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>" |
| 2200 | "<a href=\"#\" rel=\"1\">Modified</a></th>" |
| 2201 | "<th><a href=\"#\" rel=\"2\">Size</a></th></tr>" |
| 2202 | "<tr><td colspan=\"3\"><hr></td></tr>" |
| 2203 | "</thead>" |
| 2204 | "<tbody id=\"tb\">\n", |
| 2205 | (int) uri.len, uri.buf, sort_js_code, sort_js_code2, (int) uri.len, |
| 2206 | uri.buf); |
| 2207 | mg_printf(c, "%s", |
| 2208 | " <tr><td><a href=\"..\">..</a></td>" |
| 2209 | "<td name=-1></td><td name=-1>[DIR]</td></tr>\n"); |
| 2210 | |
| 2211 | fs->ls(dir, printdirentry, &d); |
| 2212 | mg_printf(c, |
| 2213 | "</tbody><tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>" |
| 2214 | "</table><address>Mongoose v.%s</address></body></html>\n", |
| 2215 | MG_VERSION); |
| 2216 | n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); |
| 2217 | if (n > sizeof(tmp)) n = 0; |
| 2218 | memcpy(c->send.buf + off - 12, tmp, n); // Set content length |
| 2219 | c->is_resp = 0; // Mark response end |
| 2220 | } |
| 2221 | #endif |
| 2222 | |
| 2223 | // Resolve requested file into `path` and return its fs->st() result |
| 2224 | static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, |
| 2225 | struct mg_fs *fs, struct mg_str url, struct mg_str dir, |
| 2226 | char *path, size_t path_size) { |
| 2227 | int flags, tmp; |
| 2228 | // Append URI to the root_dir, and sanitize it |
| 2229 | size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.buf); |
| 2230 | if (n + 2 >= path_size) { |
| 2231 | mg_http_reply(c, 400, "", "Exceeded path size"); |
| 2232 | return -1; |
| 2233 | } |
| 2234 | path[path_size - 1] = '\0'; |
| 2235 | // Terminate root dir with slash |
| 2236 | if (n > 0 && path[n - 1] != '/') path[n++] = '/', path[n] = '\0'; |
| 2237 | if (url.len < hm->uri.len) { |
| 2238 | mg_url_decode(hm->uri.buf + url.len, hm->uri.len - url.len, path + n, |
| 2239 | path_size - n, 0); |
| 2240 | } |
| 2241 | path[path_size - 1] = '\0'; // Double-check |
| 2242 | if (!mg_path_is_sane(mg_str_n(path, path_size))) { |
| 2243 | mg_http_reply(c, 400, "", "Invalid path"); |
| 2244 | return -1; |
| 2245 | } |
| 2246 | n = strlen(path); |
| 2247 | while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes |
| 2248 | flags = mg_strcmp(hm->uri, mg_str("/")) == 0 ? MG_FS_DIR |
| 2249 | : fs->st(path, NULL, NULL); |
| 2250 | MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.buf, path, |
| 2251 | flags)); |
| 2252 | if (flags == 0) { |
| 2253 | // Do nothing - let's caller decide |
| 2254 | } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 && |
| 2255 | hm->uri.buf[hm->uri.len - 1] != '/') { |
| 2256 | mg_printf(c, |
| 2257 | "HTTP/1.1 301 Moved\r\n" |
| 2258 | "Location: %.*s/\r\n" |
| 2259 | "Content-Length: 0\r\n" |
| 2260 | "\r\n", |
| 2261 | (int) hm->uri.len, hm->uri.buf); |
| 2262 | c->is_resp = 0; |
| 2263 | flags = -1; |
| 2264 | } else if (flags & MG_FS_DIR) { |
| 2265 | if (((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX) > 0 && |
| 2266 | (tmp = fs->st(path, NULL, NULL)) != 0) || |
| 2267 | (mg_snprintf(path + n, path_size - n, "/index.shtml") > 0 && |
| 2268 | (tmp = fs->st(path, NULL, NULL)) != 0))) { |
| 2269 | flags = tmp; |
| 2270 | } else if ((mg_snprintf(path + n, path_size - n, "/" MG_HTTP_INDEX ".gz") > |
| 2271 | 0 && |
| 2272 | (tmp = fs->st(path, NULL, NULL)) != |
| 2273 | 0)) { // check for gzipped index |
| 2274 | flags = tmp; |
| 2275 | path[n + 1 + strlen(MG_HTTP_INDEX)] = |
| 2276 | '\0'; // Remove appended .gz in index file name |
| 2277 | } else { |
| 2278 | path[n] = '\0'; // Remove appended index file name |
| 2279 | } |
| 2280 | } |
| 2281 | return flags; |
| 2282 | } |
| 2283 | |
| 2284 | static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm, |
| 2285 | const struct mg_http_serve_opts *opts, char *path, |
| 2286 | size_t path_size) { |
| 2287 | struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; |
| 2288 | struct mg_str k, v, part, s = mg_str(opts->root_dir), u = {NULL, 0}, p = u; |
| 2289 | while (mg_span(s, &part, &s, ',')) { |
| 2290 | if (!mg_span(part, &k, &v, '=')) k = part, v = mg_str_n(NULL, 0); |
| 2291 | if (v.len == 0) v = k, k = mg_str("/"), u = k, p = v; |
| 2292 | if (hm->uri.len < k.len) continue; |
| 2293 | if (mg_strcmp(k, mg_str_n(hm->uri.buf, k.len)) != 0) continue; |
| 2294 | u = k, p = v; |
| 2295 | } |
| 2296 | return uri_to_path2(c, hm, fs, u, p, path, path_size); |
| 2297 | } |
| 2298 | |
| 2299 | void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm, |
| 2300 | const struct mg_http_serve_opts *opts) { |
| 2301 | char path[MG_PATH_MAX]; |
| 2302 | const char *sp = opts->ssi_pattern; |
| 2303 | int flags = uri_to_path(c, hm, opts, path, sizeof(path)); |
| 2304 | if (flags < 0) { |
| 2305 | // Do nothing: the response has already been sent by uri_to_path() |
| 2306 | } else if (flags & MG_FS_DIR) { |
| 2307 | #if MG_ENABLE_DIRLIST |
| 2308 | listdir(c, hm, opts, path); |
| 2309 | #else |
| 2310 | mg_http_reply(c, 403, "", "Forbidden\n"); |
| 2311 | #endif |
| 2312 | } else if (flags && sp != NULL && mg_match(mg_str(path), mg_str(sp), NULL)) { |
| 2313 | mg_http_serve_ssi(c, opts->root_dir, path); |
| 2314 | } else { |
| 2315 | mg_http_serve_file(c, hm, path, opts); |
| 2316 | } |
| 2317 | } |
| 2318 | |
| 2319 | static bool mg_is_url_safe(int c) { |
| 2320 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || |
| 2321 | (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~'; |
| 2322 | } |
| 2323 | |
| 2324 | size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { |
| 2325 | size_t i, n = 0; |
| 2326 | for (i = 0; i < sl; i++) { |
| 2327 | int c = *(unsigned char *) &s[i]; |
| 2328 | if (n + 4 >= len) return 0; |
| 2329 | if (mg_is_url_safe(c)) { |
| 2330 | buf[n++] = s[i]; |
| 2331 | } else { |
| 2332 | mg_snprintf(&buf[n], 4, "%%%M", mg_print_hex, 1, &s[i]); |
| 2333 | n += 3; |
| 2334 | } |
| 2335 | } |
| 2336 | if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination |
| 2337 | if (len > 0) buf[len - 1] = '\0'; // Always. |
| 2338 | return n; |
| 2339 | } |
| 2340 | |
| 2341 | void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen, |
| 2342 | char *pass, size_t passlen) { |
| 2343 | struct mg_str *v = mg_http_get_header(hm, "Authorization"); |
| 2344 | user[0] = pass[0] = '\0'; |
| 2345 | if (v != NULL && v->len > 6 && memcmp(v->buf, "Basic ", 6) == 0) { |
| 2346 | char buf[256]; |
| 2347 | size_t n = mg_base64_decode(v->buf + 6, v->len - 6, buf, sizeof(buf)); |
| 2348 | const char *p = (const char *) memchr(buf, ':', n > 0 ? n : 0); |
| 2349 | if (p != NULL) { |
| 2350 | mg_snprintf(user, userlen, "%.*s", p - buf, buf); |
| 2351 | mg_snprintf(pass, passlen, "%.*s", n - (size_t) (p - buf) - 1, p + 1); |
| 2352 | } |
| 2353 | } else if (v != NULL && v->len > 7 && memcmp(v->buf, "Bearer ", 7) == 0) { |
| 2354 | mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->buf + 7); |
| 2355 | } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) { |
| 2356 | struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12)); |
| 2357 | if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.buf); |
| 2358 | } else { |
| 2359 | mg_http_get_var(&hm->query, "access_token", pass, passlen); |
| 2360 | } |
| 2361 | } |
| 2362 | |
| 2363 | static struct mg_str stripquotes(struct mg_str s) { |
| 2364 | return s.len > 1 && s.buf[0] == '"' && s.buf[s.len - 1] == '"' |
| 2365 | ? mg_str_n(s.buf + 1, s.len - 2) |
| 2366 | : s; |
| 2367 | } |
| 2368 | |
| 2369 | struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { |
| 2370 | size_t i; |
| 2371 | for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) { |
| 2372 | if (s.buf[i + v.len] == '=' && memcmp(&s.buf[i], v.buf, v.len) == 0) { |
| 2373 | const char *p = &s.buf[i + v.len + 1], *b = p, *x = &s.buf[s.len]; |
| 2374 | int q = p < x && *p == '"' ? 1 : 0; |
| 2375 | while (p < x && |
| 2376 | (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ',')) |
| 2377 | p++; |
| 2378 | // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.buf, (int) v.len, |
| 2379 | // v.buf, (int) (p - b), b)); |
| 2380 | return stripquotes(mg_str_n(b, (size_t) (p - b + q))); |
| 2381 | } |
| 2382 | } |
| 2383 | return mg_str_n(NULL, 0); |
| 2384 | } |
| 2385 | |
| 2386 | long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, |
| 2387 | struct mg_fs *fs, const char *dir, size_t max_size) { |
| 2388 | char buf[20] = "0", file[MG_PATH_MAX], path[MG_PATH_MAX]; |
| 2389 | long res = 0, offset; |
| 2390 | mg_http_get_var(&hm->query, "offset", buf, sizeof(buf)); |
| 2391 | mg_http_get_var(&hm->query, "file", file, sizeof(file)); |
| 2392 | offset = strtol(buf, NULL, 0); |
| 2393 | mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, file); |
| 2394 | if (hm->body.len == 0) { |
| 2395 | mg_http_reply(c, 200, "", "%ld", res); // Nothing to write |
| 2396 | } else if (file[0] == '\0') { |
| 2397 | mg_http_reply(c, 400, "", "file required"); |
| 2398 | res = -1; |
| 2399 | } else if (mg_path_is_sane(mg_str(file)) == false) { |
| 2400 | mg_http_reply(c, 400, "", "%s: invalid file", file); |
| 2401 | res = -2; |
| 2402 | } else if (offset < 0) { |
| 2403 | mg_http_reply(c, 400, "", "offset required"); |
| 2404 | res = -3; |
| 2405 | } else if ((size_t) offset + hm->body.len > max_size) { |
| 2406 | mg_http_reply(c, 400, "", "%s: over max size of %lu", path, |
| 2407 | (unsigned long) max_size); |
| 2408 | res = -4; |
| 2409 | } else { |
| 2410 | struct mg_fd *fd; |
| 2411 | size_t current_size = 0; |
| 2412 | MG_DEBUG(("%s -> %lu bytes @ %ld", path, hm->body.len, offset)); |
| 2413 | if (offset == 0) fs->rm(path); // If offset if 0, truncate file |
| 2414 | fs->st(path, ¤t_size, NULL); |
| 2415 | if (offset > 0 && current_size != (size_t) offset) { |
| 2416 | mg_http_reply(c, 400, "", "%s: offset mismatch", path); |
| 2417 | res = -5; |
| 2418 | } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { |
| 2419 | mg_http_reply(c, 400, "", "open(%s): %d", path, errno); |
| 2420 | res = -6; |
| 2421 | } else { |
| 2422 | res = offset + (long) fs->wr(fd->fd, hm->body.buf, hm->body.len); |
| 2423 | mg_fs_close(fd); |
| 2424 | mg_http_reply(c, 200, "", "%ld", res); |
| 2425 | } |
| 2426 | } |
| 2427 | return res; |
| 2428 | } |
| 2429 | |
| 2430 | int mg_http_status(const struct mg_http_message *hm) { |
| 2431 | return atoi(hm->uri.buf); |
| 2432 | } |
| 2433 | |
| 2434 | static bool is_hex_digit(int c) { |
| 2435 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || |
| 2436 | (c >= 'A' && c <= 'F'); |
| 2437 | } |
| 2438 | |
| 2439 | static int skip_chunk(const char *buf, int len, int *pl, int *dl) { |
| 2440 | int i = 0, n = 0; |
| 2441 | if (len < 3) return 0; |
| 2442 | while (i < len && is_hex_digit(buf[i])) i++; |
| 2443 | if (i == 0) return -1; // Error, no length specified |
| 2444 | if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big |
| 2445 | if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error |
| 2446 | if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false) |
| 2447 | return -1; // Decode chunk length, overflow |
| 2448 | if (n < 0) return -1; // Error. TODO(): some checks now redundant |
| 2449 | if (n > len - i - 4) return 0; // Chunk not yet fully buffered |
| 2450 | if (buf[i + n + 2] != '\r' || buf[i + n + 3] != '\n') return -1; // Error |
| 2451 | *pl = i + 2, *dl = n; |
| 2452 | return i + 2 + n + 2; |
| 2453 | } |
| 2454 | |
| 2455 | static void http_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 2456 | if (ev == MG_EV_READ || ev == MG_EV_CLOSE || |
| 2457 | (ev == MG_EV_POLL && c->is_accepted && !c->is_draining && |
| 2458 | c->recv.len > 0)) { // see #2796 |
| 2459 | struct mg_http_message hm; |
| 2460 | size_t ofs = 0; // Parsing offset |
| 2461 | while (c->is_resp == 0 && ofs < c->recv.len) { |
| 2462 | const char *buf = (char *) c->recv.buf + ofs; |
| 2463 | int n = mg_http_parse(buf, c->recv.len - ofs, &hm); |
| 2464 | struct mg_str *te; // Transfer - encoding header |
| 2465 | bool is_chunked = false; |
| 2466 | size_t old_len = c->recv.len; |
| 2467 | if (n < 0) { |
| 2468 | // We don't use mg_error() here, to avoid closing pipelined requests |
| 2469 | // prematurely, see #2592 |
| 2470 | MG_ERROR(("HTTP parse, %lu bytes", c->recv.len)); |
| 2471 | c->is_draining = 1; |
| 2472 | mg_hexdump(buf, c->recv.len - ofs > 16 ? 16 : c->recv.len - ofs); |
| 2473 | c->recv.len = 0; |
| 2474 | return; |
| 2475 | } |
| 2476 | if (n == 0) break; // Request is not buffered yet |
| 2477 | mg_call(c, MG_EV_HTTP_HDRS, &hm); // Got all HTTP headers |
| 2478 | if (c->recv.len != old_len) { |
| 2479 | // User manipulated received data. Wash our hands |
| 2480 | MG_DEBUG(("%lu detaching HTTP handler", c->id)); |
| 2481 | c->pfn = NULL; |
| 2482 | return; |
| 2483 | } |
| 2484 | if (ev == MG_EV_CLOSE) { // If client did not set Content-Length |
| 2485 | hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG |
| 2486 | hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); |
| 2487 | } |
| 2488 | if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) { |
| 2489 | if (mg_strcasecmp(*te, mg_str("chunked")) == 0) { |
| 2490 | is_chunked = true; |
| 2491 | } else { |
| 2492 | mg_error(c, "Invalid Transfer-Encoding"); // See #2460 |
| 2493 | return; |
| 2494 | } |
| 2495 | } else if (mg_http_get_header(&hm, "Content-length") == NULL) { |
| 2496 | // #2593: HTTP packets must contain either Transfer-Encoding or |
| 2497 | // Content-length |
| 2498 | bool is_response = mg_ncasecmp(hm.method.buf, "HTTP/", 5) == 0; |
| 2499 | bool require_content_len = false; |
| 2500 | if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 || |
| 2501 | mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) { |
| 2502 | // POST and PUT should include an entity body. Therefore, they should |
| 2503 | // contain a Content-length header. Other requests can also contain a |
| 2504 | // body, but their content has no defined semantics (RFC 7231) |
| 2505 | require_content_len = true; |
| 2506 | ofs += (size_t) n; // this request has been processed |
| 2507 | } else if (is_response) { |
| 2508 | // HTTP spec 7.2 Entity body: All other responses must include a body |
| 2509 | // or Content-Length header field defined with a value of 0. |
| 2510 | int status = mg_http_status(&hm); |
| 2511 | require_content_len = status >= 200 && status != 204 && status != 304; |
| 2512 | } |
| 2513 | if (require_content_len) { |
| 2514 | if (!c->is_client) mg_http_reply(c, 411, "", ""); |
| 2515 | MG_ERROR(("Content length missing from %s", is_response ? "response" : "request")); |
| 2516 | } |
| 2517 | } |
| 2518 | |
| 2519 | if (is_chunked) { |
| 2520 | // For chunked data, strip off prefixes and suffixes from chunks |
| 2521 | // and relocate them right after the headers, then report a message |
| 2522 | char *s = (char *) c->recv.buf + ofs + n; |
| 2523 | int o = 0, pl, dl, cl, len = (int) (c->recv.len - ofs - (size_t) n); |
| 2524 | |
| 2525 | // Find zero-length chunk (the end of the body) |
| 2526 | while ((cl = skip_chunk(s + o, len - o, &pl, &dl)) > 0 && dl) o += cl; |
| 2527 | if (cl == 0) break; // No zero-len chunk, buffer more data |
| 2528 | if (cl < 0) { |
| 2529 | mg_error(c, "Invalid chunk"); |
| 2530 | break; |
| 2531 | } |
| 2532 | |
| 2533 | // Zero chunk found. Second pass: strip + relocate |
| 2534 | o = 0, hm.body.len = 0, hm.message.len = (size_t) n; |
| 2535 | while ((cl = skip_chunk(s + o, len - o, &pl, &dl)) > 0) { |
| 2536 | memmove(s + hm.body.len, s + o + pl, (size_t) dl); |
| 2537 | o += cl, hm.body.len += (size_t) dl, hm.message.len += (size_t) dl; |
| 2538 | if (dl == 0) break; |
| 2539 | } |
| 2540 | ofs += (size_t) (n + o); |
| 2541 | } else { // Normal, non-chunked data |
| 2542 | size_t len = c->recv.len - ofs - (size_t) n; |
| 2543 | if (hm.body.len > len) break; // Buffer more data |
| 2544 | ofs += (size_t) n + hm.body.len; |
| 2545 | } |
| 2546 | |
| 2547 | if (c->is_accepted) c->is_resp = 1; // Start generating response |
| 2548 | mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp |
| 2549 | if (c->is_accepted && !c->is_resp) { |
| 2550 | struct mg_str *cc = mg_http_get_header(&hm, "Connection"); |
| 2551 | if (cc != NULL && mg_strcasecmp(*cc, mg_str("close")) == 0) { |
| 2552 | c->is_draining = 1; // honor "Connection: close" |
| 2553 | break; |
| 2554 | } |
| 2555 | } |
| 2556 | } |
| 2557 | if (ofs > 0) mg_iobuf_del(&c->recv, 0, ofs); // Delete processed data |
| 2558 | } |
| 2559 | (void) ev_data; |
| 2560 | } |
| 2561 | |
| 2562 | static void mg_hfn(struct mg_connection *c, int ev, void *ev_data) { |
| 2563 | if (ev == MG_EV_HTTP_MSG) { |
| 2564 | struct mg_http_message *hm = (struct mg_http_message *) ev_data; |
| 2565 | if (mg_match(hm->uri, mg_str("/quit"), NULL)) { |
| 2566 | mg_http_reply(c, 200, "", "ok\n"); |
| 2567 | c->is_draining = 1; |
| 2568 | c->data[0] = 'X'; |
| 2569 | } else if (mg_match(hm->uri, mg_str("/debug"), NULL)) { |
| 2570 | int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); |
| 2571 | mg_log_set(level); |
| 2572 | mg_http_reply(c, 200, "", "Debug level set to %d\n", level); |
| 2573 | } else { |
| 2574 | mg_http_reply(c, 200, "", "hi\n"); |
| 2575 | } |
| 2576 | } else if (ev == MG_EV_CLOSE) { |
| 2577 | if (c->data[0] == 'X') *(bool *) c->fn_data = true; |
| 2578 | } |
| 2579 | } |
| 2580 | |
| 2581 | void mg_hello(const char *url) { |
| 2582 | struct mg_mgr mgr; |
| 2583 | bool done = false; |
| 2584 | mg_mgr_init(&mgr); |
| 2585 | if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true; |
| 2586 | while (done == false) mg_mgr_poll(&mgr, 100); |
| 2587 | mg_mgr_free(&mgr); |
| 2588 | } |
| 2589 | |
| 2590 | struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url, |
| 2591 | mg_event_handler_t fn, void *fn_data) { |
| 2592 | struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); |
| 2593 | if (c != NULL) c->pfn = http_cb; |
| 2594 | return c; |
| 2595 | } |
| 2596 | |
| 2597 | struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url, |
| 2598 | mg_event_handler_t fn, void *fn_data) { |
| 2599 | struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); |
| 2600 | if (c != NULL) c->pfn = http_cb; |
| 2601 | return c; |
| 2602 | } |
| 2603 | |
| 2604 | #ifdef MG_ENABLE_LINES |
| 2605 | #line 1 "src/iobuf.c" |
| 2606 | #endif |
| 2607 | |
| 2608 | |
| 2609 | |
| 2610 | |
| 2611 | |
| 2612 | static size_t roundup(size_t size, size_t align) { |
| 2613 | return align == 0 ? size : (size + align - 1) / align * align; |
| 2614 | } |
| 2615 | |
| 2616 | int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { |
| 2617 | int ok = 1; |
| 2618 | new_size = roundup(new_size, io->align); |
| 2619 | if (new_size == 0) { |
| 2620 | mg_bzero(io->buf, io->size); |
| 2621 | free(io->buf); |
| 2622 | io->buf = NULL; |
| 2623 | io->len = io->size = 0; |
| 2624 | } else if (new_size != io->size) { |
| 2625 | // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the |
| 2626 | // porting to some obscure platforms like FreeRTOS |
| 2627 | void *p = calloc(1, new_size); |
| 2628 | if (p != NULL) { |
| 2629 | size_t len = new_size < io->len ? new_size : io->len; |
| 2630 | if (len > 0 && io->buf != NULL) memmove(p, io->buf, len); |
| 2631 | mg_bzero(io->buf, io->size); |
| 2632 | free(io->buf); |
| 2633 | io->buf = (unsigned char *) p; |
| 2634 | io->size = new_size; |
| 2635 | } else { |
| 2636 | ok = 0; |
| 2637 | MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size)); |
| 2638 | } |
| 2639 | } |
| 2640 | return ok; |
| 2641 | } |
| 2642 | |
| 2643 | int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) { |
| 2644 | io->buf = NULL; |
| 2645 | io->align = align; |
| 2646 | io->size = io->len = 0; |
| 2647 | return mg_iobuf_resize(io, size); |
| 2648 | } |
| 2649 | |
| 2650 | size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, |
| 2651 | size_t len) { |
| 2652 | size_t new_size = roundup(io->len + len, io->align); |
| 2653 | mg_iobuf_resize(io, new_size); // Attempt to resize |
| 2654 | if (new_size != io->size) len = 0; // Resize failure, append nothing |
| 2655 | if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs); |
| 2656 | if (buf != NULL) memmove(io->buf + ofs, buf, len); |
| 2657 | if (ofs > io->len) io->len += ofs - io->len; |
| 2658 | io->len += len; |
| 2659 | return len; |
| 2660 | } |
| 2661 | |
| 2662 | size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) { |
| 2663 | if (ofs > io->len) ofs = io->len; |
| 2664 | if (ofs + len > io->len) len = io->len - ofs; |
| 2665 | if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len); |
| 2666 | if (io->buf) mg_bzero(io->buf + io->len - len, len); |
| 2667 | io->len -= len; |
| 2668 | return len; |
| 2669 | } |
| 2670 | |
| 2671 | void mg_iobuf_free(struct mg_iobuf *io) { |
| 2672 | mg_iobuf_resize(io, 0); |
| 2673 | } |
| 2674 | |
| 2675 | #ifdef MG_ENABLE_LINES |
| 2676 | #line 1 "src/json.c" |
| 2677 | #endif |
| 2678 | |
| 2679 | |
| 2680 | |
| 2681 | |
| 2682 | static const char *escapeseq(int esc) { |
| 2683 | return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; |
| 2684 | } |
| 2685 | |
| 2686 | static char json_esc(int c, int esc) { |
| 2687 | const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc); |
| 2688 | for (p = esc1; *p != '\0'; p++) { |
| 2689 | if (*p == c) return esc2[p - esc1]; |
| 2690 | } |
| 2691 | return 0; |
| 2692 | } |
| 2693 | |
| 2694 | static int mg_pass_string(const char *s, int len) { |
| 2695 | int i; |
| 2696 | for (i = 0; i < len; i++) { |
| 2697 | if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) { |
| 2698 | i++; |
| 2699 | } else if (s[i] == '\0') { |
| 2700 | return MG_JSON_INVALID; |
| 2701 | } else if (s[i] == '"') { |
| 2702 | return i; |
| 2703 | } |
| 2704 | } |
| 2705 | return MG_JSON_INVALID; |
| 2706 | } |
| 2707 | |
| 2708 | static double mg_atod(const char *p, int len, int *numlen) { |
| 2709 | double d = 0.0; |
| 2710 | int i = 0, sign = 1; |
| 2711 | |
| 2712 | // Sign |
| 2713 | if (i < len && *p == '-') { |
| 2714 | sign = -1, i++; |
| 2715 | } else if (i < len && *p == '+') { |
| 2716 | i++; |
| 2717 | } |
| 2718 | |
| 2719 | // Decimal |
| 2720 | for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { |
| 2721 | d *= 10.0; |
| 2722 | d += p[i] - '0'; |
| 2723 | } |
| 2724 | d *= sign; |
| 2725 | |
| 2726 | // Fractional |
| 2727 | if (i < len && p[i] == '.') { |
| 2728 | double frac = 0.0, base = 0.1; |
| 2729 | i++; |
| 2730 | for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { |
| 2731 | frac += base * (p[i] - '0'); |
| 2732 | base /= 10.0; |
| 2733 | } |
| 2734 | d += frac * sign; |
| 2735 | } |
| 2736 | |
| 2737 | // Exponential |
| 2738 | if (i < len && (p[i] == 'e' || p[i] == 'E')) { |
| 2739 | int j, exp = 0, minus = 0; |
| 2740 | i++; |
| 2741 | if (i < len && p[i] == '-') minus = 1, i++; |
| 2742 | if (i < len && p[i] == '+') i++; |
| 2743 | while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) |
| 2744 | exp = exp * 10 + (p[i++] - '0'); |
| 2745 | if (minus) exp = -exp; |
| 2746 | for (j = 0; j < exp; j++) d *= 10.0; |
| 2747 | for (j = 0; j < -exp; j++) d /= 10.0; |
| 2748 | } |
| 2749 | |
| 2750 | if (numlen != NULL) *numlen = i; |
| 2751 | return d; |
| 2752 | } |
| 2753 | |
| 2754 | // Iterate over object or array elements |
| 2755 | size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key, |
| 2756 | struct mg_str *val) { |
| 2757 | if (ofs >= obj.len) { |
| 2758 | ofs = 0; // Out of boundaries, stop scanning |
| 2759 | } else if (obj.len < 2 || (*obj.buf != '{' && *obj.buf != '[')) { |
| 2760 | ofs = 0; // Not an array or object, stop |
| 2761 | } else { |
| 2762 | struct mg_str sub = mg_str_n(obj.buf + ofs, obj.len - ofs); |
| 2763 | if (ofs == 0) ofs++, sub.buf++, sub.len--; |
| 2764 | if (*obj.buf == '[') { // Iterate over an array |
| 2765 | int n = 0, o = mg_json_get(sub, "$", &n); |
| 2766 | if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { |
| 2767 | ofs = 0; // Error parsing key, stop scanning |
| 2768 | } else { |
| 2769 | if (key) *key = mg_str_n(NULL, 0); |
| 2770 | if (val) *val = mg_str_n(sub.buf + o, (size_t) n); |
| 2771 | ofs = (size_t) (&sub.buf[o + n] - obj.buf); |
| 2772 | } |
| 2773 | } else { // Iterate over an object |
| 2774 | int n = 0, o = mg_json_get(sub, "$", &n); |
| 2775 | if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { |
| 2776 | ofs = 0; // Error parsing key, stop scanning |
| 2777 | } else { |
| 2778 | if (key) *key = mg_str_n(sub.buf + o, (size_t) n); |
| 2779 | sub.buf += o + n, sub.len -= (size_t) (o + n); |
| 2780 | while (sub.len > 0 && *sub.buf != ':') sub.len--, sub.buf++; |
| 2781 | if (sub.len > 0 && *sub.buf == ':') sub.len--, sub.buf++; |
| 2782 | n = 0, o = mg_json_get(sub, "$", &n); |
| 2783 | if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { |
| 2784 | ofs = 0; // Error parsing value, stop scanning |
| 2785 | } else { |
| 2786 | if (val) *val = mg_str_n(sub.buf + o, (size_t) n); |
| 2787 | ofs = (size_t) (&sub.buf[o + n] - obj.buf); |
| 2788 | } |
| 2789 | } |
| 2790 | } |
| 2791 | // MG_INFO(("SUB ofs %u %.*s", ofs, sub.len, sub.buf)); |
| 2792 | while (ofs && ofs < obj.len && |
| 2793 | (obj.buf[ofs] == ' ' || obj.buf[ofs] == '\t' || |
| 2794 | obj.buf[ofs] == '\n' || obj.buf[ofs] == '\r')) { |
| 2795 | ofs++; |
| 2796 | } |
| 2797 | if (ofs && ofs < obj.len && obj.buf[ofs] == ',') ofs++; |
| 2798 | if (ofs > obj.len) ofs = 0; |
| 2799 | } |
| 2800 | return ofs; |
| 2801 | } |
| 2802 | |
| 2803 | int mg_json_get(struct mg_str json, const char *path, int *toklen) { |
| 2804 | const char *s = json.buf; |
| 2805 | int len = (int) json.len; |
| 2806 | enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; |
| 2807 | unsigned char nesting[MG_JSON_MAX_DEPTH]; |
| 2808 | int i = 0; // Current offset in `s` |
| 2809 | int j = 0; // Offset in `s` we're looking for (return value) |
| 2810 | int depth = 0; // Current depth (nesting level) |
| 2811 | int ed = 0; // Expected depth |
| 2812 | int pos = 1; // Current position in `path` |
| 2813 | int ci = -1, ei = -1; // Current and expected index in array |
| 2814 | |
| 2815 | if (toklen) *toklen = 0; |
| 2816 | if (path[0] != '$') return MG_JSON_INVALID; |
| 2817 | |
| 2818 | #define MG_CHECKRET(x) \ |
| 2819 | do { \ |
| 2820 | if (depth == ed && path[pos] == '\0' && ci == ei) { \ |
| 2821 | if (toklen) *toklen = i - j + 1; \ |
| 2822 | return j; \ |
| 2823 | } \ |
| 2824 | } while (0) |
| 2825 | |
| 2826 | // In the ascii table, the distance between `[` and `]` is 2. |
| 2827 | // Ditto for `{` and `}`. Hence +2 in the code below. |
| 2828 | #define MG_EOO(x) \ |
| 2829 | do { \ |
| 2830 | if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \ |
| 2831 | if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ |
| 2832 | depth--; \ |
| 2833 | MG_CHECKRET(x); \ |
| 2834 | } while (0) |
| 2835 | |
| 2836 | for (i = 0; i < len; i++) { |
| 2837 | unsigned char c = ((unsigned char *) s)[i]; |
| 2838 | if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; |
| 2839 | switch (expecting) { |
| 2840 | case S_VALUE: |
| 2841 | // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei); |
| 2842 | if (depth == ed) j = i; |
| 2843 | if (c == '{') { |
| 2844 | if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; |
| 2845 | if (depth == ed && path[pos] == '.' && ci == ei) { |
| 2846 | // If we start the object, reset array indices |
| 2847 | ed++, pos++, ci = ei = -1; |
| 2848 | } |
| 2849 | nesting[depth++] = c; |
| 2850 | expecting = S_KEY; |
| 2851 | break; |
| 2852 | } else if (c == '[') { |
| 2853 | if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; |
| 2854 | if (depth == ed && path[pos] == '[' && ei == ci) { |
| 2855 | ed++, pos++, ci = 0; |
| 2856 | for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) { |
| 2857 | ei *= 10; |
| 2858 | ei += path[pos] - '0'; |
| 2859 | } |
| 2860 | if (path[pos] != 0) pos++; |
| 2861 | } |
| 2862 | nesting[depth++] = c; |
| 2863 | break; |
| 2864 | } else if (c == ']' && depth > 0) { // Empty array |
| 2865 | MG_EOO(']'); |
| 2866 | } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { |
| 2867 | i += 3; |
| 2868 | } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) { |
| 2869 | i += 3; |
| 2870 | } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) { |
| 2871 | i += 4; |
| 2872 | } else if (c == '-' || ((c >= '0' && c <= '9'))) { |
| 2873 | int numlen = 0; |
| 2874 | mg_atod(&s[i], len - i, &numlen); |
| 2875 | i += numlen - 1; |
| 2876 | } else if (c == '"') { |
| 2877 | int n = mg_pass_string(&s[i + 1], len - i - 1); |
| 2878 | if (n < 0) return n; |
| 2879 | i += n + 1; |
| 2880 | } else { |
| 2881 | return MG_JSON_INVALID; |
| 2882 | } |
| 2883 | MG_CHECKRET('V'); |
| 2884 | if (depth == ed && ei >= 0) ci++; |
| 2885 | expecting = S_COMMA_OR_EOO; |
| 2886 | break; |
| 2887 | |
| 2888 | case S_KEY: |
| 2889 | if (c == '"') { |
| 2890 | int n = mg_pass_string(&s[i + 1], len - i - 1); |
| 2891 | if (n < 0) return n; |
| 2892 | if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; |
| 2893 | if (depth < ed) return MG_JSON_NOT_FOUND; |
| 2894 | if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND; |
| 2895 | // printf("K %s [%.*s] [%.*s] %d %d %d %d %d\n", path, pos, path, n, |
| 2896 | // &s[i + 1], n, depth, ed, ci, ei); |
| 2897 | // NOTE(cpq): in the check sequence below is important. |
| 2898 | // strncmp() must go first: it fails fast if the remaining length |
| 2899 | // of the path is smaller than `n`. |
| 2900 | if (depth == ed && path[pos - 1] == '.' && |
| 2901 | strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && |
| 2902 | (path[pos + n] == '\0' || path[pos + n] == '.' || |
| 2903 | path[pos + n] == '[')) { |
| 2904 | pos += n; |
| 2905 | } |
| 2906 | i += n + 1; |
| 2907 | expecting = S_COLON; |
| 2908 | } else if (c == '}') { // Empty object |
| 2909 | MG_EOO('}'); |
| 2910 | expecting = S_COMMA_OR_EOO; |
| 2911 | if (depth == ed && ei >= 0) ci++; |
| 2912 | } else { |
| 2913 | return MG_JSON_INVALID; |
| 2914 | } |
| 2915 | break; |
| 2916 | |
| 2917 | case S_COLON: |
| 2918 | if (c == ':') { |
| 2919 | expecting = S_VALUE; |
| 2920 | } else { |
| 2921 | return MG_JSON_INVALID; |
| 2922 | } |
| 2923 | break; |
| 2924 | |
| 2925 | case S_COMMA_OR_EOO: |
| 2926 | if (depth <= 0) { |
| 2927 | return MG_JSON_INVALID; |
| 2928 | } else if (c == ',') { |
| 2929 | expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; |
| 2930 | } else if (c == ']' || c == '}') { |
| 2931 | if (depth == ed && c == '}' && path[pos - 1] == '.') |
| 2932 | return MG_JSON_NOT_FOUND; |
| 2933 | if (depth == ed && c == ']' && path[pos - 1] == ',') |
| 2934 | return MG_JSON_NOT_FOUND; |
| 2935 | MG_EOO('O'); |
| 2936 | if (depth == ed && ei >= 0) ci++; |
| 2937 | } else { |
| 2938 | return MG_JSON_INVALID; |
| 2939 | } |
| 2940 | break; |
| 2941 | } |
| 2942 | } |
| 2943 | return MG_JSON_NOT_FOUND; |
| 2944 | } |
| 2945 | |
| 2946 | struct mg_str mg_json_get_tok(struct mg_str json, const char *path) { |
| 2947 | int len = 0, ofs = mg_json_get(json, path, &len); |
| 2948 | return mg_str_n(ofs < 0 ? NULL : json.buf + ofs, |
| 2949 | (size_t) (len < 0 ? 0 : len)); |
| 2950 | } |
| 2951 | |
| 2952 | bool mg_json_get_num(struct mg_str json, const char *path, double *v) { |
| 2953 | int n, toklen, found = 0; |
| 2954 | if ((n = mg_json_get(json, path, &toklen)) >= 0 && |
| 2955 | (json.buf[n] == '-' || (json.buf[n] >= '0' && json.buf[n] <= '9'))) { |
| 2956 | if (v != NULL) *v = mg_atod(json.buf + n, toklen, NULL); |
| 2957 | found = 1; |
| 2958 | } |
| 2959 | return found; |
| 2960 | } |
| 2961 | |
| 2962 | bool mg_json_get_bool(struct mg_str json, const char *path, bool *v) { |
| 2963 | int found = 0, off = mg_json_get(json, path, NULL); |
| 2964 | if (off >= 0 && (json.buf[off] == 't' || json.buf[off] == 'f')) { |
| 2965 | if (v != NULL) *v = json.buf[off] == 't'; |
| 2966 | found = 1; |
| 2967 | } |
| 2968 | return found; |
| 2969 | } |
| 2970 | |
| 2971 | bool mg_json_unescape(struct mg_str s, char *to, size_t n) { |
| 2972 | size_t i, j; |
| 2973 | for (i = 0, j = 0; i < s.len && j < n; i++, j++) { |
| 2974 | if (s.buf[i] == '\\' && i + 5 < s.len && s.buf[i + 1] == 'u') { |
| 2975 | // \uXXXX escape. We process simple one-byte chars \u00xx within ASCII |
| 2976 | // range. More complex chars would require dragging in a UTF8 library, |
| 2977 | // which is too much for us |
| 2978 | if (mg_str_to_num(mg_str_n(s.buf + i + 2, 4), 16, &to[j], |
| 2979 | sizeof(uint8_t)) == false) |
| 2980 | return false; |
| 2981 | i += 5; |
| 2982 | } else if (s.buf[i] == '\\' && i + 1 < s.len) { |
| 2983 | char c = json_esc(s.buf[i + 1], 0); |
| 2984 | if (c == 0) return false; |
| 2985 | to[j] = c; |
| 2986 | i++; |
| 2987 | } else { |
| 2988 | to[j] = s.buf[i]; |
| 2989 | } |
| 2990 | } |
| 2991 | if (j >= n) return false; |
| 2992 | if (n > 0) to[j] = '\0'; |
| 2993 | return true; |
| 2994 | } |
| 2995 | |
| 2996 | char *mg_json_get_str(struct mg_str json, const char *path) { |
| 2997 | char *result = NULL; |
| 2998 | int len = 0, off = mg_json_get(json, path, &len); |
| 2999 | if (off >= 0 && len > 1 && json.buf[off] == '"') { |
| 3000 | if ((result = (char *) calloc(1, (size_t) len)) != NULL && |
| 3001 | !mg_json_unescape(mg_str_n(json.buf + off + 1, (size_t) (len - 2)), |
| 3002 | result, (size_t) len)) { |
| 3003 | free(result); |
| 3004 | result = NULL; |
| 3005 | } |
| 3006 | } |
| 3007 | return result; |
| 3008 | } |
| 3009 | |
| 3010 | char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) { |
| 3011 | char *result = NULL; |
| 3012 | int len = 0, off = mg_json_get(json, path, &len); |
| 3013 | if (off >= 0 && json.buf[off] == '"' && len > 1 && |
| 3014 | (result = (char *) calloc(1, (size_t) len)) != NULL) { |
| 3015 | size_t k = mg_base64_decode(json.buf + off + 1, (size_t) (len - 2), result, |
| 3016 | (size_t) len); |
| 3017 | if (slen != NULL) *slen = (int) k; |
| 3018 | } |
| 3019 | return result; |
| 3020 | } |
| 3021 | |
| 3022 | char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) { |
| 3023 | char *result = NULL; |
| 3024 | int len = 0, off = mg_json_get(json, path, &len); |
| 3025 | if (off >= 0 && json.buf[off] == '"' && len > 1 && |
| 3026 | (result = (char *) calloc(1, (size_t) len / 2)) != NULL) { |
| 3027 | int i; |
| 3028 | for (i = 0; i < len - 2; i += 2) { |
| 3029 | mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1], |
| 3030 | sizeof(uint8_t)); |
| 3031 | } |
| 3032 | result[len / 2 - 1] = '\0'; |
| 3033 | if (slen != NULL) *slen = len / 2 - 1; |
| 3034 | } |
| 3035 | return result; |
| 3036 | } |
| 3037 | |
| 3038 | long mg_json_get_long(struct mg_str json, const char *path, long dflt) { |
| 3039 | double dv; |
| 3040 | long result = dflt; |
| 3041 | if (mg_json_get_num(json, path, &dv)) result = (long) dv; |
| 3042 | return result; |
| 3043 | } |
| 3044 | |
| 3045 | #ifdef MG_ENABLE_LINES |
| 3046 | #line 1 "src/log.c" |
| 3047 | #endif |
| 3048 | |
| 3049 | |
| 3050 | |
| 3051 | |
| 3052 | |
| 3053 | int mg_log_level = MG_LL_INFO; |
| 3054 | static mg_pfn_t s_log_func = mg_pfn_stdout; |
| 3055 | static void *s_log_func_param = NULL; |
| 3056 | |
| 3057 | void mg_log_set_fn(mg_pfn_t fn, void *param) { |
| 3058 | s_log_func = fn; |
| 3059 | s_log_func_param = param; |
| 3060 | } |
| 3061 | |
| 3062 | static void logc(unsigned char c) { |
| 3063 | s_log_func((char) c, s_log_func_param); |
| 3064 | } |
| 3065 | |
| 3066 | static void logs(const char *buf, size_t len) { |
| 3067 | size_t i; |
| 3068 | for (i = 0; i < len; i++) logc(((unsigned char *) buf)[i]); |
| 3069 | } |
| 3070 | |
| 3071 | #if MG_ENABLE_CUSTOM_LOG |
| 3072 | // Let user define their own mg_log_prefix() and mg_log() |
| 3073 | #else |
| 3074 | void mg_log_prefix(int level, const char *file, int line, const char *fname) { |
| 3075 | const char *p = strrchr(file, '/'); |
| 3076 | char buf[41]; |
| 3077 | size_t n; |
| 3078 | if (p == NULL) p = strrchr(file, '\\'); |
| 3079 | n = mg_snprintf(buf, sizeof(buf), "%-6llx %d %s:%d:%s", mg_millis(), level, |
| 3080 | p == NULL ? file : p + 1, line, fname); |
| 3081 | if (n > sizeof(buf) - 2) n = sizeof(buf) - 2; |
| 3082 | while (n < sizeof(buf)) buf[n++] = ' '; |
| 3083 | logs(buf, n - 1); |
| 3084 | } |
| 3085 | |
| 3086 | void mg_log(const char *fmt, ...) { |
| 3087 | va_list ap; |
| 3088 | va_start(ap, fmt); |
| 3089 | mg_vxprintf(s_log_func, s_log_func_param, fmt, &ap); |
| 3090 | va_end(ap); |
| 3091 | logs("\r\n", 2); |
| 3092 | } |
| 3093 | #endif |
| 3094 | |
| 3095 | static unsigned char nibble(unsigned c) { |
| 3096 | return (unsigned char) (c < 10 ? c + '0' : c + 'W'); |
| 3097 | } |
| 3098 | |
| 3099 | #define ISPRINT(x) ((x) >= ' ' && (x) <= '~') |
| 3100 | void mg_hexdump(const void *buf, size_t len) { |
| 3101 | const unsigned char *p = (const unsigned char *) buf; |
| 3102 | unsigned char ascii[16], alen = 0; |
| 3103 | size_t i; |
| 3104 | for (i = 0; i < len; i++) { |
| 3105 | if ((i % 16) == 0) { |
| 3106 | // Print buffered ascii chars |
| 3107 | if (i > 0) |
| 3108 | logs(" ", 2), logs((char *) ascii, 16), logs("\r\n", 2), alen = 0; |
| 3109 | // Print hex address, then \t |
| 3110 | logc(nibble((i >> 12) & 15)), logc(nibble((i >> 8) & 15)), |
| 3111 | logc(nibble((i >> 4) & 15)), logc('0'), logs(" ", 3); |
| 3112 | } |
| 3113 | logc(nibble(p[i] >> 4)), logc(nibble(p[i] & 15)); // Two nibbles, e.g. c5 |
| 3114 | logc(' '); // Space after hex number |
| 3115 | ascii[alen++] = ISPRINT(p[i]) ? p[i] : '.'; // Add to the ascii buf |
| 3116 | } |
| 3117 | while (alen < 16) logs(" ", 3), ascii[alen++] = ' '; |
| 3118 | logs(" ", 2), logs((char *) ascii, 16), logs("\r\n", 2); |
| 3119 | } |
| 3120 | |
| 3121 | #ifdef MG_ENABLE_LINES |
| 3122 | #line 1 "src/md5.c" |
| 3123 | #endif |
| 3124 | |
| 3125 | |
| 3126 | |
| 3127 | // This code implements the MD5 message-digest algorithm. |
| 3128 | // The algorithm is due to Ron Rivest. This code was |
| 3129 | // written by Colin Plumb in 1993, no copyright is claimed. |
| 3130 | // This code is in the public domain; do with it what you wish. |
| 3131 | // |
| 3132 | // Equivalent code is available from RSA Data Security, Inc. |
| 3133 | // This code has been tested against that, and is equivalent, |
| 3134 | // except that you don't need to include two pages of legalese |
| 3135 | // with every copy. |
| 3136 | // |
| 3137 | // To compute the message digest of a chunk of bytes, declare an |
| 3138 | // MD5Context structure, pass it to MD5Init, call MD5Update as |
| 3139 | // needed on buffers full of bytes, and then call MD5Final, which |
| 3140 | // will fill a supplied 16-byte array with the digest. |
| 3141 | |
| 3142 | #if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5 |
| 3143 | |
| 3144 | static void mg_byte_reverse(unsigned char *buf, unsigned longs) { |
| 3145 | if (MG_BIG_ENDIAN) { |
| 3146 | do { |
| 3147 | uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | |
| 3148 | ((unsigned) buf[1] << 8 | buf[0]); |
| 3149 | *(uint32_t *) buf = t; |
| 3150 | buf += 4; |
| 3151 | } while (--longs); |
| 3152 | } else { |
| 3153 | (void) buf, (void) longs; // Little endian. Do nothing |
| 3154 | } |
| 3155 | } |
| 3156 | |
| 3157 | #define F1(x, y, z) (z ^ (x & (y ^ z))) |
| 3158 | #define F2(x, y, z) F1(z, x, y) |
| 3159 | #define F3(x, y, z) (x ^ y ^ z) |
| 3160 | #define F4(x, y, z) (y ^ (x | ~z)) |
| 3161 | |
| 3162 | #define MD5STEP(f, w, x, y, z, data, s) \ |
| 3163 | (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) |
| 3164 | |
| 3165 | /* |
| 3166 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious |
| 3167 | * initialization constants. |
| 3168 | */ |
| 3169 | void mg_md5_init(mg_md5_ctx *ctx) { |
| 3170 | ctx->buf[0] = 0x67452301; |
| 3171 | ctx->buf[1] = 0xefcdab89; |
| 3172 | ctx->buf[2] = 0x98badcfe; |
| 3173 | ctx->buf[3] = 0x10325476; |
| 3174 | |
| 3175 | ctx->bits[0] = 0; |
| 3176 | ctx->bits[1] = 0; |
| 3177 | } |
| 3178 | |
| 3179 | static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) { |
| 3180 | uint32_t a, b, c, d; |
| 3181 | |
| 3182 | a = buf[0]; |
| 3183 | b = buf[1]; |
| 3184 | c = buf[2]; |
| 3185 | d = buf[3]; |
| 3186 | |
| 3187 | MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); |
| 3188 | MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); |
| 3189 | MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); |
| 3190 | MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); |
| 3191 | MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); |
| 3192 | MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); |
| 3193 | MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); |
| 3194 | MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); |
| 3195 | MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); |
| 3196 | MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); |
| 3197 | MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); |
| 3198 | MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); |
| 3199 | MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); |
| 3200 | MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); |
| 3201 | MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); |
| 3202 | MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); |
| 3203 | |
| 3204 | MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); |
| 3205 | MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); |
| 3206 | MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); |
| 3207 | MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); |
| 3208 | MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); |
| 3209 | MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); |
| 3210 | MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); |
| 3211 | MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); |
| 3212 | MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); |
| 3213 | MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); |
| 3214 | MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); |
| 3215 | MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); |
| 3216 | MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); |
| 3217 | MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); |
| 3218 | MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); |
| 3219 | MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); |
| 3220 | |
| 3221 | MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); |
| 3222 | MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); |
| 3223 | MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); |
| 3224 | MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); |
| 3225 | MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); |
| 3226 | MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); |
| 3227 | MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); |
| 3228 | MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); |
| 3229 | MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); |
| 3230 | MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); |
| 3231 | MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); |
| 3232 | MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); |
| 3233 | MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); |
| 3234 | MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); |
| 3235 | MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); |
| 3236 | MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); |
| 3237 | |
| 3238 | MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); |
| 3239 | MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); |
| 3240 | MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); |
| 3241 | MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); |
| 3242 | MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); |
| 3243 | MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); |
| 3244 | MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); |
| 3245 | MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); |
| 3246 | MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); |
| 3247 | MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); |
| 3248 | MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); |
| 3249 | MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); |
| 3250 | MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); |
| 3251 | MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); |
| 3252 | MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); |
| 3253 | MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); |
| 3254 | |
| 3255 | buf[0] += a; |
| 3256 | buf[1] += b; |
| 3257 | buf[2] += c; |
| 3258 | buf[3] += d; |
| 3259 | } |
| 3260 | |
| 3261 | void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) { |
| 3262 | uint32_t t; |
| 3263 | |
| 3264 | t = ctx->bits[0]; |
| 3265 | if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; |
| 3266 | ctx->bits[1] += (uint32_t) len >> 29; |
| 3267 | |
| 3268 | t = (t >> 3) & 0x3f; |
| 3269 | |
| 3270 | if (t) { |
| 3271 | unsigned char *p = (unsigned char *) ctx->in + t; |
| 3272 | |
| 3273 | t = 64 - t; |
| 3274 | if (len < t) { |
| 3275 | memcpy(p, buf, len); |
| 3276 | return; |
| 3277 | } |
| 3278 | memcpy(p, buf, t); |
| 3279 | mg_byte_reverse(ctx->in, 16); |
| 3280 | mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); |
| 3281 | buf += t; |
| 3282 | len -= t; |
| 3283 | } |
| 3284 | |
| 3285 | while (len >= 64) { |
| 3286 | memcpy(ctx->in, buf, 64); |
| 3287 | mg_byte_reverse(ctx->in, 16); |
| 3288 | mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); |
| 3289 | buf += 64; |
| 3290 | len -= 64; |
| 3291 | } |
| 3292 | |
| 3293 | memcpy(ctx->in, buf, len); |
| 3294 | } |
| 3295 | |
| 3296 | void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) { |
| 3297 | unsigned count; |
| 3298 | unsigned char *p; |
| 3299 | uint32_t *a; |
| 3300 | |
| 3301 | count = (ctx->bits[0] >> 3) & 0x3F; |
| 3302 | |
| 3303 | p = ctx->in + count; |
| 3304 | *p++ = 0x80; |
| 3305 | count = 64 - 1 - count; |
| 3306 | if (count < 8) { |
| 3307 | memset(p, 0, count); |
| 3308 | mg_byte_reverse(ctx->in, 16); |
| 3309 | mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); |
| 3310 | memset(ctx->in, 0, 56); |
| 3311 | } else { |
| 3312 | memset(p, 0, count - 8); |
| 3313 | } |
| 3314 | mg_byte_reverse(ctx->in, 14); |
| 3315 | |
| 3316 | a = (uint32_t *) ctx->in; |
| 3317 | a[14] = ctx->bits[0]; |
| 3318 | a[15] = ctx->bits[1]; |
| 3319 | |
| 3320 | mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); |
| 3321 | mg_byte_reverse((unsigned char *) ctx->buf, 4); |
| 3322 | memcpy(digest, ctx->buf, 16); |
| 3323 | memset((char *) ctx, 0, sizeof(*ctx)); |
| 3324 | } |
| 3325 | #endif |
| 3326 | |
| 3327 | #ifdef MG_ENABLE_LINES |
| 3328 | #line 1 "src/mqtt.c" |
| 3329 | #endif |
| 3330 | |
| 3331 | |
| 3332 | |
| 3333 | |
| 3334 | |
| 3335 | |
| 3336 | |
| 3337 | |
| 3338 | #define MQTT_CLEAN_SESSION 0x02 |
| 3339 | #define MQTT_HAS_WILL 0x04 |
| 3340 | #define MQTT_WILL_RETAIN 0x20 |
| 3341 | #define MQTT_HAS_PASSWORD 0x40 |
| 3342 | #define MQTT_HAS_USER_NAME 0x80 |
| 3343 | |
| 3344 | struct mg_mqtt_pmap { |
| 3345 | uint8_t id; |
| 3346 | uint8_t type; |
| 3347 | }; |
| 3348 | |
| 3349 | static const struct mg_mqtt_pmap s_prop_map[] = { |
| 3350 | {MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE}, |
| 3351 | {MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT}, |
| 3352 | {MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING}, |
| 3353 | {MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING}, |
| 3354 | {MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY_DATA}, |
| 3355 | {MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARIABLE_INT}, |
| 3356 | {MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT}, |
| 3357 | {MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING}, |
| 3358 | {MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_SHORT}, |
| 3359 | {MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING}, |
| 3360 | {MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY_DATA}, |
| 3361 | {MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE}, |
| 3362 | {MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT}, |
| 3363 | {MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE}, |
| 3364 | {MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING}, |
| 3365 | {MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING}, |
| 3366 | {MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING}, |
| 3367 | {MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_SHORT}, |
| 3368 | {MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_SHORT}, |
| 3369 | {MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_SHORT}, |
| 3370 | {MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE}, |
| 3371 | {MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE}, |
| 3372 | {MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR}, |
| 3373 | {MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT}, |
| 3374 | {MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}, |
| 3375 | {MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE}, |
| 3376 | {MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}}; |
| 3377 | |
| 3378 | void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, |
| 3379 | uint32_t len) { |
| 3380 | uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; |
| 3381 | buf[0] = (uint8_t) ((cmd << 4) | flags); |
| 3382 | do { |
| 3383 | *vlen = len % 0x80; |
| 3384 | len /= 0x80; |
| 3385 | if (len > 0) *vlen |= 0x80; |
| 3386 | vlen++; |
| 3387 | } while (len > 0 && vlen < &buf[sizeof(buf)]); |
| 3388 | mg_send(c, buf, (size_t) (vlen - buf)); |
| 3389 | } |
| 3390 | |
| 3391 | static void mg_send_u16(struct mg_connection *c, uint16_t value) { |
| 3392 | mg_send(c, &value, sizeof(value)); |
| 3393 | } |
| 3394 | |
| 3395 | static void mg_send_u32(struct mg_connection *c, uint32_t value) { |
| 3396 | mg_send(c, &value, sizeof(value)); |
| 3397 | } |
| 3398 | |
| 3399 | static uint8_t varint_size(size_t length) { |
| 3400 | uint8_t bytes_needed = 0; |
| 3401 | do { |
| 3402 | bytes_needed++; |
| 3403 | length /= 0x80; |
| 3404 | } while (length > 0); |
| 3405 | return bytes_needed; |
| 3406 | } |
| 3407 | |
| 3408 | static size_t encode_varint(uint8_t *buf, size_t value) { |
| 3409 | size_t len = 0; |
| 3410 | |
| 3411 | do { |
| 3412 | uint8_t b = (uint8_t) (value % 128); |
| 3413 | value /= 128; |
| 3414 | if (value > 0) b |= 0x80; |
| 3415 | buf[len++] = b; |
| 3416 | } while (value > 0); |
| 3417 | |
| 3418 | return len; |
| 3419 | } |
| 3420 | |
| 3421 | static size_t decode_varint(const uint8_t *buf, size_t len, size_t *value) { |
| 3422 | size_t multiplier = 1, offset; |
| 3423 | *value = 0; |
| 3424 | |
| 3425 | for (offset = 0; offset < 4 && offset < len; offset++) { |
| 3426 | uint8_t encoded_byte = buf[offset]; |
| 3427 | *value += (encoded_byte & 0x7f) * multiplier; |
| 3428 | multiplier *= 128; |
| 3429 | |
| 3430 | if ((encoded_byte & 0x80) == 0) return offset + 1; |
| 3431 | } |
| 3432 | |
| 3433 | return 0; |
| 3434 | } |
| 3435 | |
| 3436 | static int mqtt_prop_type_by_id(uint8_t prop_id) { |
| 3437 | size_t i, num_properties = sizeof(s_prop_map) / sizeof(s_prop_map[0]); |
| 3438 | for (i = 0; i < num_properties; ++i) { |
| 3439 | if (s_prop_map[i].id == prop_id) return s_prop_map[i].type; |
| 3440 | } |
| 3441 | return -1; // Property ID not found |
| 3442 | } |
| 3443 | |
| 3444 | // Returns the size of the properties section, without the |
| 3445 | // size of the content's length |
| 3446 | static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) { |
| 3447 | size_t i, size = 0; |
| 3448 | for (i = 0; i < count; i++) { |
| 3449 | size++; // identifier |
| 3450 | switch (mqtt_prop_type_by_id(props[i].id)) { |
| 3451 | case MQTT_PROP_TYPE_STRING_PAIR: |
| 3452 | size += (uint32_t) (props[i].val.len + props[i].key.len + |
| 3453 | 2 * sizeof(uint16_t)); |
| 3454 | break; |
| 3455 | case MQTT_PROP_TYPE_STRING: |
| 3456 | size += (uint32_t) (props[i].val.len + sizeof(uint16_t)); |
| 3457 | break; |
| 3458 | case MQTT_PROP_TYPE_BINARY_DATA: |
| 3459 | size += (uint32_t) (props[i].val.len + sizeof(uint16_t)); |
| 3460 | break; |
| 3461 | case MQTT_PROP_TYPE_VARIABLE_INT: |
| 3462 | size += varint_size((uint32_t) props[i].iv); |
| 3463 | break; |
| 3464 | case MQTT_PROP_TYPE_INT: |
| 3465 | size += (uint32_t) sizeof(uint32_t); |
| 3466 | break; |
| 3467 | case MQTT_PROP_TYPE_SHORT: |
| 3468 | size += (uint32_t) sizeof(uint16_t); |
| 3469 | break; |
| 3470 | case MQTT_PROP_TYPE_BYTE: |
| 3471 | size += (uint32_t) sizeof(uint8_t); |
| 3472 | break; |
| 3473 | default: |
| 3474 | return size; // cannot parse further down |
| 3475 | } |
| 3476 | } |
| 3477 | |
| 3478 | return size; |
| 3479 | } |
| 3480 | |
| 3481 | // returns the entire size of the properties section, including the |
| 3482 | // size of the variable length of the content |
| 3483 | static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) { |
| 3484 | size_t size = get_properties_length(props, count); |
| 3485 | size += varint_size(size); |
| 3486 | return size; |
| 3487 | } |
| 3488 | |
| 3489 | static void mg_send_mqtt_properties(struct mg_connection *c, |
| 3490 | struct mg_mqtt_prop *props, size_t nprops) { |
| 3491 | size_t total_size = get_properties_length(props, nprops); |
| 3492 | uint8_t buf_v[4] = {0, 0, 0, 0}; |
| 3493 | uint8_t buf[4] = {0, 0, 0, 0}; |
| 3494 | size_t i, len = encode_varint(buf, total_size); |
| 3495 | |
| 3496 | mg_send(c, buf, (size_t) len); |
| 3497 | for (i = 0; i < nprops; i++) { |
| 3498 | mg_send(c, &props[i].id, sizeof(props[i].id)); |
| 3499 | switch (mqtt_prop_type_by_id(props[i].id)) { |
| 3500 | case MQTT_PROP_TYPE_STRING_PAIR: |
| 3501 | mg_send_u16(c, mg_htons((uint16_t) props[i].key.len)); |
| 3502 | mg_send(c, props[i].key.buf, props[i].key.len); |
| 3503 | mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); |
| 3504 | mg_send(c, props[i].val.buf, props[i].val.len); |
| 3505 | break; |
| 3506 | case MQTT_PROP_TYPE_BYTE: |
| 3507 | mg_send(c, &props[i].iv, sizeof(uint8_t)); |
| 3508 | break; |
| 3509 | case MQTT_PROP_TYPE_SHORT: |
| 3510 | mg_send_u16(c, mg_htons((uint16_t) props[i].iv)); |
| 3511 | break; |
| 3512 | case MQTT_PROP_TYPE_INT: |
| 3513 | mg_send_u32(c, mg_htonl((uint32_t) props[i].iv)); |
| 3514 | break; |
| 3515 | case MQTT_PROP_TYPE_STRING: |
| 3516 | mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); |
| 3517 | mg_send(c, props[i].val.buf, props[i].val.len); |
| 3518 | break; |
| 3519 | case MQTT_PROP_TYPE_BINARY_DATA: |
| 3520 | mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); |
| 3521 | mg_send(c, props[i].val.buf, props[i].val.len); |
| 3522 | break; |
| 3523 | case MQTT_PROP_TYPE_VARIABLE_INT: |
| 3524 | len = encode_varint(buf_v, props[i].iv); |
| 3525 | mg_send(c, buf_v, (size_t) len); |
| 3526 | break; |
| 3527 | } |
| 3528 | } |
| 3529 | } |
| 3530 | |
| 3531 | size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, |
| 3532 | size_t ofs) { |
| 3533 | uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs; |
| 3534 | uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len; |
| 3535 | size_t new_pos = ofs, len; |
| 3536 | prop->id = i[0]; |
| 3537 | |
| 3538 | if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size) |
| 3539 | return 0; |
| 3540 | i++, new_pos++; |
| 3541 | |
| 3542 | switch (mqtt_prop_type_by_id(prop->id)) { |
| 3543 | case MQTT_PROP_TYPE_STRING_PAIR: |
| 3544 | prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); |
| 3545 | prop->key.buf = (char *) i + 2; |
| 3546 | i += 2 + prop->key.len; |
| 3547 | prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); |
| 3548 | prop->val.buf = (char *) i + 2; |
| 3549 | new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; |
| 3550 | break; |
| 3551 | case MQTT_PROP_TYPE_BYTE: |
| 3552 | prop->iv = (uint8_t) i[0]; |
| 3553 | new_pos++; |
| 3554 | break; |
| 3555 | case MQTT_PROP_TYPE_SHORT: |
| 3556 | prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); |
| 3557 | new_pos += sizeof(uint16_t); |
| 3558 | break; |
| 3559 | case MQTT_PROP_TYPE_INT: |
| 3560 | prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | |
| 3561 | ((uint32_t) i[2] << 8) | i[3]; |
| 3562 | new_pos += sizeof(uint32_t); |
| 3563 | break; |
| 3564 | case MQTT_PROP_TYPE_STRING: |
| 3565 | prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); |
| 3566 | prop->val.buf = (char *) i + 2; |
| 3567 | new_pos += 2 + prop->val.len; |
| 3568 | break; |
| 3569 | case MQTT_PROP_TYPE_BINARY_DATA: |
| 3570 | prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); |
| 3571 | prop->val.buf = (char *) i + 2; |
| 3572 | new_pos += 2 + prop->val.len; |
| 3573 | break; |
| 3574 | case MQTT_PROP_TYPE_VARIABLE_INT: |
| 3575 | len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv); |
| 3576 | new_pos = (!len) ? 0 : new_pos + len; |
| 3577 | break; |
| 3578 | default: |
| 3579 | new_pos = 0; |
| 3580 | } |
| 3581 | |
| 3582 | return new_pos; |
| 3583 | } |
| 3584 | |
| 3585 | void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) { |
| 3586 | char client_id[21]; |
| 3587 | struct mg_str cid = opts->client_id; |
| 3588 | size_t total_len = 7 + 1 + 2 + 2; |
| 3589 | uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0}; |
| 3590 | |
| 3591 | if (cid.len == 0) { |
| 3592 | mg_random_str(client_id, sizeof(client_id) - 1); |
| 3593 | client_id[sizeof(client_id) - 1] = '\0'; |
| 3594 | cid = mg_str(client_id); |
| 3595 | } |
| 3596 | |
| 3597 | if (hdr[6] == 0) hdr[6] = 4; // If version is not set, use 4 (3.1.1) |
| 3598 | c->is_mqtt5 = hdr[6] == 5; // Set version 5 flag |
| 3599 | hdr[7] = (uint8_t) ((opts->qos & 3) << 3); // Connection flags |
| 3600 | if (opts->user.len > 0) { |
| 3601 | total_len += 2 + (uint32_t) opts->user.len; |
| 3602 | hdr[7] |= MQTT_HAS_USER_NAME; |
| 3603 | } |
| 3604 | if (opts->pass.len > 0) { |
| 3605 | total_len += 2 + (uint32_t) opts->pass.len; |
| 3606 | hdr[7] |= MQTT_HAS_PASSWORD; |
| 3607 | } |
| 3608 | if (opts->topic.len > 0) { // allow zero-length msgs, message.len is size_t |
| 3609 | total_len += 4 + (uint32_t) opts->topic.len + (uint32_t) opts->message.len; |
| 3610 | hdr[7] |= MQTT_HAS_WILL; |
| 3611 | } |
| 3612 | if (opts->clean || cid.len == 0) hdr[7] |= MQTT_CLEAN_SESSION; |
| 3613 | if (opts->retain) hdr[7] |= MQTT_WILL_RETAIN; |
| 3614 | total_len += (uint32_t) cid.len; |
| 3615 | if (c->is_mqtt5) { |
| 3616 | total_len += get_props_size(opts->props, opts->num_props); |
| 3617 | if (hdr[7] & MQTT_HAS_WILL) |
| 3618 | total_len += get_props_size(opts->will_props, opts->num_will_props); |
| 3619 | } |
| 3620 | |
| 3621 | mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len); |
| 3622 | mg_send(c, hdr, sizeof(hdr)); |
| 3623 | // keepalive == 0 means "do not disconnect us!" |
| 3624 | mg_send_u16(c, mg_htons((uint16_t) opts->keepalive)); |
| 3625 | |
| 3626 | if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); |
| 3627 | |
| 3628 | mg_send_u16(c, mg_htons((uint16_t) cid.len)); |
| 3629 | mg_send(c, cid.buf, cid.len); |
| 3630 | |
| 3631 | if (hdr[7] & MQTT_HAS_WILL) { |
| 3632 | if (c->is_mqtt5) |
| 3633 | mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props); |
| 3634 | |
| 3635 | mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); |
| 3636 | mg_send(c, opts->topic.buf, opts->topic.len); |
| 3637 | mg_send_u16(c, mg_htons((uint16_t) opts->message.len)); |
| 3638 | mg_send(c, opts->message.buf, opts->message.len); |
| 3639 | } |
| 3640 | if (opts->user.len > 0) { |
| 3641 | mg_send_u16(c, mg_htons((uint16_t) opts->user.len)); |
| 3642 | mg_send(c, opts->user.buf, opts->user.len); |
| 3643 | } |
| 3644 | if (opts->pass.len > 0) { |
| 3645 | mg_send_u16(c, mg_htons((uint16_t) opts->pass.len)); |
| 3646 | mg_send(c, opts->pass.buf, opts->pass.len); |
| 3647 | } |
| 3648 | } |
| 3649 | |
| 3650 | uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) { |
| 3651 | uint16_t id = opts->retransmit_id; |
| 3652 | uint8_t flags = (uint8_t) (((opts->qos & 3) << 1) | (opts->retain ? 1 : 0)); |
| 3653 | size_t len = 2 + opts->topic.len + opts->message.len; |
| 3654 | MG_DEBUG(("%lu [%.*s] <- [%.*s%c", c->id, (int) opts->topic.len, |
| 3655 | (char *) opts->topic.buf, |
| 3656 | (int) (opts->message.len <= 10 ? opts->message.len : 10), |
| 3657 | (char *) opts->message.buf, opts->message.len <= 10 ? ']' : ' ')); |
| 3658 | if (opts->qos > 0) len += 2; |
| 3659 | if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props); |
| 3660 | |
| 3661 | if (opts->qos > 0 && id != 0) flags |= 1 << 3; |
| 3662 | mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len); |
| 3663 | mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); |
| 3664 | mg_send(c, opts->topic.buf, opts->topic.len); |
| 3665 | if (opts->qos > 0) { // need to send 'id' field |
| 3666 | if (id == 0) { // generate new one if not resending |
| 3667 | if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; |
| 3668 | id = c->mgr->mqtt_id; |
| 3669 | } |
| 3670 | mg_send_u16(c, mg_htons(id)); |
| 3671 | } |
| 3672 | |
| 3673 | if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); |
| 3674 | |
| 3675 | if (opts->message.len > 0) mg_send(c, opts->message.buf, opts->message.len); |
| 3676 | return id; |
| 3677 | } |
| 3678 | |
| 3679 | void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) { |
| 3680 | uint8_t qos_ = opts->qos & 3; |
| 3681 | size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0; |
| 3682 | size_t len = 2 + opts->topic.len + 2 + 1 + plen; |
| 3683 | |
| 3684 | mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len); |
| 3685 | if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; |
| 3686 | mg_send_u16(c, mg_htons(c->mgr->mqtt_id)); |
| 3687 | if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); |
| 3688 | |
| 3689 | mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); |
| 3690 | mg_send(c, opts->topic.buf, opts->topic.len); |
| 3691 | mg_send(c, &qos_, sizeof(qos_)); |
| 3692 | } |
| 3693 | |
| 3694 | int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version, |
| 3695 | struct mg_mqtt_message *m) { |
| 3696 | uint8_t lc = 0, *p, *end; |
| 3697 | uint32_t n = 0, len_len = 0; |
| 3698 | |
| 3699 | memset(m, 0, sizeof(*m)); |
| 3700 | m->dgram.buf = (char *) buf; |
| 3701 | if (len < 2) return MQTT_INCOMPLETE; |
| 3702 | m->cmd = (uint8_t) (buf[0] >> 4); |
| 3703 | m->qos = (buf[0] >> 1) & 3; |
| 3704 | |
| 3705 | n = len_len = 0; |
| 3706 | p = (uint8_t *) buf + 1; |
| 3707 | while ((size_t) (p - buf) < len) { |
| 3708 | lc = *((uint8_t *) p++); |
| 3709 | n += (uint32_t) ((lc & 0x7f) << 7 * len_len); |
| 3710 | len_len++; |
| 3711 | if (!(lc & 0x80)) break; |
| 3712 | if (len_len >= 4) return MQTT_MALFORMED; |
| 3713 | } |
| 3714 | end = p + n; |
| 3715 | if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE; |
| 3716 | m->dgram.len = (size_t) (end - buf); |
| 3717 | |
| 3718 | switch (m->cmd) { |
| 3719 | case MQTT_CMD_CONNACK: |
| 3720 | if (end - p < 2) return MQTT_MALFORMED; |
| 3721 | m->ack = p[1]; |
| 3722 | break; |
| 3723 | case MQTT_CMD_PUBACK: |
| 3724 | case MQTT_CMD_PUBREC: |
| 3725 | case MQTT_CMD_PUBREL: |
| 3726 | case MQTT_CMD_PUBCOMP: |
| 3727 | case MQTT_CMD_SUBSCRIBE: |
| 3728 | case MQTT_CMD_SUBACK: |
| 3729 | case MQTT_CMD_UNSUBSCRIBE: |
| 3730 | case MQTT_CMD_UNSUBACK: |
| 3731 | if (p + 2 > end) return MQTT_MALFORMED; |
| 3732 | m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); |
| 3733 | p += 2; |
| 3734 | break; |
| 3735 | case MQTT_CMD_PUBLISH: { |
| 3736 | if (p + 2 > end) return MQTT_MALFORMED; |
| 3737 | m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); |
| 3738 | m->topic.buf = (char *) p + 2; |
| 3739 | p += 2 + m->topic.len; |
| 3740 | if (p > end) return MQTT_MALFORMED; |
| 3741 | if (m->qos > 0) { |
| 3742 | if (p + 2 > end) return MQTT_MALFORMED; |
| 3743 | m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); |
| 3744 | p += 2; |
| 3745 | } |
| 3746 | if (p > end) return MQTT_MALFORMED; |
| 3747 | if (version == 5 && p + 2 < end) { |
| 3748 | len_len = |
| 3749 | (uint32_t) decode_varint(p, (size_t) (end - p), &m->props_size); |
| 3750 | if (!len_len) return MQTT_MALFORMED; |
| 3751 | m->props_start = (size_t) (p + len_len - buf); |
| 3752 | p += len_len + m->props_size; |
| 3753 | } |
| 3754 | if (p > end) return MQTT_MALFORMED; |
| 3755 | m->data.buf = (char *) p; |
| 3756 | m->data.len = (size_t) (end - p); |
| 3757 | break; |
| 3758 | } |
| 3759 | default: |
| 3760 | break; |
| 3761 | } |
| 3762 | return MQTT_OK; |
| 3763 | } |
| 3764 | |
| 3765 | static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 3766 | if (ev == MG_EV_READ) { |
| 3767 | for (;;) { |
| 3768 | uint8_t version = c->is_mqtt5 ? 5 : 4; |
| 3769 | struct mg_mqtt_message mm; |
| 3770 | int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, version, &mm); |
| 3771 | if (rc == MQTT_MALFORMED) { |
| 3772 | MG_ERROR(("%lu MQTT malformed message", c->id)); |
| 3773 | c->is_closing = 1; |
| 3774 | break; |
| 3775 | } else if (rc == MQTT_OK) { |
| 3776 | MG_VERBOSE(("%lu MQTT CMD %d len %d [%.*s]", c->id, mm.cmd, |
| 3777 | (int) mm.dgram.len, (int) mm.data.len, mm.data.buf)); |
| 3778 | switch (mm.cmd) { |
| 3779 | case MQTT_CMD_CONNACK: |
| 3780 | mg_call(c, MG_EV_MQTT_OPEN, &mm.ack); |
| 3781 | if (mm.ack == 0) { |
| 3782 | MG_DEBUG(("%lu Connected", c->id)); |
| 3783 | } else { |
| 3784 | MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack)); |
| 3785 | c->is_closing = 1; |
| 3786 | } |
| 3787 | break; |
| 3788 | case MQTT_CMD_PUBLISH: { |
| 3789 | MG_DEBUG(("%lu [%.*s] -> [%.*s%c", c->id, (int) mm.topic.len, |
| 3790 | mm.topic.buf, |
| 3791 | (int) (mm.data.len <= 10 ? mm.data.len : 10), mm.data.buf, |
| 3792 | mm.data.len <= 10 ? ']' : ' ')); |
| 3793 | if (mm.qos > 0) { |
| 3794 | uint16_t id = mg_ntohs(mm.id); |
| 3795 | uint32_t remaining_len = sizeof(id); |
| 3796 | if (c->is_mqtt5) remaining_len += 2; // 3.4.2 |
| 3797 | |
| 3798 | mg_mqtt_send_header( |
| 3799 | c, |
| 3800 | (uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK), |
| 3801 | 0, remaining_len); |
| 3802 | mg_send(c, &id, sizeof(id)); |
| 3803 | |
| 3804 | if (c->is_mqtt5) { |
| 3805 | uint16_t zero = 0; |
| 3806 | mg_send(c, &zero, sizeof(zero)); |
| 3807 | } |
| 3808 | } |
| 3809 | mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff |
| 3810 | break; |
| 3811 | } |
| 3812 | case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc |
| 3813 | uint16_t id = mg_ntohs(mm.id); |
| 3814 | uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1 |
| 3815 | mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len); |
| 3816 | mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2 |
| 3817 | break; |
| 3818 | } |
| 3819 | case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc |
| 3820 | uint16_t id = mg_ntohs(mm.id); |
| 3821 | uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1 |
| 3822 | mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len); |
| 3823 | mg_send(c, &id, sizeof(id)); |
| 3824 | break; |
| 3825 | } |
| 3826 | } |
| 3827 | mg_call(c, MG_EV_MQTT_CMD, &mm); |
| 3828 | mg_iobuf_del(&c->recv, 0, mm.dgram.len); |
| 3829 | } else { |
| 3830 | break; |
| 3831 | } |
| 3832 | } |
| 3833 | } |
| 3834 | (void) ev_data; |
| 3835 | } |
| 3836 | |
| 3837 | void mg_mqtt_ping(struct mg_connection *nc) { |
| 3838 | mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0); |
| 3839 | } |
| 3840 | |
| 3841 | void mg_mqtt_pong(struct mg_connection *nc) { |
| 3842 | mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0); |
| 3843 | } |
| 3844 | |
| 3845 | void mg_mqtt_disconnect(struct mg_connection *c, |
| 3846 | const struct mg_mqtt_opts *opts) { |
| 3847 | size_t len = 0; |
| 3848 | if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props); |
| 3849 | mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len); |
| 3850 | |
| 3851 | if (c->is_mqtt5) { |
| 3852 | uint8_t zero = 0; |
| 3853 | mg_send(c, &zero, sizeof(zero)); // reason code |
| 3854 | mg_send_mqtt_properties(c, opts->props, opts->num_props); |
| 3855 | } |
| 3856 | } |
| 3857 | |
| 3858 | struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url, |
| 3859 | const struct mg_mqtt_opts *opts, |
| 3860 | mg_event_handler_t fn, void *fn_data) { |
| 3861 | struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); |
| 3862 | if (c != NULL) { |
| 3863 | struct mg_mqtt_opts empty; |
| 3864 | memset(&empty, 0, sizeof(empty)); |
| 3865 | mg_mqtt_login(c, opts == NULL ? &empty : opts); |
| 3866 | c->pfn = mqtt_cb; |
| 3867 | } |
| 3868 | return c; |
| 3869 | } |
| 3870 | |
| 3871 | struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, |
| 3872 | mg_event_handler_t fn, void *fn_data) { |
| 3873 | struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); |
| 3874 | if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr; |
| 3875 | return c; |
| 3876 | } |
| 3877 | |
| 3878 | #ifdef MG_ENABLE_LINES |
| 3879 | #line 1 "src/net.c" |
| 3880 | #endif |
| 3881 | |
| 3882 | |
| 3883 | |
| 3884 | |
| 3885 | |
| 3886 | |
| 3887 | |
| 3888 | |
| 3889 | |
| 3890 | size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) { |
| 3891 | size_t old = c->send.len; |
| 3892 | mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); |
| 3893 | return c->send.len - old; |
| 3894 | } |
| 3895 | |
| 3896 | size_t mg_printf(struct mg_connection *c, const char *fmt, ...) { |
| 3897 | size_t len = 0; |
| 3898 | va_list ap; |
| 3899 | va_start(ap, fmt); |
| 3900 | len = mg_vprintf(c, fmt, &ap); |
| 3901 | va_end(ap); |
| 3902 | return len; |
| 3903 | } |
| 3904 | |
| 3905 | static bool mg_atonl(struct mg_str str, struct mg_addr *addr) { |
| 3906 | uint32_t localhost = mg_htonl(0x7f000001); |
| 3907 | if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false; |
| 3908 | memcpy(addr->ip, &localhost, sizeof(uint32_t)); |
| 3909 | addr->is_ip6 = false; |
| 3910 | return true; |
| 3911 | } |
| 3912 | |
| 3913 | static bool mg_atone(struct mg_str str, struct mg_addr *addr) { |
| 3914 | if (str.len > 0) return false; |
| 3915 | memset(addr->ip, 0, sizeof(addr->ip)); |
| 3916 | addr->is_ip6 = false; |
| 3917 | return true; |
| 3918 | } |
| 3919 | |
| 3920 | static bool mg_aton4(struct mg_str str, struct mg_addr *addr) { |
| 3921 | uint8_t data[4] = {0, 0, 0, 0}; |
| 3922 | size_t i, num_dots = 0; |
| 3923 | for (i = 0; i < str.len; i++) { |
| 3924 | if (str.buf[i] >= '0' && str.buf[i] <= '9') { |
| 3925 | int octet = data[num_dots] * 10 + (str.buf[i] - '0'); |
| 3926 | if (octet > 255) return false; |
| 3927 | data[num_dots] = (uint8_t) octet; |
| 3928 | } else if (str.buf[i] == '.') { |
| 3929 | if (num_dots >= 3 || i == 0 || str.buf[i - 1] == '.') return false; |
| 3930 | num_dots++; |
| 3931 | } else { |
| 3932 | return false; |
| 3933 | } |
| 3934 | } |
| 3935 | if (num_dots != 3 || str.buf[i - 1] == '.') return false; |
| 3936 | memcpy(&addr->ip, data, sizeof(data)); |
| 3937 | addr->is_ip6 = false; |
| 3938 | return true; |
| 3939 | } |
| 3940 | |
| 3941 | static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) { |
| 3942 | int i; |
| 3943 | uint32_t ipv4; |
| 3944 | if (str.len < 14) return false; |
| 3945 | if (str.buf[0] != ':' || str.buf[1] != ':' || str.buf[6] != ':') return false; |
| 3946 | for (i = 2; i < 6; i++) { |
| 3947 | if (str.buf[i] != 'f' && str.buf[i] != 'F') return false; |
| 3948 | } |
| 3949 | // struct mg_str s = mg_str_n(&str.buf[7], str.len - 7); |
| 3950 | if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false; |
| 3951 | memcpy(&ipv4, addr->ip, sizeof(ipv4)); |
| 3952 | memset(addr->ip, 0, sizeof(addr->ip)); |
| 3953 | addr->ip[10] = addr->ip[11] = 255; |
| 3954 | memcpy(&addr->ip[12], &ipv4, 4); |
| 3955 | addr->is_ip6 = true; |
| 3956 | return true; |
| 3957 | } |
| 3958 | |
| 3959 | static bool mg_aton6(struct mg_str str, struct mg_addr *addr) { |
| 3960 | size_t i, j = 0, n = 0, dc = 42; |
| 3961 | addr->scope_id = 0; |
| 3962 | if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2; |
| 3963 | if (mg_v4mapped(str, addr)) return true; |
| 3964 | for (i = 0; i < str.len; i++) { |
| 3965 | if ((str.buf[i] >= '0' && str.buf[i] <= '9') || |
| 3966 | (str.buf[i] >= 'a' && str.buf[i] <= 'f') || |
| 3967 | (str.buf[i] >= 'A' && str.buf[i] <= 'F')) { |
| 3968 | unsigned long val = 0; // TODO(): This loops on chars, refactor |
| 3969 | if (i > j + 3) return false; |
| 3970 | // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j])); |
| 3971 | mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val)); |
| 3972 | addr->ip[n] = (uint8_t) ((val >> 8) & 255); |
| 3973 | addr->ip[n + 1] = (uint8_t) (val & 255); |
| 3974 | } else if (str.buf[i] == ':') { |
| 3975 | j = i + 1; |
| 3976 | if (i > 0 && str.buf[i - 1] == ':') { |
| 3977 | dc = n; // Double colon |
| 3978 | if (i > 1 && str.buf[i - 2] == ':') return false; |
| 3979 | } else if (i > 0) { |
| 3980 | n += 2; |
| 3981 | } |
| 3982 | if (n > 14) return false; |
| 3983 | addr->ip[n] = addr->ip[n + 1] = 0; // For trailing :: |
| 3984 | } else if (str.buf[i] == '%') { // Scope ID, last in string |
| 3985 | return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10, |
| 3986 | &addr->scope_id, sizeof(uint8_t)); |
| 3987 | } else { |
| 3988 | return false; |
| 3989 | } |
| 3990 | } |
| 3991 | if (n < 14 && dc == 42) return false; |
| 3992 | if (n < 14) { |
| 3993 | memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2); |
| 3994 | memset(&addr->ip[dc], 0, 14 - n); |
| 3995 | } |
| 3996 | |
| 3997 | addr->is_ip6 = true; |
| 3998 | return true; |
| 3999 | } |
| 4000 | |
| 4001 | bool mg_aton(struct mg_str str, struct mg_addr *addr) { |
| 4002 | // MG_INFO(("[%.*s]", (int) str.len, str.buf)); |
| 4003 | return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) || |
| 4004 | mg_aton6(str, addr); |
| 4005 | } |
| 4006 | |
| 4007 | struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) { |
| 4008 | struct mg_connection *c = |
| 4009 | (struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize); |
| 4010 | if (c != NULL) { |
| 4011 | c->mgr = mgr; |
| 4012 | c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE; |
| 4013 | c->id = ++mgr->nextid; |
| 4014 | MG_PROF_INIT(c); |
| 4015 | } |
| 4016 | return c; |
| 4017 | } |
| 4018 | |
| 4019 | void mg_close_conn(struct mg_connection *c) { |
| 4020 | mg_resolve_cancel(c); // Close any pending DNS query |
| 4021 | LIST_DELETE(struct mg_connection, &c->mgr->conns, c); |
| 4022 | if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL; |
| 4023 | if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL; |
| 4024 | // Order of operations is important. `MG_EV_CLOSE` event must be fired |
| 4025 | // before we deallocate received data, see #1331 |
| 4026 | mg_call(c, MG_EV_CLOSE, NULL); |
| 4027 | MG_DEBUG(("%lu %ld closed", c->id, c->fd)); |
| 4028 | MG_PROF_DUMP(c); |
| 4029 | MG_PROF_FREE(c); |
| 4030 | |
| 4031 | mg_tls_free(c); |
| 4032 | mg_iobuf_free(&c->recv); |
| 4033 | mg_iobuf_free(&c->send); |
| 4034 | mg_iobuf_free(&c->rtls); |
| 4035 | mg_bzero((unsigned char *) c, sizeof(*c)); |
| 4036 | free(c); |
| 4037 | } |
| 4038 | |
| 4039 | struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url, |
| 4040 | mg_event_handler_t fn, void *fn_data) { |
| 4041 | struct mg_connection *c = NULL; |
| 4042 | if (url == NULL || url[0] == '\0') { |
| 4043 | MG_ERROR(("null url")); |
| 4044 | } else if ((c = mg_alloc_conn(mgr)) == NULL) { |
| 4045 | MG_ERROR(("OOM")); |
| 4046 | } else { |
| 4047 | LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); |
| 4048 | c->is_udp = (strncmp(url, "udp:", 4) == 0); |
| 4049 | c->fd = (void *) (size_t) MG_INVALID_SOCKET; |
| 4050 | c->fn = fn; |
| 4051 | c->is_client = true; |
| 4052 | c->fn_data = fn_data; |
| 4053 | MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); |
| 4054 | mg_call(c, MG_EV_OPEN, (void *) url); |
| 4055 | mg_resolve(c, url); |
| 4056 | } |
| 4057 | return c; |
| 4058 | } |
| 4059 | |
| 4060 | struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, |
| 4061 | mg_event_handler_t fn, void *fn_data) { |
| 4062 | struct mg_connection *c = NULL; |
| 4063 | if ((c = mg_alloc_conn(mgr)) == NULL) { |
| 4064 | MG_ERROR(("OOM %s", url)); |
| 4065 | } else if (!mg_open_listener(c, url)) { |
| 4066 | MG_ERROR(("Failed: %s, errno %d", url, errno)); |
| 4067 | MG_PROF_FREE(c); |
| 4068 | free(c); |
| 4069 | c = NULL; |
| 4070 | } else { |
| 4071 | c->is_listening = 1; |
| 4072 | c->is_udp = strncmp(url, "udp:", 4) == 0; |
| 4073 | LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); |
| 4074 | c->fn = fn; |
| 4075 | c->fn_data = fn_data; |
| 4076 | mg_call(c, MG_EV_OPEN, NULL); |
| 4077 | if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must |
| 4078 | MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); |
| 4079 | } |
| 4080 | return c; |
| 4081 | } |
| 4082 | |
| 4083 | struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd, |
| 4084 | mg_event_handler_t fn, void *fn_data) { |
| 4085 | struct mg_connection *c = mg_alloc_conn(mgr); |
| 4086 | if (c != NULL) { |
| 4087 | c->fd = (void *) (size_t) fd; |
| 4088 | c->fn = fn; |
| 4089 | c->fn_data = fn_data; |
| 4090 | MG_EPOLL_ADD(c); |
| 4091 | mg_call(c, MG_EV_OPEN, NULL); |
| 4092 | LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); |
| 4093 | } |
| 4094 | return c; |
| 4095 | } |
| 4096 | |
| 4097 | struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, |
| 4098 | unsigned flags, void (*fn)(void *), void *arg) { |
| 4099 | struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t)); |
| 4100 | if (t != NULL) { |
| 4101 | flags |= MG_TIMER_AUTODELETE; // We have calloc-ed it, so autodelete |
| 4102 | mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg); |
| 4103 | } |
| 4104 | return t; |
| 4105 | } |
| 4106 | |
| 4107 | long mg_io_recv(struct mg_connection *c, void *buf, size_t len) { |
| 4108 | if (c->rtls.len == 0) return MG_IO_WAIT; |
| 4109 | if (len > c->rtls.len) len = c->rtls.len; |
| 4110 | memcpy(buf, c->rtls.buf, len); |
| 4111 | mg_iobuf_del(&c->rtls, 0, len); |
| 4112 | return (long) len; |
| 4113 | } |
| 4114 | |
| 4115 | void mg_mgr_free(struct mg_mgr *mgr) { |
| 4116 | struct mg_connection *c; |
| 4117 | struct mg_timer *tmp, *t = mgr->timers; |
| 4118 | while (t != NULL) tmp = t->next, free(t), t = tmp; |
| 4119 | mgr->timers = NULL; // Important. Next call to poll won't touch timers |
| 4120 | for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1; |
| 4121 | mg_mgr_poll(mgr, 0); |
| 4122 | #if MG_ENABLE_FREERTOS_TCP |
| 4123 | FreeRTOS_DeleteSocketSet(mgr->ss); |
| 4124 | #endif |
| 4125 | MG_DEBUG(("All connections closed")); |
| 4126 | #if MG_ENABLE_EPOLL |
| 4127 | if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1; |
| 4128 | #endif |
| 4129 | mg_tls_ctx_free(mgr); |
| 4130 | } |
| 4131 | |
| 4132 | void mg_mgr_init(struct mg_mgr *mgr) { |
| 4133 | memset(mgr, 0, sizeof(*mgr)); |
| 4134 | #if MG_ENABLE_EPOLL |
| 4135 | if ((mgr->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) |
| 4136 | MG_ERROR(("epoll_create1 errno %d", errno)); |
| 4137 | #else |
| 4138 | mgr->epoll_fd = -1; |
| 4139 | #endif |
| 4140 | #if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK |
| 4141 | // clang-format off |
| 4142 | { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); } |
| 4143 | // clang-format on |
| 4144 | #elif MG_ENABLE_FREERTOS_TCP |
| 4145 | mgr->ss = FreeRTOS_CreateSocketSet(); |
| 4146 | #elif defined(__unix) || defined(__unix__) || defined(__APPLE__) |
| 4147 | // Ignore SIGPIPE signal, so if client cancels the request, it |
| 4148 | // won't kill the whole process. |
| 4149 | signal(SIGPIPE, SIG_IGN); |
| 4150 | #elif MG_ENABLE_TCPIP_DRIVER_INIT && defined(MG_TCPIP_DRIVER_INIT) |
| 4151 | MG_TCPIP_DRIVER_INIT(mgr); |
| 4152 | #endif |
| 4153 | mgr->pipe = MG_INVALID_SOCKET; |
| 4154 | mgr->dnstimeout = 3000; |
| 4155 | mgr->dns4.url = "udp://8.8.8.8:53"; |
| 4156 | mgr->dns6.url = "udp://[2001:4860:4860::8888]:53"; |
| 4157 | mg_tls_ctx_init(mgr); |
| 4158 | } |
| 4159 | |
| 4160 | #ifdef MG_ENABLE_LINES |
| 4161 | #line 1 "src/net_builtin.c" |
| 4162 | #endif |
| 4163 | |
| 4164 | |
| 4165 | #if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP |
| 4166 | #define MG_EPHEMERAL_PORT_BASE 32768 |
| 4167 | #define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a)))) |
| 4168 | |
| 4169 | #ifndef MIP_TCP_KEEPALIVE_MS |
| 4170 | #define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms |
| 4171 | #endif |
| 4172 | |
| 4173 | #define MIP_TCP_ACK_MS 150 // Timeout for ACKing |
| 4174 | #define MIP_ARP_RESP_MS 100 // Timeout for ARP response |
| 4175 | #define MIP_TCP_SYN_MS 15000 // Timeout for connection establishment |
| 4176 | #define MIP_TCP_FIN_MS 1000 // Timeout for closing connection |
| 4177 | #define MIP_TCP_WIN 6000 // TCP window size |
| 4178 | |
| 4179 | struct connstate { |
| 4180 | uint32_t seq, ack; // TCP seq/ack counters |
| 4181 | uint64_t timer; // TCP keep-alive / ACK timer |
| 4182 | uint32_t acked; // Last ACK-ed number |
| 4183 | size_t unacked; // Not acked bytes |
| 4184 | uint8_t mac[6]; // Peer MAC address |
| 4185 | uint8_t ttype; // Timer type. 0: ack, 1: keep-alive |
| 4186 | #define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive |
| 4187 | #define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon |
| 4188 | #define MIP_TTYPE_ARP 2 // ARP resolve sent, waiting for response |
| 4189 | #define MIP_TTYPE_SYN 3 // SYN sent, waiting for response |
| 4190 | #define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection |
| 4191 | uint8_t tmiss; // Number of keep-alive misses |
| 4192 | struct mg_iobuf raw; // For TLS only. Incoming raw data |
| 4193 | bool fin_rcvd; // We have received FIN from the peer |
| 4194 | bool twclosure; // 3-way closure done |
| 4195 | }; |
| 4196 | |
| 4197 | #pragma pack(push, 1) |
| 4198 | |
| 4199 | struct lcp { |
| 4200 | uint8_t addr, ctrl, proto[2], code, id, len[2]; |
| 4201 | }; |
| 4202 | |
| 4203 | struct eth { |
| 4204 | uint8_t dst[6]; // Destination MAC address |
| 4205 | uint8_t src[6]; // Source MAC address |
| 4206 | uint16_t type; // Ethernet type |
| 4207 | }; |
| 4208 | |
| 4209 | struct ip { |
| 4210 | uint8_t ver; // Version |
| 4211 | uint8_t tos; // Unused |
| 4212 | uint16_t len; // Length |
| 4213 | uint16_t id; // Unused |
| 4214 | uint16_t frag; // Fragmentation |
| 4215 | #define IP_FRAG_OFFSET_MSK 0x1fff |
| 4216 | #define IP_MORE_FRAGS_MSK 0x2000 |
| 4217 | uint8_t ttl; // Time to live |
| 4218 | uint8_t proto; // Upper level protocol |
| 4219 | uint16_t csum; // Checksum |
| 4220 | uint32_t src; // Source IP |
| 4221 | uint32_t dst; // Destination IP |
| 4222 | }; |
| 4223 | |
| 4224 | struct ip6 { |
| 4225 | uint8_t ver; // Version |
| 4226 | uint8_t opts[3]; // Options |
| 4227 | uint16_t len; // Length |
| 4228 | uint8_t proto; // Upper level protocol |
| 4229 | uint8_t ttl; // Time to live |
| 4230 | uint8_t src[16]; // Source IP |
| 4231 | uint8_t dst[16]; // Destination IP |
| 4232 | }; |
| 4233 | |
| 4234 | struct icmp { |
| 4235 | uint8_t type; |
| 4236 | uint8_t code; |
| 4237 | uint16_t csum; |
| 4238 | }; |
| 4239 | |
| 4240 | struct arp { |
| 4241 | uint16_t fmt; // Format of hardware address |
| 4242 | uint16_t pro; // Format of protocol address |
| 4243 | uint8_t hlen; // Length of hardware address |
| 4244 | uint8_t plen; // Length of protocol address |
| 4245 | uint16_t op; // Operation |
| 4246 | uint8_t sha[6]; // Sender hardware address |
| 4247 | uint32_t spa; // Sender protocol address |
| 4248 | uint8_t tha[6]; // Target hardware address |
| 4249 | uint32_t tpa; // Target protocol address |
| 4250 | }; |
| 4251 | |
| 4252 | struct tcp { |
| 4253 | uint16_t sport; // Source port |
| 4254 | uint16_t dport; // Destination port |
| 4255 | uint32_t seq; // Sequence number |
| 4256 | uint32_t ack; // Acknowledgement number |
| 4257 | uint8_t off; // Data offset |
| 4258 | uint8_t flags; // TCP flags |
| 4259 | #define TH_FIN 0x01 |
| 4260 | #define TH_SYN 0x02 |
| 4261 | #define TH_RST 0x04 |
| 4262 | #define TH_PUSH 0x08 |
| 4263 | #define TH_ACK 0x10 |
| 4264 | #define TH_URG 0x20 |
| 4265 | #define TH_ECE 0x40 |
| 4266 | #define TH_CWR 0x80 |
| 4267 | uint16_t win; // Window |
| 4268 | uint16_t csum; // Checksum |
| 4269 | uint16_t urp; // Urgent pointer |
| 4270 | }; |
| 4271 | |
| 4272 | struct udp { |
| 4273 | uint16_t sport; // Source port |
| 4274 | uint16_t dport; // Destination port |
| 4275 | uint16_t len; // UDP length |
| 4276 | uint16_t csum; // UDP checksum |
| 4277 | }; |
| 4278 | |
| 4279 | struct dhcp { |
| 4280 | uint8_t op, htype, hlen, hops; |
| 4281 | uint32_t xid; |
| 4282 | uint16_t secs, flags; |
| 4283 | uint32_t ciaddr, yiaddr, siaddr, giaddr; |
| 4284 | uint8_t hwaddr[208]; |
| 4285 | uint32_t magic; |
| 4286 | uint8_t options[30 + sizeof(((struct mg_tcpip_if *) 0)->dhcp_name)]; |
| 4287 | }; |
| 4288 | |
| 4289 | #pragma pack(pop) |
| 4290 | |
| 4291 | struct pkt { |
| 4292 | struct mg_str raw; // Raw packet data |
| 4293 | struct mg_str pay; // Payload data |
| 4294 | struct eth *eth; |
| 4295 | struct llc *llc; |
| 4296 | struct arp *arp; |
| 4297 | struct ip *ip; |
| 4298 | struct ip6 *ip6; |
| 4299 | struct icmp *icmp; |
| 4300 | struct tcp *tcp; |
| 4301 | struct udp *udp; |
| 4302 | struct dhcp *dhcp; |
| 4303 | }; |
| 4304 | |
| 4305 | static void mg_tcpip_call(struct mg_tcpip_if *ifp, int ev, void *ev_data) { |
| 4306 | if (ifp->fn != NULL) ifp->fn(ifp, ev, ev_data); |
| 4307 | } |
| 4308 | |
| 4309 | static void send_syn(struct mg_connection *c); |
| 4310 | |
| 4311 | static void mkpay(struct pkt *pkt, void *p) { |
| 4312 | pkt->pay = |
| 4313 | mg_str_n((char *) p, (size_t) (&pkt->raw.buf[pkt->raw.len] - (char *) p)); |
| 4314 | } |
| 4315 | |
| 4316 | static uint32_t csumup(uint32_t sum, const void *buf, size_t len) { |
| 4317 | size_t i; |
| 4318 | const uint8_t *p = (const uint8_t *) buf; |
| 4319 | for (i = 0; i < len; i++) sum += i & 1 ? p[i] : ((uint32_t) p[i]) << 8; |
| 4320 | return sum; |
| 4321 | } |
| 4322 | |
| 4323 | static uint16_t csumfin(uint32_t sum) { |
| 4324 | while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); |
| 4325 | return mg_htons(~sum & 0xffff); |
| 4326 | } |
| 4327 | |
| 4328 | static uint16_t ipcsum(const void *buf, size_t len) { |
| 4329 | uint32_t sum = csumup(0, buf, len); |
| 4330 | return csumfin(sum); |
| 4331 | } |
| 4332 | |
| 4333 | static void settmout(struct mg_connection *c, uint8_t type) { |
| 4334 | struct mg_tcpip_if *ifp = c->mgr->ifp; |
| 4335 | struct connstate *s = (struct connstate *) (c + 1); |
| 4336 | unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS |
| 4337 | : type == MIP_TTYPE_ARP ? MIP_ARP_RESP_MS |
| 4338 | : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS |
| 4339 | : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS |
| 4340 | : MIP_TCP_KEEPALIVE_MS; |
| 4341 | s->timer = ifp->now + n; |
| 4342 | s->ttype = type; |
| 4343 | MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer)); |
| 4344 | } |
| 4345 | |
| 4346 | static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) { |
| 4347 | size_t n = ifp->driver->tx(ifp->tx.buf, len, ifp); |
| 4348 | if (n == len) ifp->nsent++; |
| 4349 | return n; |
| 4350 | } |
| 4351 | |
| 4352 | void mg_tcpip_arp_request(struct mg_tcpip_if *ifp, uint32_t ip, uint8_t *mac) { |
| 4353 | struct eth *eth = (struct eth *) ifp->tx.buf; |
| 4354 | struct arp *arp = (struct arp *) (eth + 1); |
| 4355 | memset(eth->dst, 255, sizeof(eth->dst)); |
| 4356 | memcpy(eth->src, ifp->mac, sizeof(eth->src)); |
| 4357 | eth->type = mg_htons(0x806); |
| 4358 | memset(arp, 0, sizeof(*arp)); |
| 4359 | arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6, |
| 4360 | arp->plen = 4; |
| 4361 | arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip; |
| 4362 | memcpy(arp->sha, ifp->mac, sizeof(arp->sha)); |
| 4363 | if (mac != NULL) memcpy(arp->tha, mac, sizeof(arp->tha)); |
| 4364 | ether_output(ifp, PDIFF(eth, arp + 1)); |
| 4365 | } |
| 4366 | |
| 4367 | static void onstatechange(struct mg_tcpip_if *ifp) { |
| 4368 | if (ifp->state == MG_TCPIP_STATE_READY) { |
| 4369 | MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip)); |
| 4370 | MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); |
| 4371 | MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); |
| 4372 | } else if (ifp->state == MG_TCPIP_STATE_IP) { |
| 4373 | MG_ERROR(("Got IP")); |
| 4374 | mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request |
| 4375 | } else if (ifp->state == MG_TCPIP_STATE_UP) { |
| 4376 | MG_ERROR(("Link up")); |
| 4377 | srand((unsigned int) mg_millis()); |
| 4378 | } else if (ifp->state == MG_TCPIP_STATE_DOWN) { |
| 4379 | MG_ERROR(("Link down")); |
| 4380 | } |
| 4381 | mg_tcpip_call(ifp, MG_TCPIP_EV_ST_CHG, &ifp->state); |
| 4382 | } |
| 4383 | |
| 4384 | static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst, |
| 4385 | uint8_t proto, uint32_t ip_src, uint32_t ip_dst, |
| 4386 | size_t plen) { |
| 4387 | struct eth *eth = (struct eth *) ifp->tx.buf; |
| 4388 | struct ip *ip = (struct ip *) (eth + 1); |
| 4389 | memcpy(eth->dst, mac_dst, sizeof(eth->dst)); |
| 4390 | memcpy(eth->src, ifp->mac, sizeof(eth->src)); // Use our MAC |
| 4391 | eth->type = mg_htons(0x800); |
| 4392 | memset(ip, 0, sizeof(*ip)); |
| 4393 | ip->ver = 0x45; // Version 4, header length 5 words |
| 4394 | ip->frag = mg_htons(0x4000); // Don't fragment |
| 4395 | ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen)); |
| 4396 | ip->ttl = 64; |
| 4397 | ip->proto = proto; |
| 4398 | ip->src = ip_src; |
| 4399 | ip->dst = ip_dst; |
| 4400 | ip->csum = ipcsum(ip, sizeof(*ip)); |
| 4401 | return ip; |
| 4402 | } |
| 4403 | |
| 4404 | static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, |
| 4405 | uint16_t sport, uint32_t ip_dst, uint16_t dport, |
| 4406 | const void *buf, size_t len) { |
| 4407 | struct ip *ip = |
| 4408 | tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp)); |
| 4409 | struct udp *udp = (struct udp *) (ip + 1); |
| 4410 | // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len)); |
| 4411 | udp->sport = sport; |
| 4412 | udp->dport = dport; |
| 4413 | udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); |
| 4414 | udp->csum = 0; |
| 4415 | uint32_t cs = csumup(0, udp, sizeof(*udp)); |
| 4416 | cs = csumup(cs, buf, len); |
| 4417 | cs = csumup(cs, &ip->src, sizeof(ip->src)); |
| 4418 | cs = csumup(cs, &ip->dst, sizeof(ip->dst)); |
| 4419 | cs += (uint32_t) (ip->proto + sizeof(*udp) + len); |
| 4420 | udp->csum = csumfin(cs); |
| 4421 | memmove(udp + 1, buf, len); |
| 4422 | // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len)); |
| 4423 | ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len); |
| 4424 | } |
| 4425 | |
| 4426 | static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, |
| 4427 | uint32_t ip_dst, uint8_t *opts, size_t optslen, |
| 4428 | bool ciaddr) { |
| 4429 | // https://datatracker.ietf.org/doc/html/rfc2132#section-9.6 |
| 4430 | struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; |
| 4431 | dhcp.magic = mg_htonl(0x63825363); |
| 4432 | memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac)); |
| 4433 | memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid)); |
| 4434 | memcpy(&dhcp.options, opts, optslen); |
| 4435 | if (ciaddr) dhcp.ciaddr = ip_src; |
| 4436 | tx_udp(ifp, mac_dst, ip_src, mg_htons(68), ip_dst, mg_htons(67), &dhcp, |
| 4437 | sizeof(dhcp)); |
| 4438 | } |
| 4439 | |
| 4440 | static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; |
| 4441 | |
| 4442 | // RFC-2131 #4.3.6, #4.4.1; RFC-2132 #9.8 |
| 4443 | static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req, |
| 4444 | uint32_t ip_srv) { |
| 4445 | uint8_t extra = (uint8_t) ((ifp->enable_req_dns ? 1 : 0) + |
| 4446 | (ifp->enable_req_sntp ? 1 : 0)); |
| 4447 | size_t len = strlen(ifp->dhcp_name); |
| 4448 | size_t olen = 21 + len + extra + 2 + 1; // Total length of options |
| 4449 | #define OPTS_MAXLEN (21 + sizeof(ifp->dhcp_name) + 2 + 2 + 1) |
| 4450 | uint8_t opts[OPTS_MAXLEN]; // Allocate options (max size possible) |
| 4451 | uint8_t *p = opts; |
| 4452 | assert(olen <= sizeof(opts)); |
| 4453 | memset(opts, 0, sizeof(opts)); |
| 4454 | *p++ = 53, *p++ = 1, *p++ = 3; // Type: DHCP request |
| 4455 | *p++ = 54, *p++ = 4, memcpy(p, &ip_srv, 4), p += 4; // DHCP server ID |
| 4456 | *p++ = 50, *p++ = 4, memcpy(p, &ip_req, 4), p += 4; // Requested IP |
| 4457 | *p++ = 12, *p++ = (uint8_t) (len & 255); // DHCP host |
| 4458 | memcpy(p, ifp->dhcp_name, len), p += len; // name |
| 4459 | *p++ = 55, *p++ = 2 + extra, *p++ = 1, *p++ = 3; // GW, MASK |
| 4460 | if (ifp->enable_req_dns) *p++ = 6; // DNS |
| 4461 | if (ifp->enable_req_sntp) *p++ = 42; // SNTP |
| 4462 | *p++ = 255; // End of options |
| 4463 | // assert((size_t) (p - opts) < olen); |
| 4464 | tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, olen, 0); |
| 4465 | MG_DEBUG(("DHCP req sent")); |
| 4466 | } |
| 4467 | |
| 4468 | // RFC-2131 #4.3.6, #4.4.5 (renewing: unicast, rebinding: bcast) |
| 4469 | static void tx_dhcp_request_re(struct mg_tcpip_if *ifp, uint8_t *mac_dst, |
| 4470 | uint32_t ip_src, uint32_t ip_dst) { |
| 4471 | uint8_t opts[] = { |
| 4472 | 53, 1, 3, // Type: DHCP request |
| 4473 | 255 // End of options |
| 4474 | }; |
| 4475 | tx_dhcp(ifp, mac_dst, ip_src, ip_dst, opts, sizeof(opts), true); |
| 4476 | MG_DEBUG(("DHCP req sent")); |
| 4477 | } |
| 4478 | |
| 4479 | static void tx_dhcp_discover(struct mg_tcpip_if *ifp) { |
| 4480 | uint8_t opts[] = { |
| 4481 | 53, 1, 1, // Type: DHCP discover |
| 4482 | 55, 2, 1, 3, // Parameters: ip, mask |
| 4483 | 255 // End of options |
| 4484 | }; |
| 4485 | tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); |
| 4486 | MG_DEBUG(("DHCP discover sent. Our MAC: %M", mg_print_mac, ifp->mac)); |
| 4487 | } |
| 4488 | |
| 4489 | static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt, |
| 4490 | bool lsn) { |
| 4491 | struct mg_connection *c = NULL; |
| 4492 | for (c = mgr->conns; c != NULL; c = c->next) { |
| 4493 | if (c->is_arplooking && pkt->arp && |
| 4494 | memcmp(&pkt->arp->spa, c->rem.ip, sizeof(pkt->arp->spa)) == 0) |
| 4495 | break; |
| 4496 | if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break; |
| 4497 | if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && |
| 4498 | lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) |
| 4499 | break; |
| 4500 | } |
| 4501 | return c; |
| 4502 | } |
| 4503 | |
| 4504 | static void mac_resolved(struct mg_connection *c); |
| 4505 | |
| 4506 | static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4507 | if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) { |
| 4508 | // ARP request. Make a response, then send |
| 4509 | // MG_DEBUG(("ARP op %d %M: %M", mg_ntohs(pkt->arp->op), mg_print_ip4, |
| 4510 | // &pkt->arp->spa, mg_print_ip4, &pkt->arp->tpa)); |
| 4511 | struct eth *eth = (struct eth *) ifp->tx.buf; |
| 4512 | struct arp *arp = (struct arp *) (eth + 1); |
| 4513 | memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst)); |
| 4514 | memcpy(eth->src, ifp->mac, sizeof(eth->src)); |
| 4515 | eth->type = mg_htons(0x806); |
| 4516 | *arp = *pkt->arp; |
| 4517 | arp->op = mg_htons(2); |
| 4518 | memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha)); |
| 4519 | memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha)); |
| 4520 | arp->tpa = pkt->arp->spa; |
| 4521 | arp->spa = ifp->ip; |
| 4522 | MG_DEBUG(("ARP: tell %M we're %M", mg_print_ip4, &arp->tpa, mg_print_mac, |
| 4523 | &ifp->mac)); |
| 4524 | ether_output(ifp, PDIFF(eth, arp + 1)); |
| 4525 | } else if (pkt->arp->op == mg_htons(2)) { |
| 4526 | if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return; |
| 4527 | if (pkt->arp->spa == ifp->gw) { |
| 4528 | // Got response for the GW ARP request. Set ifp->gwmac and IP -> READY |
| 4529 | memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac)); |
| 4530 | if (ifp->state == MG_TCPIP_STATE_IP) { |
| 4531 | ifp->state = MG_TCPIP_STATE_READY; |
| 4532 | onstatechange(ifp); |
| 4533 | } |
| 4534 | } else { |
| 4535 | struct mg_connection *c = getpeer(ifp->mgr, pkt, false); |
| 4536 | if (c != NULL && c->is_arplooking) { |
| 4537 | struct connstate *s = (struct connstate *) (c + 1); |
| 4538 | memcpy(s->mac, pkt->arp->sha, sizeof(s->mac)); |
| 4539 | MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip, |
| 4540 | mg_print_mac, s->mac)); |
| 4541 | c->is_arplooking = 0; |
| 4542 | mac_resolved(c); |
| 4543 | } |
| 4544 | } |
| 4545 | } |
| 4546 | } |
| 4547 | |
| 4548 | static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4549 | // MG_DEBUG(("ICMP %d", (int) len)); |
| 4550 | if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { |
| 4551 | size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp); |
| 4552 | size_t space = ifp->tx.len - hlen, plen = pkt->pay.len; |
| 4553 | if (plen > space) plen = space; |
| 4554 | struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src, |
| 4555 | sizeof(struct icmp) + plen); |
| 4556 | struct icmp *icmp = (struct icmp *) (ip + 1); |
| 4557 | memset(icmp, 0, sizeof(*icmp)); // Set csum to 0 |
| 4558 | memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX |
| 4559 | icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen); |
| 4560 | ether_output(ifp, hlen + plen); |
| 4561 | } |
| 4562 | } |
| 4563 | |
| 4564 | static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4565 | uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0; |
| 4566 | uint8_t msgtype = 0, state = ifp->state; |
| 4567 | // perform size check first, then access fields |
| 4568 | uint8_t *p = pkt->dhcp->options, |
| 4569 | *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; |
| 4570 | if (end < (uint8_t *) (pkt->dhcp + 1)) return; |
| 4571 | if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; |
| 4572 | while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9 |
| 4573 | if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask |
| 4574 | memcpy(&mask, p + 2, sizeof(mask)); |
| 4575 | } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW |
| 4576 | memcpy(&gw, p + 2, sizeof(gw)); |
| 4577 | ip = pkt->dhcp->yiaddr; |
| 4578 | } else if (ifp->enable_req_dns && p[0] == 6 && p[1] == sizeof(dns) && |
| 4579 | p + 6 < end) { // DNS |
| 4580 | memcpy(&dns, p + 2, sizeof(dns)); |
| 4581 | } else if (ifp->enable_req_sntp && p[0] == 42 && p[1] == sizeof(sntp) && |
| 4582 | p + 6 < end) { // SNTP |
| 4583 | memcpy(&sntp, p + 2, sizeof(sntp)); |
| 4584 | } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease |
| 4585 | memcpy(&lease, p + 2, sizeof(lease)); |
| 4586 | lease = mg_ntohl(lease); |
| 4587 | } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type |
| 4588 | msgtype = p[2]; |
| 4589 | } |
| 4590 | p += p[1] + 2; |
| 4591 | } |
| 4592 | // Process message type, RFC-1533 (9.4); RFC-2131 (3.1, 4) |
| 4593 | if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP |
| 4594 | ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; |
| 4595 | } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw && |
| 4596 | lease) { // DHCPOFFER |
| 4597 | // select IP, (4.4.1) (fallback to IP source addr on foul play) |
| 4598 | tx_dhcp_request_sel(ifp, ip, |
| 4599 | pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); |
| 4600 | ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state |
| 4601 | } else if (msgtype == 5) { // DHCPACK |
| 4602 | if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP |
| 4603 | ifp->lease_expire = ifp->now + lease * 1000; |
| 4604 | MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); |
| 4605 | // assume DHCP server = router until ARP resolves |
| 4606 | memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); |
| 4607 | ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; |
| 4608 | ifp->state = MG_TCPIP_STATE_IP; // BOUND state |
| 4609 | uint64_t rand; |
| 4610 | mg_random(&rand, sizeof(rand)); |
| 4611 | srand((unsigned int) (rand + mg_millis())); |
| 4612 | if (ifp->enable_req_dns && dns != 0) |
| 4613 | mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_DNS, &dns); |
| 4614 | if (ifp->enable_req_sntp && sntp != 0) |
| 4615 | mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); |
| 4616 | } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew |
| 4617 | ifp->lease_expire = ifp->now + lease * 1000; |
| 4618 | MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); |
| 4619 | } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4) |
| 4620 | } |
| 4621 | if (ifp->state != state) onstatechange(ifp); |
| 4622 | } |
| 4623 | |
| 4624 | // Simple DHCP server that assigns a next IP address: ifp->ip + 1 |
| 4625 | static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4626 | uint8_t op = 0, *p = pkt->dhcp->options, |
| 4627 | *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; |
| 4628 | if (end < (uint8_t *) (pkt->dhcp + 1)) return; |
| 4629 | // struct dhcp *req = pkt->dhcp; |
| 4630 | struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; |
| 4631 | res.yiaddr = ifp->ip; |
| 4632 | ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 |
| 4633 | while (p + 1 < end && p[0] != 255) { // Parse options |
| 4634 | if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type |
| 4635 | op = p[2]; |
| 4636 | } |
| 4637 | p += p[1] + 2; |
| 4638 | } |
| 4639 | if (op == 1 || op == 3) { // DHCP Discover or DHCP Request |
| 4640 | uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK |
| 4641 | uint8_t opts[] = { |
| 4642 | 53, 1, msg, // Message type |
| 4643 | 1, 4, 0, 0, 0, 0, // Subnet mask |
| 4644 | 54, 4, 0, 0, 0, 0, // Server ID |
| 4645 | 12, 3, 'm', 'i', 'p', // Host name: "mip" |
| 4646 | 51, 4, 255, 255, 255, 255, // Lease time |
| 4647 | 255 // End of options |
| 4648 | }; |
| 4649 | memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6); |
| 4650 | memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask)); |
| 4651 | memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip)); |
| 4652 | memcpy(&res.options, opts, sizeof(opts)); |
| 4653 | res.magic = pkt->dhcp->magic; |
| 4654 | res.xid = pkt->dhcp->xid; |
| 4655 | if (ifp->enable_get_gateway) { |
| 4656 | ifp->gw = res.yiaddr; // set gw IP, best-effort gwmac as DHCP server's |
| 4657 | memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); |
| 4658 | } |
| 4659 | tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67), |
| 4660 | op == 1 ? ~0U : res.yiaddr, mg_htons(68), &res, sizeof(res)); |
| 4661 | } |
| 4662 | } |
| 4663 | |
| 4664 | static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4665 | struct mg_connection *c = getpeer(ifp->mgr, pkt, true); |
| 4666 | if (c == NULL) { |
| 4667 | // No UDP listener on this port. Should send ICMP, but keep silent. |
| 4668 | } else { |
| 4669 | c->rem.port = pkt->udp->sport; |
| 4670 | memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); |
| 4671 | struct connstate *s = (struct connstate *) (c + 1); |
| 4672 | memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); |
| 4673 | if (c->recv.len >= MG_MAX_RECV_SIZE) { |
| 4674 | mg_error(c, "max_recv_buf_size reached"); |
| 4675 | } else if (c->recv.size - c->recv.len < pkt->pay.len && |
| 4676 | !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) { |
| 4677 | mg_error(c, "oom"); |
| 4678 | } else { |
| 4679 | memcpy(&c->recv.buf[c->recv.len], pkt->pay.buf, pkt->pay.len); |
| 4680 | c->recv.len += pkt->pay.len; |
| 4681 | mg_call(c, MG_EV_READ, &pkt->pay.len); |
| 4682 | } |
| 4683 | } |
| 4684 | } |
| 4685 | |
| 4686 | static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip, |
| 4687 | uint8_t flags, uint16_t sport, uint16_t dport, |
| 4688 | uint32_t seq, uint32_t ack, const void *buf, size_t len) { |
| 4689 | #if 0 |
| 4690 | uint8_t opts[] = {2, 4, 5, 0xb4, 4, 2, 0, 0}; // MSS = 1460, SACK permitted |
| 4691 | if (flags & TH_SYN) { |
| 4692 | // Handshake? Set MSS |
| 4693 | buf = opts; |
| 4694 | len = sizeof(opts); |
| 4695 | } |
| 4696 | #endif |
| 4697 | struct ip *ip = |
| 4698 | tx_ip(ifp, dst_mac, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len); |
| 4699 | struct tcp *tcp = (struct tcp *) (ip + 1); |
| 4700 | memset(tcp, 0, sizeof(*tcp)); |
| 4701 | if (buf != NULL && len) memmove(tcp + 1, buf, len); |
| 4702 | tcp->sport = sport; |
| 4703 | tcp->dport = dport; |
| 4704 | tcp->seq = seq; |
| 4705 | tcp->ack = ack; |
| 4706 | tcp->flags = flags; |
| 4707 | tcp->win = mg_htons(MIP_TCP_WIN); |
| 4708 | tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); |
| 4709 | // if (flags & TH_SYN) tcp->off = 0x70; // Handshake? header size 28 bytes |
| 4710 | |
| 4711 | uint32_t cs = 0; |
| 4712 | uint16_t n = (uint16_t) (sizeof(*tcp) + len); |
| 4713 | uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)}; |
| 4714 | cs = csumup(cs, tcp, n); |
| 4715 | cs = csumup(cs, &ip->src, sizeof(ip->src)); |
| 4716 | cs = csumup(cs, &ip->dst, sizeof(ip->dst)); |
| 4717 | cs = csumup(cs, pseudo, sizeof(pseudo)); |
| 4718 | tcp->csum = csumfin(cs); |
| 4719 | MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src, |
| 4720 | mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst, |
| 4721 | mg_ntohs(tcp->dport), tcp->flags, len)); |
| 4722 | // mg_hexdump(ifp->tx.buf, PDIFF(ifp->tx.buf, tcp + 1) + len); |
| 4723 | return ether_output(ifp, PDIFF(ifp->tx.buf, tcp + 1) + len); |
| 4724 | } |
| 4725 | |
| 4726 | static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt, |
| 4727 | uint8_t flags, uint32_t seq, const void *buf, |
| 4728 | size_t len) { |
| 4729 | uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0; |
| 4730 | return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport, |
| 4731 | pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta), |
| 4732 | buf, len); |
| 4733 | } |
| 4734 | |
| 4735 | static struct mg_connection *accept_conn(struct mg_connection *lsn, |
| 4736 | struct pkt *pkt) { |
| 4737 | struct mg_connection *c = mg_alloc_conn(lsn->mgr); |
| 4738 | if (c == NULL) { |
| 4739 | MG_ERROR(("OOM")); |
| 4740 | return NULL; |
| 4741 | } |
| 4742 | struct connstate *s = (struct connstate *) (c + 1); |
| 4743 | s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); |
| 4744 | memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); |
| 4745 | settmout(c, MIP_TTYPE_KEEPALIVE); |
| 4746 | memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); |
| 4747 | c->rem.port = pkt->tcp->sport; |
| 4748 | MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem)); |
| 4749 | LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c); |
| 4750 | c->is_accepted = 1; |
| 4751 | c->is_hexdumping = lsn->is_hexdumping; |
| 4752 | c->pfn = lsn->pfn; |
| 4753 | c->loc = lsn->loc; |
| 4754 | c->pfn_data = lsn->pfn_data; |
| 4755 | c->fn = lsn->fn; |
| 4756 | c->fn_data = lsn->fn_data; |
| 4757 | mg_call(c, MG_EV_OPEN, NULL); |
| 4758 | mg_call(c, MG_EV_ACCEPT, NULL); |
| 4759 | return c; |
| 4760 | } |
| 4761 | |
| 4762 | static size_t trim_len(struct mg_connection *c, size_t len) { |
| 4763 | struct mg_tcpip_if *ifp = c->mgr->ifp; |
| 4764 | size_t eth_h_len = 14, ip_max_h_len = 24, tcp_max_h_len = 60, udp_h_len = 8; |
| 4765 | size_t max_headers_len = |
| 4766 | eth_h_len + ip_max_h_len + (c->is_udp ? udp_h_len : tcp_max_h_len); |
| 4767 | size_t min_mtu = c->is_udp ? 68 /* RFC-791 */ : max_headers_len - eth_h_len; |
| 4768 | |
| 4769 | // If the frame exceeds the available buffer, trim the length |
| 4770 | if (len + max_headers_len > ifp->tx.len) { |
| 4771 | len = ifp->tx.len - max_headers_len; |
| 4772 | } |
| 4773 | // Ensure the MTU isn't lower than the minimum allowed value |
| 4774 | if (ifp->mtu < min_mtu) { |
| 4775 | MG_ERROR(("MTU is lower than minimum, capping to %lu", min_mtu)); |
| 4776 | ifp->mtu = (uint16_t) min_mtu; |
| 4777 | } |
| 4778 | // If the total packet size exceeds the MTU, trim the length |
| 4779 | if (len + max_headers_len - eth_h_len > ifp->mtu) { |
| 4780 | len = ifp->mtu - max_headers_len + eth_h_len; |
| 4781 | if (c->is_udp) { |
| 4782 | MG_ERROR(("UDP datagram exceeds MTU. Truncating it.")); |
| 4783 | } |
| 4784 | } |
| 4785 | |
| 4786 | return len; |
| 4787 | } |
| 4788 | |
| 4789 | long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { |
| 4790 | struct mg_tcpip_if *ifp = c->mgr->ifp; |
| 4791 | struct connstate *s = (struct connstate *) (c + 1); |
| 4792 | uint32_t dst_ip = *(uint32_t *) c->rem.ip; |
| 4793 | len = trim_len(c, len); |
| 4794 | if (c->is_udp) { |
| 4795 | tx_udp(ifp, s->mac, ifp->ip, c->loc.port, dst_ip, c->rem.port, buf, len); |
| 4796 | } else { |
| 4797 | size_t sent = |
| 4798 | tx_tcp(ifp, s->mac, dst_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port, |
| 4799 | mg_htonl(s->seq), mg_htonl(s->ack), buf, len); |
| 4800 | if (sent == 0) { |
| 4801 | return MG_IO_WAIT; |
| 4802 | } else if (sent == (size_t) -1) { |
| 4803 | return MG_IO_ERR; |
| 4804 | } else { |
| 4805 | s->seq += (uint32_t) len; |
| 4806 | if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE); |
| 4807 | } |
| 4808 | } |
| 4809 | return (long) len; |
| 4810 | } |
| 4811 | |
| 4812 | static void handle_tls_recv(struct mg_connection *c) { |
| 4813 | size_t avail = mg_tls_pending(c); |
| 4814 | size_t min = avail > MG_MAX_RECV_SIZE ? MG_MAX_RECV_SIZE : avail; |
| 4815 | struct mg_iobuf *io = &c->recv; |
| 4816 | if (io->size - io->len < min && !mg_iobuf_resize(io, io->len + min)) { |
| 4817 | mg_error(c, "oom"); |
| 4818 | } else { |
| 4819 | // Decrypt data directly into c->recv |
| 4820 | long n = mg_tls_recv(c, io->buf != NULL ? &io->buf[io->len] : io->buf, |
| 4821 | io->size - io->len); |
| 4822 | if (n == MG_IO_ERR) { |
| 4823 | mg_error(c, "TLS recv error"); |
| 4824 | } else if (n > 0) { |
| 4825 | // Decrypted successfully - trigger MG_EV_READ |
| 4826 | io->len += (size_t) n; |
| 4827 | mg_call(c, MG_EV_READ, &n); |
| 4828 | } // else n < 0: outstanding data to be moved to c->recv |
| 4829 | } |
| 4830 | } |
| 4831 | |
| 4832 | static void read_conn(struct mg_connection *c, struct pkt *pkt) { |
| 4833 | struct connstate *s = (struct connstate *) (c + 1); |
| 4834 | struct mg_iobuf *io = c->is_tls ? &c->rtls : &c->recv; |
| 4835 | uint32_t seq = mg_ntohl(pkt->tcp->seq); |
| 4836 | uint32_t rem_ip; |
| 4837 | memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); |
| 4838 | if (pkt->tcp->flags & TH_FIN) { |
| 4839 | // If we initiated the closure, we reply with ACK upon receiving FIN |
| 4840 | // If we didn't initiate it, we reply with FIN as part of the normal TCP |
| 4841 | // closure process |
| 4842 | uint8_t flags = TH_ACK; |
| 4843 | s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1); |
| 4844 | s->fin_rcvd = true; |
| 4845 | if (c->is_draining && s->ttype == MIP_TTYPE_FIN) { |
| 4846 | if (s->seq == mg_htonl(pkt->tcp->ack)) { // Simultaneous closure ? |
| 4847 | s->seq++; // Yes. Increment our SEQ |
| 4848 | } else { // Otherwise, |
| 4849 | s->seq = mg_htonl(pkt->tcp->ack); // Set to peer's ACK |
| 4850 | } |
| 4851 | s->twclosure = true; |
| 4852 | } else { |
| 4853 | flags |= TH_FIN; |
| 4854 | c->is_draining = 1; |
| 4855 | settmout(c, MIP_TTYPE_FIN); |
| 4856 | } |
| 4857 | tx_tcp(c->mgr->ifp, s->mac, rem_ip, flags, c->loc.port, c->rem.port, |
| 4858 | mg_htonl(s->seq), mg_htonl(s->ack), "", 0); |
| 4859 | if (pkt->pay.len == 0) return; // if no data, we're done |
| 4860 | } else if (pkt->pay.len == 0) { // this is an ACK |
| 4861 | if (s->fin_rcvd && s->ttype == MIP_TTYPE_FIN) s->twclosure = true; |
| 4862 | return; // no data to process |
| 4863 | } else if (seq != s->ack) { |
| 4864 | uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); |
| 4865 | if (s->ack == ack) { |
| 4866 | MG_VERBOSE(("ignoring duplicate pkt")); |
| 4867 | } else { |
| 4868 | MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, ack)); |
| 4869 | tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, |
| 4870 | mg_htonl(s->seq), mg_htonl(s->ack), "", 0); |
| 4871 | } |
| 4872 | return; // drop it |
| 4873 | } else if (io->size - io->len < pkt->pay.len && |
| 4874 | !mg_iobuf_resize(io, io->len + pkt->pay.len)) { |
| 4875 | mg_error(c, "oom"); |
| 4876 | return; // drop it |
| 4877 | } |
| 4878 | // Copy TCP payload into the IO buffer. If the connection is plain text, |
| 4879 | // we copy to c->recv. If the connection is TLS, this data is encrypted, |
| 4880 | // therefore we copy that encrypted data to the c->rtls iobuffer instead, |
| 4881 | // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will |
| 4882 | // call back mg_io_recv() which grabs raw data from c->rtls |
| 4883 | memcpy(&io->buf[io->len], pkt->pay.buf, pkt->pay.len); |
| 4884 | io->len += pkt->pay.len; |
| 4885 | MG_VERBOSE(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack)); |
| 4886 | // Advance ACK counter |
| 4887 | s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); |
| 4888 | s->unacked += pkt->pay.len; |
| 4889 | // size_t diff = s->acked <= s->ack ? s->ack - s->acked : s->ack; |
| 4890 | if (s->unacked > MIP_TCP_WIN / 2 && s->acked != s->ack) { |
| 4891 | // Send ACK immediately |
| 4892 | MG_VERBOSE(("%lu imm ACK %lu", c->id, s->acked)); |
| 4893 | tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, |
| 4894 | mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); |
| 4895 | s->unacked = 0; |
| 4896 | s->acked = s->ack; |
| 4897 | if (s->ttype != MIP_TTYPE_KEEPALIVE) settmout(c, MIP_TTYPE_KEEPALIVE); |
| 4898 | } else { |
| 4899 | // if not already running, setup a timer to send an ACK later |
| 4900 | if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); |
| 4901 | } |
| 4902 | if (c->is_tls && c->is_tls_hs) { |
| 4903 | mg_tls_handshake(c); |
| 4904 | } else if (c->is_tls) { |
| 4905 | handle_tls_recv(c); |
| 4906 | } else { |
| 4907 | // Plain text connection, data is already in c->recv, trigger MG_EV_READ |
| 4908 | mg_call(c, MG_EV_READ, &pkt->pay.len); |
| 4909 | } |
| 4910 | } |
| 4911 | |
| 4912 | static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4913 | struct mg_connection *c = getpeer(ifp->mgr, pkt, false); |
| 4914 | struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1); |
| 4915 | #if 0 |
| 4916 | MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len)); |
| 4917 | #endif |
| 4918 | if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) { |
| 4919 | s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1; |
| 4920 | tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0); |
| 4921 | c->is_connecting = 0; // Client connected |
| 4922 | settmout(c, MIP_TTYPE_KEEPALIVE); |
| 4923 | mg_call(c, MG_EV_CONNECT, NULL); // Let user know |
| 4924 | if (c->is_tls_hs) mg_tls_handshake(c); |
| 4925 | } else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) { |
| 4926 | // mg_hexdump(pkt->raw.buf, pkt->raw.len); |
| 4927 | tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); |
| 4928 | } else if (c != NULL && pkt->tcp->flags & TH_RST) { |
| 4929 | mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 |
| 4930 | } else if (c != NULL) { |
| 4931 | #if 0 |
| 4932 | MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len, |
| 4933 | mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport), |
| 4934 | mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport))); |
| 4935 | mg_hexdump(pkt->pay.buf, pkt->pay.len); |
| 4936 | #endif |
| 4937 | s->tmiss = 0; // Reset missed keep-alive counter |
| 4938 | if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer |
| 4939 | settmout(c, |
| 4940 | MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending |
| 4941 | read_conn(c, pkt); // Override timer with ACK timeout if needed |
| 4942 | } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { |
| 4943 | tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); |
| 4944 | } else if (pkt->tcp->flags & TH_RST) { |
| 4945 | if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 |
| 4946 | // ignore RST if not connected |
| 4947 | } else if (pkt->tcp->flags & TH_SYN) { |
| 4948 | // Use peer's source port as ISN, in order to recognise the handshake |
| 4949 | uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport)); |
| 4950 | tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0); |
| 4951 | } else if (pkt->tcp->flags & TH_FIN) { |
| 4952 | tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0); |
| 4953 | } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) { |
| 4954 | accept_conn(c, pkt); |
| 4955 | } else if (!c->is_accepted) { // no peer |
| 4956 | tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); |
| 4957 | } else { |
| 4958 | // MG_VERBOSE(("dropped silently..")); |
| 4959 | } |
| 4960 | } |
| 4961 | |
| 4962 | static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 4963 | uint16_t frag = mg_ntohs(pkt->ip->frag); |
| 4964 | if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) { |
| 4965 | if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1); |
| 4966 | if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1); |
| 4967 | struct mg_connection *c = getpeer(ifp->mgr, pkt, false); |
| 4968 | if (c) mg_error(c, "Received fragmented packet"); |
| 4969 | } else if (pkt->ip->proto == 1) { |
| 4970 | pkt->icmp = (struct icmp *) (pkt->ip + 1); |
| 4971 | if (pkt->pay.len < sizeof(*pkt->icmp)) return; |
| 4972 | mkpay(pkt, pkt->icmp + 1); |
| 4973 | rx_icmp(ifp, pkt); |
| 4974 | } else if (pkt->ip->proto == 17) { |
| 4975 | pkt->udp = (struct udp *) (pkt->ip + 1); |
| 4976 | if (pkt->pay.len < sizeof(*pkt->udp)) return; |
| 4977 | mkpay(pkt, pkt->udp + 1); |
| 4978 | MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, |
| 4979 | mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst, |
| 4980 | mg_ntohs(pkt->udp->dport), (int) pkt->pay.len)); |
| 4981 | if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68)) { |
| 4982 | pkt->dhcp = (struct dhcp *) (pkt->udp + 1); |
| 4983 | mkpay(pkt, pkt->dhcp + 1); |
| 4984 | rx_dhcp_client(ifp, pkt); |
| 4985 | } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) { |
| 4986 | pkt->dhcp = (struct dhcp *) (pkt->udp + 1); |
| 4987 | mkpay(pkt, pkt->dhcp + 1); |
| 4988 | rx_dhcp_server(ifp, pkt); |
| 4989 | } else { |
| 4990 | rx_udp(ifp, pkt); |
| 4991 | } |
| 4992 | } else if (pkt->ip->proto == 6) { |
| 4993 | pkt->tcp = (struct tcp *) (pkt->ip + 1); |
| 4994 | if (pkt->pay.len < sizeof(*pkt->tcp)) return; |
| 4995 | mkpay(pkt, pkt->tcp + 1); |
| 4996 | uint16_t iplen = mg_ntohs(pkt->ip->len); |
| 4997 | uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U)); |
| 4998 | if (iplen >= off) pkt->pay.len = (size_t) (iplen - off); |
| 4999 | MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, |
| 5000 | mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst, |
| 5001 | mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len)); |
| 5002 | rx_tcp(ifp, pkt); |
| 5003 | } |
| 5004 | } |
| 5005 | |
| 5006 | static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { |
| 5007 | // MG_DEBUG(("IP %d", (int) len)); |
| 5008 | if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) { |
| 5009 | pkt->icmp = (struct icmp *) (pkt->ip6 + 1); |
| 5010 | if (pkt->pay.len < sizeof(*pkt->icmp)) return; |
| 5011 | mkpay(pkt, pkt->icmp + 1); |
| 5012 | rx_icmp(ifp, pkt); |
| 5013 | } else if (pkt->ip6->proto == 17) { |
| 5014 | pkt->udp = (struct udp *) (pkt->ip6 + 1); |
| 5015 | if (pkt->pay.len < sizeof(*pkt->udp)) return; |
| 5016 | // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport), |
| 5017 | // mg_htons(udp->dport))); |
| 5018 | mkpay(pkt, pkt->udp + 1); |
| 5019 | } |
| 5020 | } |
| 5021 | |
| 5022 | static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) { |
| 5023 | struct pkt pkt; |
| 5024 | memset(&pkt, 0, sizeof(pkt)); |
| 5025 | pkt.raw.buf = (char *) buf; |
| 5026 | pkt.raw.len = len; |
| 5027 | pkt.eth = (struct eth *) buf; |
| 5028 | // mg_hexdump(buf, len > 16 ? 16: len); |
| 5029 | if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt? |
| 5030 | if (ifp->enable_mac_check && |
| 5031 | memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 && |
| 5032 | memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0) |
| 5033 | return; |
| 5034 | if (ifp->enable_crc32_check && len > 4) { |
| 5035 | len -= 4; // TODO(scaprile): check on bigendian |
| 5036 | uint32_t crc = mg_crc32(0, (const char *) buf, len); |
| 5037 | if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return; |
| 5038 | } |
| 5039 | if (pkt.eth->type == mg_htons(0x806)) { |
| 5040 | pkt.arp = (struct arp *) (pkt.eth + 1); |
| 5041 | if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated |
| 5042 | mg_tcpip_call(ifp, MG_TCPIP_EV_ARP, &pkt.raw); |
| 5043 | rx_arp(ifp, &pkt); |
| 5044 | } else if (pkt.eth->type == mg_htons(0x86dd)) { |
| 5045 | pkt.ip6 = (struct ip6 *) (pkt.eth + 1); |
| 5046 | if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated |
| 5047 | if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP |
| 5048 | mkpay(&pkt, pkt.ip6 + 1); |
| 5049 | rx_ip6(ifp, &pkt); |
| 5050 | } else if (pkt.eth->type == mg_htons(0x800)) { |
| 5051 | pkt.ip = (struct ip *) (pkt.eth + 1); |
| 5052 | if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated |
| 5053 | // Truncate frame to what IP header tells us |
| 5054 | if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) { |
| 5055 | pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth); |
| 5056 | } |
| 5057 | if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated |
| 5058 | if ((pkt.ip->ver >> 4) != 4) return; // Not IP |
| 5059 | mkpay(&pkt, pkt.ip + 1); |
| 5060 | rx_ip(ifp, &pkt); |
| 5061 | } else { |
| 5062 | MG_DEBUG(("Unknown eth type %x", mg_htons(pkt.eth->type))); |
| 5063 | if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(buf, len >= 32 ? 32 : len); |
| 5064 | } |
| 5065 | } |
| 5066 | |
| 5067 | static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { |
| 5068 | struct mg_connection *c; |
| 5069 | bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, now); |
| 5070 | ifp->now = now; |
| 5071 | |
| 5072 | if (expired_1000ms) { |
| 5073 | #if MG_ENABLE_TCPIP_PRINT_DEBUG_STATS |
| 5074 | const char *names[] = {"down", "up", "req", "ip", "ready"}; |
| 5075 | MG_INFO(("Status: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", |
| 5076 | names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, |
| 5077 | ifp->ndrop, ifp->nerr)); |
| 5078 | #endif |
| 5079 | } |
| 5080 | // Handle gw ARP request timeout, order is important |
| 5081 | if (expired_1000ms && ifp->state == MG_TCPIP_STATE_IP) { |
| 5082 | ifp->state = MG_TCPIP_STATE_READY; // keep best-effort MAC |
| 5083 | onstatechange(ifp); |
| 5084 | } |
| 5085 | // poll driver |
| 5086 | if (ifp->driver->poll) { |
| 5087 | bool up = ifp->driver->poll(ifp, expired_1000ms); |
| 5088 | // Handle physical interface up/down status |
| 5089 | if (expired_1000ms) { |
| 5090 | bool current = ifp->state != MG_TCPIP_STATE_DOWN; |
| 5091 | if (!up && ifp->enable_dhcp_client) ifp->ip = 0; |
| 5092 | if (up != current) { // link state has changed |
| 5093 | ifp->state = up == false ? MG_TCPIP_STATE_DOWN |
| 5094 | : ifp->enable_dhcp_client || ifp->ip == 0 |
| 5095 | ? MG_TCPIP_STATE_UP |
| 5096 | : MG_TCPIP_STATE_IP; |
| 5097 | onstatechange(ifp); |
| 5098 | } else if (!ifp->enable_dhcp_client && ifp->state == MG_TCPIP_STATE_UP && |
| 5099 | ifp->ip) { |
| 5100 | ifp->state = MG_TCPIP_STATE_IP; // ifp->fn has set an IP |
| 5101 | onstatechange(ifp); |
| 5102 | } |
| 5103 | if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); |
| 5104 | mg_tcpip_call(ifp, MG_TCPIP_EV_TIMER_1S, NULL); |
| 5105 | } |
| 5106 | } |
| 5107 | if (ifp->state == MG_TCPIP_STATE_DOWN) return; |
| 5108 | |
| 5109 | // DHCP RFC-2131 (4.4) |
| 5110 | if (ifp->enable_dhcp_client && expired_1000ms) { |
| 5111 | if (ifp->state == MG_TCPIP_STATE_UP) { |
| 5112 | tx_dhcp_discover(ifp); // INIT (4.4.1) |
| 5113 | } else if (ifp->state == MG_TCPIP_STATE_READY && |
| 5114 | ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING |
| 5115 | if (ifp->now >= ifp->lease_expire) { |
| 5116 | ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP |
| 5117 | onstatechange(ifp); |
| 5118 | } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && |
| 5119 | ((ifp->now / 1000) % 60) == 0) { |
| 5120 | // hack: 30 min before deadline, try to rebind (4.3.6) every min |
| 5121 | tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); |
| 5122 | } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) |
| 5123 | } |
| 5124 | } |
| 5125 | |
| 5126 | // Read data from the network |
| 5127 | if (ifp->driver->rx != NULL) { // Simple polling driver, returns one frame |
| 5128 | size_t len = |
| 5129 | ifp->driver->rx(ifp->recv_queue.buf, ifp->recv_queue.size, ifp); |
| 5130 | if (len > 0) { |
| 5131 | ifp->nrecv++; |
| 5132 | mg_tcpip_rx(ifp, ifp->recv_queue.buf, len); |
| 5133 | } |
| 5134 | } else { // Complex poll / Interrupt-based driver. Queues recvd frames |
| 5135 | char *buf; |
| 5136 | size_t len = mg_queue_next(&ifp->recv_queue, &buf); |
| 5137 | if (len > 0) { |
| 5138 | mg_tcpip_rx(ifp, buf, len); |
| 5139 | mg_queue_del(&ifp->recv_queue, len); |
| 5140 | } |
| 5141 | } |
| 5142 | |
| 5143 | // Process timeouts |
| 5144 | for (c = ifp->mgr->conns; c != NULL; c = c->next) { |
| 5145 | if ((c->is_udp && !c->is_arplooking) || c->is_listening || c->is_resolving) |
| 5146 | continue; |
| 5147 | struct connstate *s = (struct connstate *) (c + 1); |
| 5148 | uint32_t rem_ip; |
| 5149 | memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); |
| 5150 | if (ifp->now > s->timer) { |
| 5151 | if (s->ttype == MIP_TTYPE_ARP) { |
| 5152 | mg_error(c, "ARP timeout"); |
| 5153 | } else if (c->is_udp) { |
| 5154 | continue; |
| 5155 | } else if (s->ttype == MIP_TTYPE_ACK && s->acked != s->ack) { |
| 5156 | MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack)); |
| 5157 | tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, |
| 5158 | mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); |
| 5159 | s->acked = s->ack; |
| 5160 | } else if (s->ttype == MIP_TTYPE_SYN) { |
| 5161 | mg_error(c, "Connection timeout"); |
| 5162 | } else if (s->ttype == MIP_TTYPE_FIN) { |
| 5163 | c->is_closing = 1; |
| 5164 | continue; |
| 5165 | } else { |
| 5166 | if (s->tmiss++ > 2) { |
| 5167 | mg_error(c, "keepalive"); |
| 5168 | } else { |
| 5169 | MG_VERBOSE(("%lu keepalive", c->id)); |
| 5170 | tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, |
| 5171 | mg_htonl(s->seq - 1), mg_htonl(s->ack), NULL, 0); |
| 5172 | } |
| 5173 | } |
| 5174 | |
| 5175 | settmout(c, MIP_TTYPE_KEEPALIVE); |
| 5176 | } |
| 5177 | } |
| 5178 | } |
| 5179 | |
| 5180 | // This function executes in interrupt context, thus it should copy data |
| 5181 | // somewhere fast. Note that newlib's malloc is not thread safe, thus use |
| 5182 | // our lock-free queue with preallocated buffer to copy data and return asap |
| 5183 | void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) { |
| 5184 | char *p; |
| 5185 | if (mg_queue_book(&ifp->recv_queue, &p, len) >= len) { |
| 5186 | memcpy(p, buf, len); |
| 5187 | mg_queue_add(&ifp->recv_queue, len); |
| 5188 | ifp->nrecv++; |
| 5189 | } else { |
| 5190 | ifp->ndrop++; |
| 5191 | } |
| 5192 | } |
| 5193 | |
| 5194 | void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { |
| 5195 | // If MAC address is not set, make a random one |
| 5196 | if (ifp->mac[0] == 0 && ifp->mac[1] == 0 && ifp->mac[2] == 0 && |
| 5197 | ifp->mac[3] == 0 && ifp->mac[4] == 0 && ifp->mac[5] == 0) { |
| 5198 | ifp->mac[0] = 0x02; // Locally administered, unicast |
| 5199 | mg_random(&ifp->mac[1], sizeof(ifp->mac) - 1); |
| 5200 | MG_INFO(("MAC not set. Generated random: %M", mg_print_mac, ifp->mac)); |
| 5201 | } |
| 5202 | |
| 5203 | // Uf DHCP name is not set, use "mip" |
| 5204 | if (ifp->dhcp_name[0] == '\0') { |
| 5205 | memcpy(ifp->dhcp_name, "mip", 4); |
| 5206 | } |
| 5207 | ifp->dhcp_name[sizeof(ifp->dhcp_name) - 1] = '\0'; // Just in case |
| 5208 | |
| 5209 | if (ifp->driver->init && !ifp->driver->init(ifp)) { |
| 5210 | MG_ERROR(("driver init failed")); |
| 5211 | } else { |
| 5212 | size_t framesize = 1540; |
| 5213 | ifp->tx.buf = (char *) calloc(1, framesize), ifp->tx.len = framesize; |
| 5214 | if (ifp->recv_queue.size == 0) |
| 5215 | ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192; |
| 5216 | ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size); |
| 5217 | ifp->timer_1000ms = mg_millis(); |
| 5218 | mgr->ifp = ifp; |
| 5219 | ifp->mgr = mgr; |
| 5220 | ifp->mtu = MG_TCPIP_MTU_DEFAULT; |
| 5221 | mgr->extraconnsize = sizeof(struct connstate); |
| 5222 | if (ifp->ip == 0) ifp->enable_dhcp_client = true; |
| 5223 | memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set best-effort to bcast |
| 5224 | mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535 |
| 5225 | ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from |
| 5226 | // MG_EPHEMERAL_PORT_BASE to 65535 |
| 5227 | if (ifp->tx.buf == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM")); |
| 5228 | } |
| 5229 | } |
| 5230 | |
| 5231 | void mg_tcpip_free(struct mg_tcpip_if *ifp) { |
| 5232 | free(ifp->recv_queue.buf); |
| 5233 | free(ifp->tx.buf); |
| 5234 | } |
| 5235 | |
| 5236 | static void send_syn(struct mg_connection *c) { |
| 5237 | struct connstate *s = (struct connstate *) (c + 1); |
| 5238 | uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); |
| 5239 | uint32_t rem_ip; |
| 5240 | memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); |
| 5241 | tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, |
| 5242 | NULL, 0); |
| 5243 | } |
| 5244 | |
| 5245 | static void mac_resolved(struct mg_connection *c) { |
| 5246 | if (c->is_udp) { |
| 5247 | c->is_connecting = 0; |
| 5248 | mg_call(c, MG_EV_CONNECT, NULL); |
| 5249 | } else { |
| 5250 | send_syn(c); |
| 5251 | settmout(c, MIP_TTYPE_SYN); |
| 5252 | } |
| 5253 | } |
| 5254 | |
| 5255 | static void ip4_mcastmac(uint8_t *mac, uint32_t *ip) { |
| 5256 | uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group MAC |
| 5257 | memcpy(mac, mcastp, 3); |
| 5258 | memcpy(mac + 3, ((uint8_t *) ip) + 1, 3); // 23 LSb |
| 5259 | mac[3] &= 0x7F; |
| 5260 | } |
| 5261 | |
| 5262 | void mg_connect_resolved(struct mg_connection *c) { |
| 5263 | struct mg_tcpip_if *ifp = c->mgr->ifp; |
| 5264 | uint32_t rem_ip; |
| 5265 | memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); |
| 5266 | c->is_resolving = 0; |
| 5267 | if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE; |
| 5268 | memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t)); |
| 5269 | c->loc.port = mg_htons(ifp->eport++); |
| 5270 | MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port, |
| 5271 | &c->rem)); |
| 5272 | mg_call(c, MG_EV_RESOLVE, NULL); |
| 5273 | c->is_connecting = 1; |
| 5274 | if (c->is_udp && (rem_ip == 0xffffffff || rem_ip == (ifp->ip | ~ifp->mask))) { |
| 5275 | struct connstate *s = (struct connstate *) (c + 1); |
| 5276 | memset(s->mac, 0xFF, sizeof(s->mac)); // global or local broadcast |
| 5277 | mac_resolved(c); |
| 5278 | } else if (ifp->ip && ((rem_ip & ifp->mask) == (ifp->ip & ifp->mask)) && |
| 5279 | rem_ip != ifp->gw) { // skip if gw (onstatechange -> READY -> ARP) |
| 5280 | // If we're in the same LAN, fire an ARP lookup. |
| 5281 | MG_DEBUG(("%lu ARP lookup...", c->id)); |
| 5282 | mg_tcpip_arp_request(ifp, rem_ip, NULL); |
| 5283 | settmout(c, MIP_TTYPE_ARP); |
| 5284 | c->is_arplooking = 1; |
| 5285 | } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) { |
| 5286 | struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF |
| 5287 | ip4_mcastmac(s->mac, &rem_ip); // multicast group |
| 5288 | mac_resolved(c); |
| 5289 | } else { |
| 5290 | struct connstate *s = (struct connstate *) (c + 1); |
| 5291 | memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac)); |
| 5292 | mac_resolved(c); |
| 5293 | } |
| 5294 | } |
| 5295 | |
| 5296 | bool mg_open_listener(struct mg_connection *c, const char *url) { |
| 5297 | c->loc.port = mg_htons(mg_url_port(url)); |
| 5298 | if (!mg_aton(mg_url_host(url), &c->loc)) { |
| 5299 | MG_ERROR(("invalid listening URL: %s", url)); |
| 5300 | return false; |
| 5301 | } |
| 5302 | return true; |
| 5303 | } |
| 5304 | |
| 5305 | static void write_conn(struct mg_connection *c) { |
| 5306 | long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len) |
| 5307 | : mg_io_send(c, c->send.buf, c->send.len); |
| 5308 | if (len == MG_IO_ERR) { |
| 5309 | mg_error(c, "tx err"); |
| 5310 | } else if (len > 0) { |
| 5311 | mg_iobuf_del(&c->send, 0, (size_t) len); |
| 5312 | mg_call(c, MG_EV_WRITE, &len); |
| 5313 | } |
| 5314 | } |
| 5315 | |
| 5316 | static void init_closure(struct mg_connection *c) { |
| 5317 | struct connstate *s = (struct connstate *) (c + 1); |
| 5318 | if (c->is_udp == false && c->is_listening == false && |
| 5319 | c->is_connecting == false) { // For TCP conns, |
| 5320 | uint32_t rem_ip; |
| 5321 | memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); |
| 5322 | tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, |
| 5323 | c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); |
| 5324 | settmout(c, MIP_TTYPE_FIN); |
| 5325 | } |
| 5326 | } |
| 5327 | |
| 5328 | static void close_conn(struct mg_connection *c) { |
| 5329 | struct connstate *s = (struct connstate *) (c + 1); |
| 5330 | mg_iobuf_free(&s->raw); // For TLS connections, release raw data |
| 5331 | mg_close_conn(c); |
| 5332 | } |
| 5333 | |
| 5334 | static bool can_write(struct mg_connection *c) { |
| 5335 | return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 && |
| 5336 | c->is_tls_hs == 0 && c->is_arplooking == 0; |
| 5337 | } |
| 5338 | |
| 5339 | void mg_mgr_poll(struct mg_mgr *mgr, int ms) { |
| 5340 | struct mg_connection *c, *tmp; |
| 5341 | uint64_t now = mg_millis(); |
| 5342 | mg_timer_poll(&mgr->timers, now); |
| 5343 | if (mgr->ifp == NULL || mgr->ifp->driver == NULL) return; |
| 5344 | mg_tcpip_poll(mgr->ifp, now); |
| 5345 | for (c = mgr->conns; c != NULL; c = tmp) { |
| 5346 | tmp = c->next; |
| 5347 | struct connstate *s = (struct connstate *) (c + 1); |
| 5348 | mg_call(c, MG_EV_POLL, &now); |
| 5349 | MG_VERBOSE(("%lu .. %c%c%c%c%c %lu %lu", c->id, c->is_tls ? 'T' : 't', |
| 5350 | c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h', |
| 5351 | c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c', |
| 5352 | mg_tls_pending(c), c->rtls.len)); |
| 5353 | // order is important, TLS conn close with > 1 record in buffer (below) |
| 5354 | if (c->is_tls && (c->rtls.len > 0 || mg_tls_pending(c) > 0)) |
| 5355 | handle_tls_recv(c); |
| 5356 | if (can_write(c)) write_conn(c); |
| 5357 | if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN) |
| 5358 | init_closure(c); |
| 5359 | // For non-TLS, close immediately upon completing the 3-way closure |
| 5360 | // For TLS, handle any pending data (above) until MIP_TTYPE_FIN expires |
| 5361 | if (s->twclosure && |
| 5362 | (!c->is_tls || (c->rtls.len == 0 && mg_tls_pending(c) == 0))) |
| 5363 | c->is_closing = 1; |
| 5364 | if (c->is_closing) close_conn(c); |
| 5365 | } |
| 5366 | (void) ms; |
| 5367 | } |
| 5368 | |
| 5369 | bool mg_send(struct mg_connection *c, const void *buf, size_t len) { |
| 5370 | struct mg_tcpip_if *ifp = c->mgr->ifp; |
| 5371 | bool res = false; |
| 5372 | uint32_t rem_ip; |
| 5373 | memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); |
| 5374 | if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) { |
| 5375 | mg_error(c, "net down"); |
| 5376 | } else if (c->is_udp && (c->is_arplooking || c->is_resolving)) { |
| 5377 | // Fail to send, no target MAC or IP |
| 5378 | MG_VERBOSE(("still resolving...")); |
| 5379 | } else if (c->is_udp) { |
| 5380 | struct connstate *s = (struct connstate *) (c + 1); |
| 5381 | len = trim_len(c, len); // Trimming length if necessary |
| 5382 | tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len); |
| 5383 | res = true; |
| 5384 | } else { |
| 5385 | res = mg_iobuf_add(&c->send, c->send.len, buf, len); |
| 5386 | } |
| 5387 | return res; |
| 5388 | } |
| 5389 | |
| 5390 | uint8_t mcast_addr[6] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb}; |
| 5391 | void mg_multicast_add(struct mg_connection *c, char *ip) { |
| 5392 | (void) ip; // ip4_mcastmac(mcast_mac, &ip); |
| 5393 | // TODO(): actual IP -> MAC; check database, update |
| 5394 | c->mgr->ifp->update_mac_hash_table = true; // mark dirty |
| 5395 | } |
| 5396 | |
| 5397 | #endif // MG_ENABLE_TCPIP |
| 5398 | |
| 5399 | #ifdef MG_ENABLE_LINES |
| 5400 | #line 1 "src/ota_ch32v307.c" |
| 5401 | #endif |
| 5402 | |
| 5403 | |
| 5404 | |
| 5405 | |
| 5406 | #if MG_OTA == MG_OTA_CH32V307 |
| 5407 | // RM: https://www.wch-ic.com/downloads/CH32FV2x_V3xRM_PDF.html |
| 5408 | |
| 5409 | static bool mg_ch32v307_write(void *, const void *, size_t); |
| 5410 | static bool mg_ch32v307_swap(void); |
| 5411 | |
| 5412 | static struct mg_flash s_mg_flash_ch32v307 = { |
| 5413 | (void *) 0x08000000, // Start |
| 5414 | 480 * 1024, // Size, first 320k is 0-wait |
| 5415 | 4 * 1024, // Sector size, 4k |
| 5416 | 4, // Align, 32 bit |
| 5417 | mg_ch32v307_write, |
| 5418 | mg_ch32v307_swap, |
| 5419 | }; |
| 5420 | |
| 5421 | #define FLASH_BASE 0x40022000 |
| 5422 | #define FLASH_ACTLR (FLASH_BASE + 0) |
| 5423 | #define FLASH_KEYR (FLASH_BASE + 4) |
| 5424 | #define FLASH_OBKEYR (FLASH_BASE + 8) |
| 5425 | #define FLASH_STATR (FLASH_BASE + 12) |
| 5426 | #define FLASH_CTLR (FLASH_BASE + 16) |
| 5427 | #define FLASH_ADDR (FLASH_BASE + 20) |
| 5428 | #define FLASH_OBR (FLASH_BASE + 28) |
| 5429 | #define FLASH_WPR (FLASH_BASE + 32) |
| 5430 | |
| 5431 | MG_IRAM static void flash_unlock(void) { |
| 5432 | static bool unlocked; |
| 5433 | if (unlocked == false) { |
| 5434 | MG_REG(FLASH_KEYR) = 0x45670123; |
| 5435 | MG_REG(FLASH_KEYR) = 0xcdef89ab; |
| 5436 | unlocked = true; |
| 5437 | } |
| 5438 | } |
| 5439 | |
| 5440 | MG_IRAM static void flash_wait(void) { |
| 5441 | while (MG_REG(FLASH_STATR) & MG_BIT(0)) (void) 0; |
| 5442 | } |
| 5443 | |
| 5444 | MG_IRAM static void mg_ch32v307_erase(void *addr) { |
| 5445 | // MG_INFO(("%p", addr)); |
| 5446 | flash_unlock(); |
| 5447 | flash_wait(); |
| 5448 | MG_REG(FLASH_ADDR) = (uint32_t) addr; |
| 5449 | MG_REG(FLASH_CTLR) |= MG_BIT(1) | MG_BIT(6); // PER | STRT; |
| 5450 | flash_wait(); |
| 5451 | } |
| 5452 | |
| 5453 | MG_IRAM static bool is_page_boundary(const void *addr) { |
| 5454 | uint32_t val = (uint32_t) addr; |
| 5455 | return (val & (s_mg_flash_ch32v307.secsz - 1)) == 0; |
| 5456 | } |
| 5457 | |
| 5458 | MG_IRAM static bool mg_ch32v307_write(void *addr, const void *buf, size_t len) { |
| 5459 | // MG_INFO(("%p %p %lu", addr, buf, len)); |
| 5460 | // mg_hexdump(buf, len); |
| 5461 | flash_unlock(); |
| 5462 | const uint16_t *src = (uint16_t *) buf, *end = &src[len / 2]; |
| 5463 | uint16_t *dst = (uint16_t *) addr; |
| 5464 | MG_REG(FLASH_CTLR) |= MG_BIT(0); // Set PG |
| 5465 | // MG_INFO(("CTLR: %#lx", MG_REG(FLASH_CTLR))); |
| 5466 | while (src < end) { |
| 5467 | if (is_page_boundary(dst)) mg_ch32v307_erase(dst); |
| 5468 | *dst++ = *src++; |
| 5469 | flash_wait(); |
| 5470 | } |
| 5471 | MG_REG(FLASH_CTLR) &= ~MG_BIT(0); // Clear PG |
| 5472 | return true; |
| 5473 | } |
| 5474 | |
| 5475 | MG_IRAM bool mg_ch32v307_swap(void) { |
| 5476 | return true; |
| 5477 | } |
| 5478 | |
| 5479 | // just overwrite instead of swap |
| 5480 | MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { |
| 5481 | // no stdlib calls here |
| 5482 | for (size_t ofs = 0; ofs < s; ofs += ss) { |
| 5483 | mg_ch32v307_write(p1 + ofs, p2 + ofs, ss); |
| 5484 | } |
| 5485 | *((volatile uint32_t *) 0xbeef0000) |= 1U << 7; // NVIC_SystemReset() |
| 5486 | } |
| 5487 | |
| 5488 | bool mg_ota_begin(size_t new_firmware_size) { |
| 5489 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_ch32v307); |
| 5490 | } |
| 5491 | |
| 5492 | bool mg_ota_write(const void *buf, size_t len) { |
| 5493 | return mg_ota_flash_write(buf, len, &s_mg_flash_ch32v307); |
| 5494 | } |
| 5495 | |
| 5496 | bool mg_ota_end(void) { |
| 5497 | if (mg_ota_flash_end(&s_mg_flash_ch32v307)) { |
| 5498 | // Swap partitions. Pray power does not go away |
| 5499 | MG_INFO(("Swapping partitions, size %u (%u sectors)", |
| 5500 | s_mg_flash_ch32v307.size, |
| 5501 | s_mg_flash_ch32v307.size / s_mg_flash_ch32v307.secsz)); |
| 5502 | MG_INFO(("Do NOT power off...")); |
| 5503 | mg_log_level = MG_LL_NONE; |
| 5504 | // TODO() disable IRQ, s_flash_irq_disabled = true; |
| 5505 | // Runs in RAM, will reset when finished |
| 5506 | single_bank_swap( |
| 5507 | (char *) s_mg_flash_ch32v307.start, |
| 5508 | (char *) s_mg_flash_ch32v307.start + s_mg_flash_ch32v307.size / 2, |
| 5509 | s_mg_flash_ch32v307.size / 2, s_mg_flash_ch32v307.secsz); |
| 5510 | } |
| 5511 | return false; |
| 5512 | } |
| 5513 | #endif |
| 5514 | |
| 5515 | #ifdef MG_ENABLE_LINES |
| 5516 | #line 1 "src/ota_dummy.c" |
| 5517 | #endif |
| 5518 | |
| 5519 | |
| 5520 | |
| 5521 | #if MG_OTA == MG_OTA_NONE |
| 5522 | bool mg_ota_begin(size_t new_firmware_size) { |
| 5523 | (void) new_firmware_size; |
| 5524 | return true; |
| 5525 | } |
| 5526 | bool mg_ota_write(const void *buf, size_t len) { |
| 5527 | (void) buf, (void) len; |
| 5528 | return true; |
| 5529 | } |
| 5530 | bool mg_ota_end(void) { |
| 5531 | return true; |
| 5532 | } |
| 5533 | #endif |
| 5534 | |
| 5535 | #ifdef MG_ENABLE_LINES |
| 5536 | #line 1 "src/ota_esp32.c" |
| 5537 | #endif |
| 5538 | |
| 5539 | |
| 5540 | #if MG_ARCH == MG_ARCH_ESP32 && MG_OTA == MG_OTA_ESP32 |
| 5541 | |
| 5542 | static const esp_partition_t *s_ota_update_partition; |
| 5543 | static esp_ota_handle_t s_ota_update_handle; |
| 5544 | static bool s_ota_success; |
| 5545 | |
| 5546 | // Those empty macros do nothing, but mark places in the code which could |
| 5547 | // potentially trigger a watchdog reboot due to the log flash erase operation |
| 5548 | #define disable_wdt() |
| 5549 | #define enable_wdt() |
| 5550 | |
| 5551 | bool mg_ota_begin(size_t new_firmware_size) { |
| 5552 | if (s_ota_update_partition != NULL) { |
| 5553 | MG_ERROR(("Update in progress. Call mg_ota_end() ?")); |
| 5554 | return false; |
| 5555 | } else { |
| 5556 | s_ota_success = false; |
| 5557 | disable_wdt(); |
| 5558 | s_ota_update_partition = esp_ota_get_next_update_partition(NULL); |
| 5559 | esp_err_t err = esp_ota_begin(s_ota_update_partition, new_firmware_size, |
| 5560 | &s_ota_update_handle); |
| 5561 | enable_wdt(); |
| 5562 | MG_DEBUG(("esp_ota_begin(): %d", err)); |
| 5563 | s_ota_success = (err == ESP_OK); |
| 5564 | } |
| 5565 | return s_ota_success; |
| 5566 | } |
| 5567 | |
| 5568 | bool mg_ota_write(const void *buf, size_t len) { |
| 5569 | disable_wdt(); |
| 5570 | esp_err_t err = esp_ota_write(s_ota_update_handle, buf, len); |
| 5571 | enable_wdt(); |
| 5572 | MG_INFO(("esp_ota_write(): %d", err)); |
| 5573 | s_ota_success = err == ESP_OK; |
| 5574 | return s_ota_success; |
| 5575 | } |
| 5576 | |
| 5577 | bool mg_ota_end(void) { |
| 5578 | esp_err_t err = esp_ota_end(s_ota_update_handle); |
| 5579 | MG_DEBUG(("esp_ota_end(%p): %d", s_ota_update_handle, err)); |
| 5580 | if (s_ota_success && err == ESP_OK) { |
| 5581 | err = esp_ota_set_boot_partition(s_ota_update_partition); |
| 5582 | s_ota_success = (err == ESP_OK); |
| 5583 | } |
| 5584 | MG_DEBUG(("Finished ESP32 OTA, success: %d", s_ota_success)); |
| 5585 | s_ota_update_partition = NULL; |
| 5586 | return s_ota_success; |
| 5587 | } |
| 5588 | |
| 5589 | #endif |
| 5590 | |
| 5591 | #ifdef MG_ENABLE_LINES |
| 5592 | #line 1 "src/ota_imxrt.c" |
| 5593 | #endif |
| 5594 | |
| 5595 | |
| 5596 | |
| 5597 | |
| 5598 | #if MG_OTA >= MG_OTA_RT1020 && MG_OTA <= MG_OTA_RT1170 |
| 5599 | |
| 5600 | static bool mg_imxrt_write(void *, const void *, size_t); |
| 5601 | static bool mg_imxrt_swap(void); |
| 5602 | |
| 5603 | #if MG_OTA <= MG_OTA_RT1060 |
| 5604 | #define MG_IMXRT_FLASH_START 0x60000000 |
| 5605 | #define FLEXSPI_NOR_INSTANCE 0 |
| 5606 | #elif MG_OTA == MG_OTA_RT1064 |
| 5607 | #define MG_IMXRT_FLASH_START 0x70000000 |
| 5608 | #define FLEXSPI_NOR_INSTANCE 1 |
| 5609 | #else // RT1170 |
| 5610 | #define MG_IMXRT_FLASH_START 0x30000000 |
| 5611 | #define FLEXSPI_NOR_INSTANCE 1 |
| 5612 | #endif |
| 5613 | |
| 5614 | #if MG_OTA == MG_OTA_RT1050 |
| 5615 | #define MG_IMXRT_SECTOR_SIZE (256 * 1024) |
| 5616 | #define MG_IMXRT_PAGE_SIZE 512 |
| 5617 | #else |
| 5618 | #define MG_IMXRT_SECTOR_SIZE (4 * 1024) |
| 5619 | #define MG_IMXRT_PAGE_SIZE 256 |
| 5620 | #endif |
| 5621 | |
| 5622 | // TODO(): fill at init, support more devices in a dynamic way |
| 5623 | // TODO(): then, check alignment is <= 256, see Wizard's #251 |
| 5624 | static struct mg_flash s_mg_flash_imxrt = { |
| 5625 | (void *) MG_IMXRT_FLASH_START, // Start, |
| 5626 | 4 * 1024 * 1024, // Size, 4mb |
| 5627 | MG_IMXRT_SECTOR_SIZE, // Sector size |
| 5628 | MG_IMXRT_PAGE_SIZE, // Align |
| 5629 | mg_imxrt_write, |
| 5630 | mg_imxrt_swap, |
| 5631 | }; |
| 5632 | |
| 5633 | struct mg_flexspi_lut_seq { |
| 5634 | uint8_t seqNum; |
| 5635 | uint8_t seqId; |
| 5636 | uint16_t reserved; |
| 5637 | }; |
| 5638 | |
| 5639 | struct mg_flexspi_mem_config { |
| 5640 | uint32_t tag; |
| 5641 | uint32_t version; |
| 5642 | uint32_t reserved0; |
| 5643 | uint8_t readSampleClkSrc; |
| 5644 | uint8_t csHoldTime; |
| 5645 | uint8_t csSetupTime; |
| 5646 | uint8_t columnAddressWidth; |
| 5647 | uint8_t deviceModeCfgEnable; |
| 5648 | uint8_t deviceModeType; |
| 5649 | uint16_t waitTimeCfgCommands; |
| 5650 | struct mg_flexspi_lut_seq deviceModeSeq; |
| 5651 | uint32_t deviceModeArg; |
| 5652 | uint8_t configCmdEnable; |
| 5653 | uint8_t configModeType[3]; |
| 5654 | struct mg_flexspi_lut_seq configCmdSeqs[3]; |
| 5655 | uint32_t reserved1; |
| 5656 | uint32_t configCmdArgs[3]; |
| 5657 | uint32_t reserved2; |
| 5658 | uint32_t controllerMiscOption; |
| 5659 | uint8_t deviceType; |
| 5660 | uint8_t sflashPadType; |
| 5661 | uint8_t serialClkFreq; |
| 5662 | uint8_t lutCustomSeqEnable; |
| 5663 | uint32_t reserved3[2]; |
| 5664 | uint32_t sflashA1Size; |
| 5665 | uint32_t sflashA2Size; |
| 5666 | uint32_t sflashB1Size; |
| 5667 | uint32_t sflashB2Size; |
| 5668 | uint32_t csPadSettingOverride; |
| 5669 | uint32_t sclkPadSettingOverride; |
| 5670 | uint32_t dataPadSettingOverride; |
| 5671 | uint32_t dqsPadSettingOverride; |
| 5672 | uint32_t timeoutInMs; |
| 5673 | uint32_t commandInterval; |
| 5674 | uint16_t dataValidTime[2]; |
| 5675 | uint16_t busyOffset; |
| 5676 | uint16_t busyBitPolarity; |
| 5677 | uint32_t lookupTable[64]; |
| 5678 | struct mg_flexspi_lut_seq lutCustomSeq[12]; |
| 5679 | uint32_t reserved4[4]; |
| 5680 | }; |
| 5681 | |
| 5682 | struct mg_flexspi_nor_config { |
| 5683 | struct mg_flexspi_mem_config memConfig; |
| 5684 | uint32_t pageSize; |
| 5685 | uint32_t sectorSize; |
| 5686 | uint8_t ipcmdSerialClkFreq; |
| 5687 | uint8_t isUniformBlockSize; |
| 5688 | uint8_t reserved0[2]; |
| 5689 | uint8_t serialNorType; |
| 5690 | uint8_t needExitNoCmdMode; |
| 5691 | uint8_t halfClkForNonReadCmd; |
| 5692 | uint8_t needRestoreNoCmdMode; |
| 5693 | uint32_t blockSize; |
| 5694 | uint32_t reserve2[11]; |
| 5695 | }; |
| 5696 | |
| 5697 | /* FLEXSPI memory config block related defintions */ |
| 5698 | #define MG_FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian |
| 5699 | #define MG_FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 |
| 5700 | |
| 5701 | #define MG_FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ |
| 5702 | (MG_FLEXSPI_LUT_OPERAND0(op0) | MG_FLEXSPI_LUT_NUM_PADS0(pad0) | \ |
| 5703 | MG_FLEXSPI_LUT_OPCODE0(cmd0) | MG_FLEXSPI_LUT_OPERAND1(op1) | \ |
| 5704 | MG_FLEXSPI_LUT_NUM_PADS1(pad1) | MG_FLEXSPI_LUT_OPCODE1(cmd1)) |
| 5705 | |
| 5706 | #define MG_CMD_SDR 0x01 |
| 5707 | #define MG_CMD_DDR 0x21 |
| 5708 | #define MG_DUMMY_SDR 0x0C |
| 5709 | #define MG_DUMMY_DDR 0x2C |
| 5710 | #define MG_DUMMY_RWDS_DDR 0x2D |
| 5711 | #define MG_RADDR_SDR 0x02 |
| 5712 | #define MG_RADDR_DDR 0x22 |
| 5713 | #define MG_CADDR_DDR 0x23 |
| 5714 | #define MG_READ_SDR 0x09 |
| 5715 | #define MG_READ_DDR 0x29 |
| 5716 | #define MG_WRITE_SDR 0x08 |
| 5717 | #define MG_WRITE_DDR 0x28 |
| 5718 | #define MG_STOP 0 |
| 5719 | |
| 5720 | #define MG_FLEXSPI_1PAD 0 |
| 5721 | #define MG_FLEXSPI_2PAD 1 |
| 5722 | #define MG_FLEXSPI_4PAD 2 |
| 5723 | #define MG_FLEXSPI_8PAD 3 |
| 5724 | |
| 5725 | #define MG_FLEXSPI_QSPI_LUT \ |
| 5726 | { \ |
| 5727 | [0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0xEB, MG_RADDR_SDR, \ |
| 5728 | MG_FLEXSPI_4PAD, 0x18), \ |
| 5729 | [1] = MG_FLEXSPI_LUT_SEQ(MG_DUMMY_SDR, MG_FLEXSPI_4PAD, 0x06, MG_READ_SDR, \ |
| 5730 | MG_FLEXSPI_4PAD, 0x04), \ |
| 5731 | [4 * 1 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x05, \ |
| 5732 | MG_READ_SDR, MG_FLEXSPI_1PAD, 0x04), \ |
| 5733 | [4 * 3 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x06, \ |
| 5734 | MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ |
| 5735 | [4 * 5 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x20, \ |
| 5736 | MG_RADDR_SDR, MG_FLEXSPI_1PAD, 0x18), \ |
| 5737 | [4 * 8 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0xD8, \ |
| 5738 | MG_RADDR_SDR, MG_FLEXSPI_1PAD, 0x18), \ |
| 5739 | [4 * 9 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x02, \ |
| 5740 | MG_RADDR_SDR, MG_FLEXSPI_1PAD, 0x18), \ |
| 5741 | [4 * 9 + 1] = MG_FLEXSPI_LUT_SEQ(MG_WRITE_SDR, MG_FLEXSPI_1PAD, 0x04, \ |
| 5742 | MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ |
| 5743 | [4 * 11 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x60, \ |
| 5744 | MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ |
| 5745 | } |
| 5746 | |
| 5747 | #define MG_FLEXSPI_HYPER_LUT \ |
| 5748 | { \ |
| 5749 | [0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xA0, MG_RADDR_DDR, \ |
| 5750 | MG_FLEXSPI_8PAD, 0x18), \ |
| 5751 | [1] = MG_FLEXSPI_LUT_SEQ(MG_CADDR_DDR, MG_FLEXSPI_8PAD, 0x10, \ |
| 5752 | MG_DUMMY_DDR, MG_FLEXSPI_8PAD, 0x0C), \ |
| 5753 | [2] = MG_FLEXSPI_LUT_SEQ(MG_READ_DDR, MG_FLEXSPI_8PAD, 0x04, MG_STOP, \ |
| 5754 | MG_FLEXSPI_1PAD, 0x0), \ |
| 5755 | [4 * 1 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5756 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5757 | [4 * 1 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5758 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5759 | [4 * 1 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5760 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5761 | [4 * 1 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5762 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x70), \ |
| 5763 | [4 * 2 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xA0, \ |
| 5764 | MG_RADDR_DDR, MG_FLEXSPI_8PAD, 0x18), \ |
| 5765 | [4 * 2 + 1] = \ |
| 5766 | MG_FLEXSPI_LUT_SEQ(MG_CADDR_DDR, MG_FLEXSPI_8PAD, 0x10, \ |
| 5767 | MG_DUMMY_RWDS_DDR, MG_FLEXSPI_8PAD, 0x0B), \ |
| 5768 | [4 * 2 + 2] = MG_FLEXSPI_LUT_SEQ(MG_READ_DDR, MG_FLEXSPI_8PAD, 0x4, \ |
| 5769 | MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ |
| 5770 | [4 * 3 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5771 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5772 | [4 * 3 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5773 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5774 | [4 * 3 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5775 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5776 | [4 * 3 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5777 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5778 | [4 * 4 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5779 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5780 | [4 * 4 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5781 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x55), \ |
| 5782 | [4 * 4 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5783 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x02), \ |
| 5784 | [4 * 4 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5785 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x55), \ |
| 5786 | [4 * 5 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5787 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5788 | [4 * 5 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5789 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5790 | [4 * 5 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5791 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5792 | [4 * 5 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5793 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x80), \ |
| 5794 | [4 * 6 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5795 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5796 | [4 * 6 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5797 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5798 | [4 * 6 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5799 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5800 | [4 * 6 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5801 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5802 | [4 * 7 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5803 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5804 | [4 * 7 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5805 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x55), \ |
| 5806 | [4 * 7 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5807 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x02), \ |
| 5808 | [4 * 7 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5809 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x55), \ |
| 5810 | [4 * 8 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5811 | MG_RADDR_DDR, MG_FLEXSPI_8PAD, 0x18), \ |
| 5812 | [4 * 8 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CADDR_DDR, MG_FLEXSPI_8PAD, 0x10, \ |
| 5813 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5814 | [4 * 8 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x30, \ |
| 5815 | MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ |
| 5816 | [4 * 9 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5817 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5818 | [4 * 9 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5819 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5820 | [4 * 9 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5821 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5822 | [4 * 9 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5823 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xA0), \ |
| 5824 | [4 * 10 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5825 | MG_RADDR_DDR, MG_FLEXSPI_8PAD, 0x18), \ |
| 5826 | [4 * 10 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CADDR_DDR, MG_FLEXSPI_8PAD, 0x10, \ |
| 5827 | MG_WRITE_DDR, MG_FLEXSPI_8PAD, 0x80), \ |
| 5828 | [4 * 11 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5829 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5830 | [4 * 11 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5831 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5832 | [4 * 11 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5833 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5834 | [4 * 11 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5835 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x80), \ |
| 5836 | [4 * 12 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5837 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5838 | [4 * 12 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5839 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5840 | [4 * 12 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5841 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5842 | [4 * 12 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5843 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5844 | [4 * 13 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5845 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5846 | [4 * 13 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5847 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x55), \ |
| 5848 | [4 * 13 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5849 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x02), \ |
| 5850 | [4 * 13 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5851 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x55), \ |
| 5852 | [4 * 14 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5853 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0), \ |
| 5854 | [4 * 14 + 1] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5855 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0xAA), \ |
| 5856 | [4 * 14 + 2] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5857 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x05), \ |
| 5858 | [4 * 14 + 3] = MG_FLEXSPI_LUT_SEQ(MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x0, \ |
| 5859 | MG_CMD_DDR, MG_FLEXSPI_8PAD, 0x10), \ |
| 5860 | } |
| 5861 | |
| 5862 | #define MG_LUT_CUSTOM_SEQ \ |
| 5863 | { \ |
| 5864 | {.seqNum = 0, .seqId = 0, .reserved = 0}, \ |
| 5865 | {.seqNum = 2, .seqId = 1, .reserved = 0}, \ |
| 5866 | {.seqNum = 2, .seqId = 3, .reserved = 0}, \ |
| 5867 | {.seqNum = 4, .seqId = 5, .reserved = 0}, \ |
| 5868 | {.seqNum = 2, .seqId = 9, .reserved = 0}, \ |
| 5869 | {.seqNum = 4, .seqId = 11, .reserved = 0}, \ |
| 5870 | } |
| 5871 | |
| 5872 | #define MG_FLEXSPI_LUT_OPERAND0(x) (((uint32_t) (((uint32_t) (x)))) & 0xFFU) |
| 5873 | #define MG_FLEXSPI_LUT_NUM_PADS0(x) \ |
| 5874 | (((uint32_t) (((uint32_t) (x)) << 8U)) & 0x300U) |
| 5875 | #define MG_FLEXSPI_LUT_OPCODE0(x) \ |
| 5876 | (((uint32_t) (((uint32_t) (x)) << 10U)) & 0xFC00U) |
| 5877 | #define MG_FLEXSPI_LUT_OPERAND1(x) \ |
| 5878 | (((uint32_t) (((uint32_t) (x)) << 16U)) & 0xFF0000U) |
| 5879 | #define MG_FLEXSPI_LUT_NUM_PADS1(x) \ |
| 5880 | (((uint32_t) (((uint32_t) (x)) << 24U)) & 0x3000000U) |
| 5881 | #define MG_FLEXSPI_LUT_OPCODE1(x) \ |
| 5882 | (((uint32_t) (((uint32_t) (x)) << 26U)) & 0xFC000000U) |
| 5883 | |
| 5884 | #if MG_OTA == MG_OTA_RT1020 || MG_OTA == MG_OTA_RT1050 |
| 5885 | // RT102X and RT105x boards support ROM API version 1.4 |
| 5886 | struct mg_flexspi_nor_driver_interface { |
| 5887 | uint32_t version; |
| 5888 | int (*init)(uint32_t instance, struct mg_flexspi_nor_config *config); |
| 5889 | int (*program)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5890 | uint32_t dst_addr, const uint32_t *src); |
| 5891 | uint32_t reserved; |
| 5892 | int (*erase)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5893 | uint32_t start, uint32_t lengthInBytes); |
| 5894 | uint32_t reserved2; |
| 5895 | int (*update_lut)(uint32_t instance, uint32_t seqIndex, |
| 5896 | const uint32_t *lutBase, uint32_t seqNumber); |
| 5897 | int (*xfer)(uint32_t instance, char *xfer); |
| 5898 | void (*clear_cache)(uint32_t instance); |
| 5899 | }; |
| 5900 | #elif MG_OTA <= MG_OTA_RT1064 |
| 5901 | // RT104x and RT106x support ROM API version 1.5 |
| 5902 | struct mg_flexspi_nor_driver_interface { |
| 5903 | uint32_t version; |
| 5904 | int (*init)(uint32_t instance, struct mg_flexspi_nor_config *config); |
| 5905 | int (*program)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5906 | uint32_t dst_addr, const uint32_t *src); |
| 5907 | int (*erase_all)(uint32_t instance, struct mg_flexspi_nor_config *config); |
| 5908 | int (*erase)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5909 | uint32_t start, uint32_t lengthInBytes); |
| 5910 | int (*read)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5911 | uint32_t *dst, uint32_t addr, uint32_t lengthInBytes); |
| 5912 | void (*clear_cache)(uint32_t instance); |
| 5913 | int (*xfer)(uint32_t instance, char *xfer); |
| 5914 | int (*update_lut)(uint32_t instance, uint32_t seqIndex, |
| 5915 | const uint32_t *lutBase, uint32_t seqNumber); |
| 5916 | int (*get_config)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5917 | uint32_t *option); |
| 5918 | }; |
| 5919 | #else |
| 5920 | // RT117x support ROM API version 1.7 |
| 5921 | struct mg_flexspi_nor_driver_interface { |
| 5922 | uint32_t version; |
| 5923 | int (*init)(uint32_t instance, struct mg_flexspi_nor_config *config); |
| 5924 | int (*program)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5925 | uint32_t dst_addr, const uint32_t *src); |
| 5926 | int (*erase_all)(uint32_t instance, struct mg_flexspi_nor_config *config); |
| 5927 | int (*erase)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5928 | uint32_t start, uint32_t lengthInBytes); |
| 5929 | int (*read)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5930 | uint32_t *dst, uint32_t addr, uint32_t lengthInBytes); |
| 5931 | uint32_t reserved; |
| 5932 | int (*xfer)(uint32_t instance, char *xfer); |
| 5933 | int (*update_lut)(uint32_t instance, uint32_t seqIndex, |
| 5934 | const uint32_t *lutBase, uint32_t seqNumber); |
| 5935 | int (*get_config)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5936 | uint32_t *option); |
| 5937 | int (*erase_sector)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5938 | uint32_t address); |
| 5939 | int (*erase_block)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5940 | uint32_t address); |
| 5941 | void (*hw_reset)(uint32_t instance, uint32_t resetLogic); |
| 5942 | int (*wait_busy)(uint32_t instance, struct mg_flexspi_nor_config *config, |
| 5943 | bool isParallelMode, uint32_t address); |
| 5944 | int (*set_clock_source)(uint32_t instance, uint32_t clockSrc); |
| 5945 | void (*config_clock)(uint32_t instance, uint32_t freqOption, |
| 5946 | uint32_t sampleClkMode); |
| 5947 | }; |
| 5948 | #endif |
| 5949 | |
| 5950 | #if MG_OTA <= MG_OTA_RT1064 |
| 5951 | #define MG_FLEXSPI_BASE 0x402A8000 |
| 5952 | #define flexspi_nor \ |
| 5953 | (*((struct mg_flexspi_nor_driver_interface **) (*(uint32_t *) 0x0020001c + \ |
| 5954 | 16))) |
| 5955 | #else |
| 5956 | #define MG_FLEXSPI_BASE 0x400CC000 |
| 5957 | #define flexspi_nor \ |
| 5958 | (*((struct mg_flexspi_nor_driver_interface **) (*(uint32_t *) 0x0021001c + \ |
| 5959 | 12))) |
| 5960 | #endif |
| 5961 | |
| 5962 | static bool s_flash_irq_disabled; |
| 5963 | |
| 5964 | MG_IRAM static bool flash_page_start(volatile uint32_t *dst) { |
| 5965 | char *base = (char *) s_mg_flash_imxrt.start, |
| 5966 | *end = base + s_mg_flash_imxrt.size; |
| 5967 | volatile char *p = (char *) dst; |
| 5968 | return p >= base && p < end && ((p - base) % s_mg_flash_imxrt.secsz) == 0; |
| 5969 | } |
| 5970 | |
| 5971 | #if MG_OTA == MG_OTA_RT1050 |
| 5972 | // Configuration for Hyper flash memory |
| 5973 | static struct mg_flexspi_nor_config default_config = { |
| 5974 | .memConfig = |
| 5975 | { |
| 5976 | .tag = MG_FLEXSPI_CFG_BLK_TAG, |
| 5977 | .version = MG_FLEXSPI_CFG_BLK_VERSION, |
| 5978 | .readSampleClkSrc = 3, // ReadSampleClk_LoopbackFromDqsPad |
| 5979 | .csHoldTime = 3, |
| 5980 | .csSetupTime = 3, |
| 5981 | .columnAddressWidth = 3u, |
| 5982 | .controllerMiscOption = |
| 5983 | MG_BIT(6) | MG_BIT(4) | MG_BIT(3) | MG_BIT(0), |
| 5984 | .deviceType = 1, // serial NOR |
| 5985 | .sflashPadType = 8, |
| 5986 | .serialClkFreq = 7, // 133MHz |
| 5987 | .sflashA1Size = 64 * 1024 * 1024, |
| 5988 | .dataValidTime = {15, 0}, |
| 5989 | .busyOffset = 15, |
| 5990 | .busyBitPolarity = 1, |
| 5991 | .lutCustomSeqEnable = 0x1, |
| 5992 | .lookupTable = MG_FLEXSPI_HYPER_LUT, |
| 5993 | .lutCustomSeq = MG_LUT_CUSTOM_SEQ, |
| 5994 | }, |
| 5995 | .pageSize = 512, |
| 5996 | .sectorSize = 256 * 1024, |
| 5997 | .ipcmdSerialClkFreq = 1, |
| 5998 | .serialNorType = 1u, |
| 5999 | .blockSize = 256 * 1024, |
| 6000 | .isUniformBlockSize = true}; |
| 6001 | #else |
| 6002 | // Note: this QSPI configuration works for RTs supporting QSPI |
| 6003 | // Configuration for QSPI memory |
| 6004 | static struct mg_flexspi_nor_config default_config = { |
| 6005 | .memConfig = {.tag = MG_FLEXSPI_CFG_BLK_TAG, |
| 6006 | .version = MG_FLEXSPI_CFG_BLK_VERSION, |
| 6007 | .readSampleClkSrc = 1, // ReadSampleClk_LoopbackFromDqsPad |
| 6008 | .csHoldTime = 3, |
| 6009 | .csSetupTime = 3, |
| 6010 | .controllerMiscOption = MG_BIT(4), |
| 6011 | .deviceType = 1, // serial NOR |
| 6012 | .sflashPadType = 4, |
| 6013 | .serialClkFreq = 7, // 133MHz |
| 6014 | .sflashA1Size = 8 * 1024 * 1024, |
| 6015 | .lookupTable = MG_FLEXSPI_QSPI_LUT}, |
| 6016 | .pageSize = 256, |
| 6017 | .sectorSize = 4 * 1024, |
| 6018 | .ipcmdSerialClkFreq = 1, |
| 6019 | .blockSize = 64 * 1024, |
| 6020 | .isUniformBlockSize = false}; |
| 6021 | #endif |
| 6022 | |
| 6023 | // must reside in RAM, as flash will be erased |
| 6024 | MG_IRAM static int flexspi_nor_get_config( |
| 6025 | struct mg_flexspi_nor_config **config) { |
| 6026 | *config = &default_config; |
| 6027 | return 0; |
| 6028 | } |
| 6029 | |
| 6030 | #if 0 |
| 6031 | // ROM API get_config call (ROM version >= 1.5) |
| 6032 | MG_IRAM static int flexspi_nor_get_config( |
| 6033 | struct mg_flexspi_nor_config **config) { |
| 6034 | uint32_t options[] = {0xc0000000, 0x00}; |
| 6035 | |
| 6036 | MG_ARM_DISABLE_IRQ(); |
| 6037 | uint32_t status = |
| 6038 | flexspi_nor->get_config(FLEXSPI_NOR_INSTANCE, *config, options); |
| 6039 | if (!s_flash_irq_disabled) { |
| 6040 | MG_ARM_ENABLE_IRQ(); |
| 6041 | } |
| 6042 | if (status) { |
| 6043 | MG_ERROR(("Failed to extract flash configuration: status %u", status)); |
| 6044 | } |
| 6045 | return status; |
| 6046 | } |
| 6047 | #endif |
| 6048 | |
| 6049 | MG_IRAM static void mg_spin(volatile uint32_t count) { |
| 6050 | while (count--) (void) 0; |
| 6051 | } |
| 6052 | |
| 6053 | MG_IRAM static void flash_wait(void) { |
| 6054 | while ((*((volatile uint32_t *) (MG_FLEXSPI_BASE + 0xE0)) & MG_BIT(1)) == 0) |
| 6055 | mg_spin(1); |
| 6056 | } |
| 6057 | |
| 6058 | MG_IRAM static bool flash_erase(struct mg_flexspi_nor_config *config, |
| 6059 | void *addr) { |
| 6060 | if (flash_page_start(addr) == false) { |
| 6061 | MG_ERROR(("%p is not on a sector boundary", addr)); |
| 6062 | return false; |
| 6063 | } |
| 6064 | |
| 6065 | void *dst = (void *) ((char *) addr - (char *) s_mg_flash_imxrt.start); |
| 6066 | |
| 6067 | bool ok = (flexspi_nor->erase(FLEXSPI_NOR_INSTANCE, config, (uint32_t) dst, |
| 6068 | s_mg_flash_imxrt.secsz) == 0); |
| 6069 | MG_DEBUG(("Sector starting at %p erasure: %s", addr, ok ? "ok" : "fail")); |
| 6070 | return ok; |
| 6071 | } |
| 6072 | |
| 6073 | #if 0 |
| 6074 | // standalone erase call |
| 6075 | MG_IRAM static bool mg_imxrt_erase(void *addr) { |
| 6076 | struct mg_flexspi_nor_config config, *config_ptr = &config; |
| 6077 | bool ret; |
| 6078 | // Interrupts must be disabled before calls to ROM API in RT1020 and 1060 |
| 6079 | MG_ARM_DISABLE_IRQ(); |
| 6080 | ret = (flexspi_nor_get_config(&config_ptr) == 0); |
| 6081 | if (ret) ret = flash_erase(config_ptr, addr); |
| 6082 | MG_ARM_ENABLE_IRQ(); |
| 6083 | return ret; |
| 6084 | } |
| 6085 | #endif |
| 6086 | |
| 6087 | MG_IRAM bool mg_imxrt_swap(void) { |
| 6088 | return true; |
| 6089 | } |
| 6090 | |
| 6091 | MG_IRAM static bool mg_imxrt_write(void *addr, const void *buf, size_t len) { |
| 6092 | struct mg_flexspi_nor_config config, *config_ptr = &config; |
| 6093 | bool ok = false; |
| 6094 | // Interrupts must be disabled before calls to ROM API in RT1020 and 1060 |
| 6095 | MG_ARM_DISABLE_IRQ(); |
| 6096 | if (flexspi_nor_get_config(&config_ptr) != 0) goto fwxit; |
| 6097 | if ((len % s_mg_flash_imxrt.align) != 0) { |
| 6098 | MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_imxrt.align)); |
| 6099 | goto fwxit; |
| 6100 | } |
| 6101 | if ((char *) addr < (char *) s_mg_flash_imxrt.start) { |
| 6102 | MG_ERROR(("Invalid flash write address: %p", addr)); |
| 6103 | goto fwxit; |
| 6104 | } |
| 6105 | |
| 6106 | uint32_t *dst = (uint32_t *) addr; |
| 6107 | uint32_t *src = (uint32_t *) buf; |
| 6108 | uint32_t *end = (uint32_t *) ((char *) buf + len); |
| 6109 | ok = true; |
| 6110 | |
| 6111 | while (ok && src < end) { |
| 6112 | if (flash_page_start(dst) && flash_erase(config_ptr, dst) == false) { |
| 6113 | ok = false; |
| 6114 | break; |
| 6115 | } |
| 6116 | uint32_t status; |
| 6117 | uint32_t dst_ofs = (uint32_t) dst - (uint32_t) s_mg_flash_imxrt.start; |
| 6118 | if ((char *) buf >= (char *) s_mg_flash_imxrt.start) { |
| 6119 | // If we copy from FLASH to FLASH, then we first need to copy the source |
| 6120 | // to RAM |
| 6121 | size_t tmp_buf_size = s_mg_flash_imxrt.align / sizeof(uint32_t); |
| 6122 | uint32_t tmp[tmp_buf_size]; |
| 6123 | |
| 6124 | for (size_t i = 0; i < tmp_buf_size; i++) { |
| 6125 | flash_wait(); |
| 6126 | tmp[i] = src[i]; |
| 6127 | } |
| 6128 | status = flexspi_nor->program(FLEXSPI_NOR_INSTANCE, config_ptr, |
| 6129 | (uint32_t) dst_ofs, tmp); |
| 6130 | } else { |
| 6131 | status = flexspi_nor->program(FLEXSPI_NOR_INSTANCE, config_ptr, |
| 6132 | (uint32_t) dst_ofs, src); |
| 6133 | } |
| 6134 | src = (uint32_t *) ((char *) src + s_mg_flash_imxrt.align); |
| 6135 | dst = (uint32_t *) ((char *) dst + s_mg_flash_imxrt.align); |
| 6136 | if (status != 0) { |
| 6137 | ok = false; |
| 6138 | } |
| 6139 | } |
| 6140 | MG_DEBUG(("Flash write %lu bytes @ %p: %s.", len, dst, ok ? "ok" : "fail")); |
| 6141 | fwxit: |
| 6142 | if (!s_flash_irq_disabled) MG_ARM_ENABLE_IRQ(); |
| 6143 | return ok; |
| 6144 | } |
| 6145 | |
| 6146 | // just overwrite instead of swap |
| 6147 | MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { |
| 6148 | // no stdlib calls here |
| 6149 | for (size_t ofs = 0; ofs < s; ofs += ss) { |
| 6150 | mg_imxrt_write(p1 + ofs, p2 + ofs, ss); |
| 6151 | } |
| 6152 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 6153 | } |
| 6154 | |
| 6155 | bool mg_ota_begin(size_t new_firmware_size) { |
| 6156 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_imxrt); |
| 6157 | } |
| 6158 | |
| 6159 | bool mg_ota_write(const void *buf, size_t len) { |
| 6160 | return mg_ota_flash_write(buf, len, &s_mg_flash_imxrt); |
| 6161 | } |
| 6162 | |
| 6163 | bool mg_ota_end(void) { |
| 6164 | if (mg_ota_flash_end(&s_mg_flash_imxrt)) { |
| 6165 | if (0) { // is_dualbank() |
| 6166 | // TODO(): no devices so far |
| 6167 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 6168 | } else { |
| 6169 | // Swap partitions. Pray power does not go away |
| 6170 | MG_INFO(("Swapping partitions, size %u (%u sectors)", |
| 6171 | s_mg_flash_imxrt.size, |
| 6172 | s_mg_flash_imxrt.size / s_mg_flash_imxrt.secsz)); |
| 6173 | MG_INFO(("Do NOT power off...")); |
| 6174 | mg_log_level = MG_LL_NONE; |
| 6175 | s_flash_irq_disabled = true; |
| 6176 | // Runs in RAM, will reset when finished |
| 6177 | single_bank_swap( |
| 6178 | (char *) s_mg_flash_imxrt.start, |
| 6179 | (char *) s_mg_flash_imxrt.start + s_mg_flash_imxrt.size / 2, |
| 6180 | s_mg_flash_imxrt.size / 2, s_mg_flash_imxrt.secsz); |
| 6181 | } |
| 6182 | } |
| 6183 | return false; |
| 6184 | } |
| 6185 | |
| 6186 | #endif |
| 6187 | |
| 6188 | #ifdef MG_ENABLE_LINES |
| 6189 | #line 1 "src/ota_mcxn.c" |
| 6190 | #endif |
| 6191 | |
| 6192 | |
| 6193 | |
| 6194 | |
| 6195 | #if MG_OTA == MG_OTA_MCXN |
| 6196 | |
| 6197 | // - Flash phrase: 16 bytes; smallest portion programmed in one operation. |
| 6198 | // - Flash page: 128 bytes; largest portion programmed in one operation. |
| 6199 | // - Flash sector: 8 KB; smallest portion that can be erased in one operation. |
| 6200 | // - Flash API mg_flash_driver->program: "start" and "len" must be page-size |
| 6201 | // aligned; to use 'phrase', FMU register access is needed. Using ROM |
| 6202 | |
| 6203 | static bool mg_mcxn_write(void *, const void *, size_t); |
| 6204 | static bool mg_mcxn_swap(void); |
| 6205 | |
| 6206 | static struct mg_flash s_mg_flash_mcxn = { |
| 6207 | (void *) 0, // Start, filled at init |
| 6208 | 0, // Size, filled at init |
| 6209 | 0, // Sector size, filled at init |
| 6210 | 0, // Align, filled at init |
| 6211 | mg_mcxn_write, |
| 6212 | mg_mcxn_swap, |
| 6213 | }; |
| 6214 | |
| 6215 | struct mg_flash_config { |
| 6216 | uint32_t addr; |
| 6217 | uint32_t size; |
| 6218 | uint32_t blocks; |
| 6219 | uint32_t page_size; |
| 6220 | uint32_t sector_size; |
| 6221 | uint32_t ffr[6]; |
| 6222 | uint32_t reserved0[5]; |
| 6223 | uint32_t *bootctx; |
| 6224 | bool useahb; |
| 6225 | }; |
| 6226 | |
| 6227 | struct mg_flash_driver_interface { |
| 6228 | uint32_t version; |
| 6229 | uint32_t (*init)(struct mg_flash_config *); |
| 6230 | uint32_t (*erase)(struct mg_flash_config *, uint32_t start, uint32_t len, |
| 6231 | uint32_t key); |
| 6232 | uint32_t (*program)(struct mg_flash_config *, uint32_t start, uint8_t *src, |
| 6233 | uint32_t len); |
| 6234 | uint32_t (*verify_erase)(struct mg_flash_config *, uint32_t start, |
| 6235 | uint32_t len); |
| 6236 | uint32_t (*verify_program)(struct mg_flash_config *, uint32_t start, |
| 6237 | uint32_t len, const uint8_t *expected, |
| 6238 | uint32_t *addr, uint32_t *failed); |
| 6239 | uint32_t reserved1[12]; |
| 6240 | uint32_t (*read)(struct mg_flash_config *, uint32_t start, uint8_t *dest, |
| 6241 | uint32_t len); |
| 6242 | uint32_t reserved2[4]; |
| 6243 | uint32_t (*deinit)(struct mg_flash_config *); |
| 6244 | }; |
| 6245 | #define mg_flash_driver \ |
| 6246 | ((struct mg_flash_driver_interface *) (*((uint32_t *) 0x1303fc00 + 4))) |
| 6247 | #define MG_MCXN_FLASK_KEY (('k' << 24) | ('e' << 16) | ('f' << 8) | 'l') |
| 6248 | |
| 6249 | MG_IRAM static bool flash_sector_start(volatile uint32_t *dst) { |
| 6250 | char *base = (char *) s_mg_flash_mcxn.start, |
| 6251 | *end = base + s_mg_flash_mcxn.size; |
| 6252 | volatile char *p = (char *) dst; |
| 6253 | return p >= base && p < end && ((p - base) % s_mg_flash_mcxn.secsz) == 0; |
| 6254 | } |
| 6255 | |
| 6256 | MG_IRAM static bool flash_erase(struct mg_flash_config *config, void *addr) { |
| 6257 | if (flash_sector_start(addr) == false) { |
| 6258 | MG_ERROR(("%p is not on a sector boundary", addr)); |
| 6259 | return false; |
| 6260 | } |
| 6261 | uint32_t dst = |
| 6262 | (uint32_t) addr - (uint32_t) s_mg_flash_mcxn.start; // future-proof |
| 6263 | uint32_t status = mg_flash_driver->erase(config, dst, s_mg_flash_mcxn.secsz, |
| 6264 | MG_MCXN_FLASK_KEY); |
| 6265 | bool ok = (status == 0); |
| 6266 | if (!ok) MG_ERROR(("Flash write error: %lu", status)); |
| 6267 | MG_DEBUG(("Sector starting at %p erasure: %s", addr, ok ? "ok" : "fail")); |
| 6268 | return ok; |
| 6269 | } |
| 6270 | |
| 6271 | #if 0 |
| 6272 | // read-while-write, no need to disable IRQs for standalone usage |
| 6273 | MG_IRAM static bool mg_mcxn_erase(void *addr) { |
| 6274 | uint32_t status; |
| 6275 | struct mg_flash_config config; |
| 6276 | if ((status = mg_flash_driver->init(&config)) != 0) { |
| 6277 | MG_ERROR(("Flash driver init error: %lu", status)); |
| 6278 | return false; |
| 6279 | } |
| 6280 | bool ok = flash_erase(&config, addr); |
| 6281 | mg_flash_driver->deinit(&config); |
| 6282 | return ok; |
| 6283 | } |
| 6284 | #endif |
| 6285 | |
| 6286 | MG_IRAM static bool mg_mcxn_swap(void) { |
| 6287 | // TODO(): no devices so far |
| 6288 | return true; |
| 6289 | } |
| 6290 | |
| 6291 | static bool s_flash_irq_disabled; |
| 6292 | |
| 6293 | MG_IRAM static bool mg_mcxn_write(void *addr, const void *buf, size_t len) { |
| 6294 | bool ok = false; |
| 6295 | uint32_t status; |
| 6296 | struct mg_flash_config config; |
| 6297 | if ((status = mg_flash_driver->init(&config)) != 0) { |
| 6298 | MG_ERROR(("Flash driver init error: %lu", status)); |
| 6299 | return false; |
| 6300 | } |
| 6301 | if ((len % s_mg_flash_mcxn.align) != 0) { |
| 6302 | MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_mcxn.align)); |
| 6303 | goto fwxit; |
| 6304 | } |
| 6305 | if ((((size_t) addr - (size_t) s_mg_flash_mcxn.start) % |
| 6306 | s_mg_flash_mcxn.align) != 0) { |
| 6307 | MG_ERROR(("%p is not on a page boundary", addr)); |
| 6308 | goto fwxit; |
| 6309 | } |
| 6310 | |
| 6311 | uint32_t *dst = (uint32_t *) addr; |
| 6312 | uint32_t *src = (uint32_t *) buf; |
| 6313 | uint32_t *end = (uint32_t *) ((char *) buf + len); |
| 6314 | ok = true; |
| 6315 | |
| 6316 | MG_ARM_DISABLE_IRQ(); |
| 6317 | while (ok && src < end) { |
| 6318 | if (flash_sector_start(dst) && flash_erase(&config, dst) == false) { |
| 6319 | ok = false; |
| 6320 | break; |
| 6321 | } |
| 6322 | uint32_t dst_ofs = (uint32_t) dst - (uint32_t) s_mg_flash_mcxn.start; |
| 6323 | // assume source is in RAM or in a different bank or read-while-write |
| 6324 | status = mg_flash_driver->program(&config, dst_ofs, (uint8_t *) src, |
| 6325 | s_mg_flash_mcxn.align); |
| 6326 | src = (uint32_t *) ((char *) src + s_mg_flash_mcxn.align); |
| 6327 | dst = (uint32_t *) ((char *) dst + s_mg_flash_mcxn.align); |
| 6328 | if (status != 0) { |
| 6329 | MG_ERROR(("Flash write error: %lu", status)); |
| 6330 | ok = false; |
| 6331 | } |
| 6332 | } |
| 6333 | if (!s_flash_irq_disabled) MG_ARM_ENABLE_IRQ(); |
| 6334 | MG_DEBUG(("Flash write %lu bytes @ %p: %s.", len, dst, ok ? "ok" : "fail")); |
| 6335 | |
| 6336 | fwxit: |
| 6337 | mg_flash_driver->deinit(&config); |
| 6338 | return ok; |
| 6339 | } |
| 6340 | |
| 6341 | // try to swap (honor dual image), otherwise just overwrite |
| 6342 | MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { |
| 6343 | char *tmp = malloc(ss); |
| 6344 | // no stdlib calls here |
| 6345 | for (size_t ofs = 0; ofs < s; ofs += ss) { |
| 6346 | if (tmp != NULL) |
| 6347 | for (size_t i = 0; i < ss; i++) tmp[i] = p1[ofs + i]; |
| 6348 | mg_mcxn_write(p1 + ofs, p2 + ofs, ss); |
| 6349 | if (tmp != NULL) mg_mcxn_write(p2 + ofs, tmp, ss); |
| 6350 | } |
| 6351 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 6352 | } |
| 6353 | |
| 6354 | bool mg_ota_begin(size_t new_firmware_size) { |
| 6355 | uint32_t status; |
| 6356 | struct mg_flash_config config; |
| 6357 | if ((status = mg_flash_driver->init(&config)) != 0) { |
| 6358 | MG_ERROR(("Flash driver init error: %lu", status)); |
| 6359 | return false; |
| 6360 | } |
| 6361 | s_mg_flash_mcxn.start = (void *) config.addr; |
| 6362 | s_mg_flash_mcxn.size = config.size; |
| 6363 | s_mg_flash_mcxn.secsz = config.sector_size; |
| 6364 | s_mg_flash_mcxn.align = config.page_size; |
| 6365 | mg_flash_driver->deinit(&config); |
| 6366 | MG_DEBUG( |
| 6367 | ("%lu-byte flash @%p, using %lu-byte sectors with %lu-byte-aligned pages", |
| 6368 | s_mg_flash_mcxn.size, s_mg_flash_mcxn.start, s_mg_flash_mcxn.secsz, |
| 6369 | s_mg_flash_mcxn.align)); |
| 6370 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_mcxn); |
| 6371 | } |
| 6372 | |
| 6373 | bool mg_ota_write(const void *buf, size_t len) { |
| 6374 | return mg_ota_flash_write(buf, len, &s_mg_flash_mcxn); |
| 6375 | } |
| 6376 | |
| 6377 | bool mg_ota_end(void) { |
| 6378 | if (mg_ota_flash_end(&s_mg_flash_mcxn)) { |
| 6379 | if (0) { // is_dualbank() |
| 6380 | // TODO(): no devices so far |
| 6381 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 6382 | } else { |
| 6383 | // Swap partitions. Pray power does not go away |
| 6384 | MG_INFO(("Swapping partitions, size %u (%u sectors)", |
| 6385 | s_mg_flash_mcxn.size, |
| 6386 | s_mg_flash_mcxn.size / s_mg_flash_mcxn.secsz)); |
| 6387 | MG_INFO(("Do NOT power off...")); |
| 6388 | mg_log_level = MG_LL_NONE; |
| 6389 | s_flash_irq_disabled = true; |
| 6390 | // Runs in RAM, will reset when finished |
| 6391 | single_bank_swap( |
| 6392 | (char *) s_mg_flash_mcxn.start, |
| 6393 | (char *) s_mg_flash_mcxn.start + s_mg_flash_mcxn.size / 2, |
| 6394 | s_mg_flash_mcxn.size / 2, s_mg_flash_mcxn.secsz); |
| 6395 | } |
| 6396 | } |
| 6397 | return false; |
| 6398 | } |
| 6399 | #endif |
| 6400 | |
| 6401 | #ifdef MG_ENABLE_LINES |
| 6402 | #line 1 "src/ota_picosdk.c" |
| 6403 | #endif |
| 6404 | |
| 6405 | |
| 6406 | |
| 6407 | |
| 6408 | #if MG_OTA == MG_OTA_PICOSDK |
| 6409 | |
| 6410 | // Both RP2040 and RP2350 have no flash, low-level flash access support in |
| 6411 | // bootrom, and high-level support in Pico-SDK (2.0+ for the RP2350) |
| 6412 | // - The RP2350 in RISC-V mode is not tested |
| 6413 | // NOTE(): See OTA design notes |
| 6414 | |
| 6415 | static bool mg_picosdk_write(void *, const void *, size_t); |
| 6416 | static bool mg_picosdk_swap(void); |
| 6417 | |
| 6418 | static struct mg_flash s_mg_flash_picosdk = { |
| 6419 | (void *) 0x10000000, // Start; functions handle offset |
| 6420 | #ifdef PICO_FLASH_SIZE_BYTES |
| 6421 | PICO_FLASH_SIZE_BYTES, // Size, from board definitions |
| 6422 | #else |
| 6423 | 0x200000, // Size, guess... is 2M enough ? |
| 6424 | #endif |
| 6425 | FLASH_SECTOR_SIZE, // Sector size, from hardware_flash |
| 6426 | FLASH_PAGE_SIZE, // Align, from hardware_flash |
| 6427 | mg_picosdk_write, mg_picosdk_swap, |
| 6428 | }; |
| 6429 | |
| 6430 | #define MG_MODULO2(x, m) ((x) & ((m) -1)) |
| 6431 | |
| 6432 | static bool __no_inline_not_in_flash_func(flash_sector_start)( |
| 6433 | volatile uint32_t *dst) { |
| 6434 | char *base = (char *) s_mg_flash_picosdk.start, |
| 6435 | *end = base + s_mg_flash_picosdk.size; |
| 6436 | volatile char *p = (char *) dst; |
| 6437 | return p >= base && p < end && |
| 6438 | MG_MODULO2(p - base, s_mg_flash_picosdk.secsz) == 0; |
| 6439 | } |
| 6440 | |
| 6441 | static bool __no_inline_not_in_flash_func(flash_erase)(void *addr) { |
| 6442 | if (flash_sector_start(addr) == false) { |
| 6443 | MG_ERROR(("%p is not on a sector boundary", addr)); |
| 6444 | return false; |
| 6445 | } |
| 6446 | void *dst = (void *) ((char *) addr - (char *) s_mg_flash_picosdk.start); |
| 6447 | flash_range_erase((uint32_t) dst, s_mg_flash_picosdk.secsz); |
| 6448 | MG_DEBUG(("Sector starting at %p erasure", addr)); |
| 6449 | return true; |
| 6450 | } |
| 6451 | |
| 6452 | static bool __no_inline_not_in_flash_func(mg_picosdk_swap)(void) { |
| 6453 | // TODO(): RP2350 might have some A/B functionality (DS 5.1) |
| 6454 | return true; |
| 6455 | } |
| 6456 | |
| 6457 | static bool s_flash_irq_disabled; |
| 6458 | |
| 6459 | static bool __no_inline_not_in_flash_func(mg_picosdk_write)(void *addr, |
| 6460 | const void *buf, |
| 6461 | size_t len) { |
| 6462 | if ((len % s_mg_flash_picosdk.align) != 0) { |
| 6463 | MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_picosdk.align)); |
| 6464 | return false; |
| 6465 | } |
| 6466 | if ((((size_t) addr - (size_t) s_mg_flash_picosdk.start) % |
| 6467 | s_mg_flash_picosdk.align) != 0) { |
| 6468 | MG_ERROR(("%p is not on a page boundary", addr)); |
| 6469 | return false; |
| 6470 | } |
| 6471 | |
| 6472 | uint32_t *dst = (uint32_t *) addr; |
| 6473 | uint32_t *src = (uint32_t *) buf; |
| 6474 | uint32_t *end = (uint32_t *) ((char *) buf + len); |
| 6475 | |
| 6476 | #ifndef __riscv |
| 6477 | MG_ARM_DISABLE_IRQ(); |
| 6478 | #else |
| 6479 | asm volatile("csrrc zero, mstatus, %0" : : "i"(1 << 3) : "memory"); |
| 6480 | #endif |
| 6481 | while (src < end) { |
| 6482 | uint32_t dst_ofs = (uint32_t) dst - (uint32_t) s_mg_flash_picosdk.start; |
| 6483 | if (flash_sector_start(dst) && flash_erase(dst) == false) break; |
| 6484 | // flash_range_program() runs in RAM and handles writing up to |
| 6485 | // FLASH_PAGE_SIZE bytes. Source must not be in flash |
| 6486 | flash_range_program((uint32_t) dst_ofs, (uint8_t *) src, |
| 6487 | s_mg_flash_picosdk.align); |
| 6488 | src = (uint32_t *) ((char *) src + s_mg_flash_picosdk.align); |
| 6489 | dst = (uint32_t *) ((char *) dst + s_mg_flash_picosdk.align); |
| 6490 | } |
| 6491 | if (!s_flash_irq_disabled) { |
| 6492 | #ifndef __riscv |
| 6493 | MG_ARM_ENABLE_IRQ(); |
| 6494 | #else |
| 6495 | asm volatile("csrrs mstatus, %0" : : "i"(1 << 3) : "memory"); |
| 6496 | #endif |
| 6497 | } |
| 6498 | MG_DEBUG(("Flash write %lu bytes @ %p.", len, dst)); |
| 6499 | return true; |
| 6500 | } |
| 6501 | |
| 6502 | // just overwrite instead of swap |
| 6503 | static void __no_inline_not_in_flash_func(single_bank_swap)(char *p1, char *p2, |
| 6504 | size_t s, |
| 6505 | size_t ss) { |
| 6506 | char *tmp = malloc(ss); |
| 6507 | if (tmp == NULL) return; |
| 6508 | #if PICO_RP2040 |
| 6509 | uint32_t xip[256 / sizeof(uint32_t)]; |
| 6510 | void *dst = (void *) ((char *) p1 - (char *) s_mg_flash_picosdk.start); |
| 6511 | size_t count = MG_ROUND_UP(s, ss); |
| 6512 | // use SDK function calls to get BootROM function pointers |
| 6513 | rom_connect_internal_flash_fn connect = (rom_connect_internal_flash_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH); |
| 6514 | rom_flash_exit_xip_fn xit = (rom_flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP); |
| 6515 | rom_flash_range_program_fn program = (rom_flash_range_program_fn) rom_func_lookup(ROM_FUNC_FLASH_RANGE_PROGRAM); |
| 6516 | rom_flash_flush_cache_fn flush = (rom_flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE); |
| 6517 | // no stdlib calls here. |
| 6518 | MG_ARM_DISABLE_IRQ(); |
| 6519 | // 2nd bootloader (XIP) is in flash, SDK functions copy it to RAM on entry |
| 6520 | for (size_t i = 0; i < 256 / sizeof(uint32_t); i++) |
| 6521 | xip[i] = ((uint32_t *) (s_mg_flash_picosdk.start))[i]; |
| 6522 | flash_range_erase((uint32_t) dst, count); |
| 6523 | // flash has been erased, no XIP to copy. Only BootROM calls possible |
| 6524 | for (uint32_t ofs = 0; ofs < s; ofs += ss) { |
| 6525 | for (size_t i = 0; i < ss; i++) tmp[i] = p2[ofs + i]; |
| 6526 | __compiler_memory_barrier(); |
| 6527 | connect(); |
| 6528 | xit(); |
| 6529 | program((uint32_t) dst + ofs, tmp, ss); |
| 6530 | flush(); |
| 6531 | ((void (*)(void))((intptr_t) xip + 1))(); // enter XIP again |
| 6532 | } |
| 6533 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; // AIRCR = SYSRESETREQ |
| 6534 | #else |
| 6535 | // RP2350 has BootRAM and copies second bootloader there, SDK uses that copy, |
| 6536 | // It might also be able to take advantage of partition swapping |
| 6537 | rom_reboot_fn reboot = (rom_reboot_fn) rom_func_lookup(ROM_FUNC_REBOOT); |
| 6538 | for (size_t ofs = 0; ofs < s; ofs += ss) { |
| 6539 | for (size_t i = 0; i < ss; i++) tmp[i] = p2[ofs + i]; |
| 6540 | mg_picosdk_write(p1 + ofs, tmp, ss); |
| 6541 | } |
| 6542 | reboot(BOOT_TYPE_NORMAL | 0x100, 1, 0, 0); // 0x100: NO_RETURN_ON_SUCCESS |
| 6543 | #endif |
| 6544 | } |
| 6545 | |
| 6546 | bool mg_ota_begin(size_t new_firmware_size) { |
| 6547 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_picosdk); |
| 6548 | } |
| 6549 | |
| 6550 | bool mg_ota_write(const void *buf, size_t len) { |
| 6551 | return mg_ota_flash_write(buf, len, &s_mg_flash_picosdk); |
| 6552 | } |
| 6553 | |
| 6554 | bool mg_ota_end(void) { |
| 6555 | if (mg_ota_flash_end(&s_mg_flash_picosdk)) { |
| 6556 | // Swap partitions. Pray power does not go away |
| 6557 | MG_INFO(("Swapping partitions, size %u (%u sectors)", |
| 6558 | s_mg_flash_picosdk.size, |
| 6559 | s_mg_flash_picosdk.size / s_mg_flash_picosdk.secsz)); |
| 6560 | MG_INFO(("Do NOT power off...")); |
| 6561 | mg_log_level = MG_LL_NONE; |
| 6562 | s_flash_irq_disabled = true; |
| 6563 | // Runs in RAM, will reset when finished or return on failure |
| 6564 | single_bank_swap( |
| 6565 | (char *) s_mg_flash_picosdk.start, |
| 6566 | (char *) s_mg_flash_picosdk.start + s_mg_flash_picosdk.size / 2, |
| 6567 | s_mg_flash_picosdk.size / 2, s_mg_flash_picosdk.secsz); |
| 6568 | } |
| 6569 | return false; |
| 6570 | } |
| 6571 | #endif |
| 6572 | |
| 6573 | #ifdef MG_ENABLE_LINES |
| 6574 | #line 1 "src/ota_stm32f.c" |
| 6575 | #endif |
| 6576 | |
| 6577 | |
| 6578 | |
| 6579 | |
| 6580 | #if MG_OTA == MG_OTA_STM32F |
| 6581 | |
| 6582 | static bool mg_stm32f_write(void *, const void *, size_t); |
| 6583 | static bool mg_stm32f_swap(void); |
| 6584 | |
| 6585 | static struct mg_flash s_mg_flash_stm32f = { |
| 6586 | (void *) 0x08000000, // Start |
| 6587 | 0, // Size, FLASH_SIZE_REG |
| 6588 | 0, // Irregular sector size |
| 6589 | 32, // Align, 256 bit |
| 6590 | mg_stm32f_write, |
| 6591 | mg_stm32f_swap, |
| 6592 | }; |
| 6593 | |
| 6594 | #define MG_FLASH_BASE 0x40023c00 |
| 6595 | #define MG_FLASH_KEYR 0x04 |
| 6596 | #define MG_FLASH_SR 0x0c |
| 6597 | #define MG_FLASH_CR 0x10 |
| 6598 | #define MG_FLASH_OPTCR 0x14 |
| 6599 | #define MG_FLASH_SIZE_REG_F7 0x1FF0F442 |
| 6600 | #define MG_FLASH_SIZE_REG_F4 0x1FFF7A22 |
| 6601 | |
| 6602 | #define STM_DBGMCU_IDCODE 0xE0042000 |
| 6603 | #define STM_DEV_ID (MG_REG(STM_DBGMCU_IDCODE) & (MG_BIT(12) - 1)) |
| 6604 | #define SYSCFG_MEMRMP 0x40013800 |
| 6605 | |
| 6606 | #define MG_FLASH_SIZE_REG_LOCATION \ |
| 6607 | ((STM_DEV_ID >= 0x449) ? MG_FLASH_SIZE_REG_F7 : MG_FLASH_SIZE_REG_F4) |
| 6608 | |
| 6609 | static size_t flash_size(void) { |
| 6610 | return (MG_REG(MG_FLASH_SIZE_REG_LOCATION) & 0xFFFF) * 1024; |
| 6611 | } |
| 6612 | |
| 6613 | MG_IRAM static int is_dualbank(void) { |
| 6614 | // only F42x/F43x series (0x419) support dual bank |
| 6615 | return STM_DEV_ID == 0x419; |
| 6616 | } |
| 6617 | |
| 6618 | MG_IRAM static void flash_unlock(void) { |
| 6619 | static bool unlocked = false; |
| 6620 | if (unlocked == false) { |
| 6621 | MG_REG(MG_FLASH_BASE + MG_FLASH_KEYR) = 0x45670123; |
| 6622 | MG_REG(MG_FLASH_BASE + MG_FLASH_KEYR) = 0xcdef89ab; |
| 6623 | unlocked = true; |
| 6624 | } |
| 6625 | } |
| 6626 | |
| 6627 | #define MG_FLASH_CONFIG_16_64_128 1 // used by STM32F7 |
| 6628 | #define MG_FLASH_CONFIG_32_128_256 2 // used by STM32F4 and F2 |
| 6629 | |
| 6630 | MG_IRAM static bool flash_page_start(volatile uint32_t *dst) { |
| 6631 | char *base = (char *) s_mg_flash_stm32f.start; |
| 6632 | char *end = base + s_mg_flash_stm32f.size; |
| 6633 | |
| 6634 | if (is_dualbank() && dst >= (uint32_t *) (base + (end - base) / 2)) { |
| 6635 | dst = (uint32_t *) ((uint32_t) dst - (end - base) / 2); |
| 6636 | } |
| 6637 | |
| 6638 | uint32_t flash_config = MG_FLASH_CONFIG_16_64_128; |
| 6639 | if (STM_DEV_ID >= 0x449) { |
| 6640 | flash_config = MG_FLASH_CONFIG_32_128_256; |
| 6641 | } |
| 6642 | |
| 6643 | volatile char *p = (char *) dst; |
| 6644 | if (p >= base && p < end) { |
| 6645 | if (p < base + 16 * 1024 * 4 * flash_config) { |
| 6646 | if ((p - base) % (16 * 1024 * flash_config) == 0) return true; |
| 6647 | } else if (p == base + 16 * 1024 * 4 * flash_config) { |
| 6648 | return true; |
| 6649 | } else if ((p - base) % (128 * 1024 * flash_config) == 0) { |
| 6650 | return true; |
| 6651 | } |
| 6652 | } |
| 6653 | return false; |
| 6654 | } |
| 6655 | |
| 6656 | MG_IRAM static int flash_sector(volatile uint32_t *addr) { |
| 6657 | char *base = (char *) s_mg_flash_stm32f.start; |
| 6658 | char *end = base + s_mg_flash_stm32f.size; |
| 6659 | bool addr_in_bank_2 = false; |
| 6660 | if (is_dualbank() && addr >= (uint32_t *) (base + (end - base) / 2)) { |
| 6661 | addr = (uint32_t *) ((uint32_t) addr - (end - base) / 2); |
| 6662 | addr_in_bank_2 = true; |
| 6663 | } |
| 6664 | volatile char *p = (char *) addr; |
| 6665 | uint32_t flash_config = MG_FLASH_CONFIG_16_64_128; |
| 6666 | if (STM_DEV_ID >= 0x449) { |
| 6667 | flash_config = MG_FLASH_CONFIG_32_128_256; |
| 6668 | } |
| 6669 | int sector = -1; |
| 6670 | if (p >= base && p < end) { |
| 6671 | if (p < base + 16 * 1024 * 4 * flash_config) { |
| 6672 | sector = (p - base) / (16 * 1024 * flash_config); |
| 6673 | } else if (p >= base + 64 * 1024 * flash_config && |
| 6674 | p < base + 128 * 1024 * flash_config) { |
| 6675 | sector = 4; |
| 6676 | } else { |
| 6677 | sector = (p - base) / (128 * 1024 * flash_config) + 4; |
| 6678 | } |
| 6679 | } |
| 6680 | if (sector == -1) return -1; |
| 6681 | if (addr_in_bank_2) sector += 12; // a bank has 12 sectors |
| 6682 | return sector; |
| 6683 | } |
| 6684 | |
| 6685 | MG_IRAM static bool flash_is_err(void) { |
| 6686 | return MG_REG(MG_FLASH_BASE + MG_FLASH_SR) & ((MG_BIT(7) - 1) << 1); |
| 6687 | } |
| 6688 | |
| 6689 | MG_IRAM static void flash_wait(void) { |
| 6690 | while (MG_REG(MG_FLASH_BASE + MG_FLASH_SR) & (MG_BIT(16))) (void) 0; |
| 6691 | } |
| 6692 | |
| 6693 | MG_IRAM static void flash_clear_err(void) { |
| 6694 | flash_wait(); // Wait until ready |
| 6695 | MG_REG(MG_FLASH_BASE + MG_FLASH_SR) = 0xf2; // Clear all errors |
| 6696 | } |
| 6697 | |
| 6698 | MG_IRAM static bool mg_stm32f_erase(void *addr) { |
| 6699 | bool ok = false; |
| 6700 | if (flash_page_start(addr) == false) { |
| 6701 | MG_ERROR(("%p is not on a sector boundary", addr)); |
| 6702 | } else { |
| 6703 | int sector = flash_sector(addr); |
| 6704 | if (sector < 0) return false; |
| 6705 | uint32_t sector_reg = sector; |
| 6706 | if (is_dualbank() && sector >= 12) { |
| 6707 | // 3.9.8 Flash control register (FLASH_CR) for F42xxx and F43xxx |
| 6708 | // BITS[7:3] |
| 6709 | sector_reg -= 12; |
| 6710 | sector_reg |= MG_BIT(4); |
| 6711 | } |
| 6712 | flash_unlock(); |
| 6713 | flash_wait(); |
| 6714 | uint32_t cr = MG_BIT(1); // SER |
| 6715 | cr |= MG_BIT(16); // STRT |
| 6716 | cr |= (sector_reg & 31) << 3; // sector |
| 6717 | MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = cr; |
| 6718 | ok = !flash_is_err(); |
| 6719 | MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr, |
| 6720 | ok ? "ok" : "fail", MG_REG(MG_FLASH_BASE + MG_FLASH_CR), |
| 6721 | MG_REG(MG_FLASH_BASE + MG_FLASH_SR))); |
| 6722 | // After we have erased the sector, set CR flags for programming |
| 6723 | // 2 << 8 is word write parallelism, bit(0) is PG. RM0385, section 3.7.5 |
| 6724 | MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = MG_BIT(0) | (2 << 8); |
| 6725 | flash_clear_err(); |
| 6726 | } |
| 6727 | return ok; |
| 6728 | } |
| 6729 | |
| 6730 | MG_IRAM static bool mg_stm32f_swap(void) { |
| 6731 | // STM32 F42x/F43x support dual bank, however, the memory mapping |
| 6732 | // change will not be carried through a hard reset. Therefore, we will use |
| 6733 | // the single bank approach for this family as well. |
| 6734 | return true; |
| 6735 | } |
| 6736 | |
| 6737 | static bool s_flash_irq_disabled; |
| 6738 | |
| 6739 | MG_IRAM static bool mg_stm32f_write(void *addr, const void *buf, size_t len) { |
| 6740 | if ((len % s_mg_flash_stm32f.align) != 0) { |
| 6741 | MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_stm32f.align)); |
| 6742 | return false; |
| 6743 | } |
| 6744 | uint32_t *dst = (uint32_t *) addr; |
| 6745 | uint32_t *src = (uint32_t *) buf; |
| 6746 | uint32_t *end = (uint32_t *) ((char *) buf + len); |
| 6747 | bool ok = true; |
| 6748 | MG_ARM_DISABLE_IRQ(); |
| 6749 | flash_unlock(); |
| 6750 | flash_clear_err(); |
| 6751 | MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = MG_BIT(0) | MG_BIT(9); // PG, 32-bit |
| 6752 | flash_wait(); |
| 6753 | MG_DEBUG(("Writing flash @ %p, %lu bytes", addr, len)); |
| 6754 | while (ok && src < end) { |
| 6755 | if (flash_page_start(dst) && mg_stm32f_erase(dst) == false) break; |
| 6756 | *(volatile uint32_t *) dst++ = *src++; |
| 6757 | MG_DSB(); // ensure flash is written with no errors |
| 6758 | flash_wait(); |
| 6759 | if (flash_is_err()) ok = false; |
| 6760 | } |
| 6761 | if (!s_flash_irq_disabled) MG_ARM_ENABLE_IRQ(); |
| 6762 | MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst, |
| 6763 | ok ? "ok" : "fail", MG_REG(MG_FLASH_BASE + MG_FLASH_CR), |
| 6764 | MG_REG(MG_FLASH_BASE + MG_FLASH_SR))); |
| 6765 | MG_REG(MG_FLASH_BASE + MG_FLASH_CR) &= ~MG_BIT(0); // Clear programming flag |
| 6766 | return ok; |
| 6767 | } |
| 6768 | |
| 6769 | // just overwrite instead of swap |
| 6770 | MG_IRAM void single_bank_swap(char *p1, char *p2, size_t size) { |
| 6771 | // no stdlib calls here |
| 6772 | mg_stm32f_write(p1, p2, size); |
| 6773 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 6774 | } |
| 6775 | |
| 6776 | bool mg_ota_begin(size_t new_firmware_size) { |
| 6777 | s_mg_flash_stm32f.size = flash_size(); |
| 6778 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32f); |
| 6779 | } |
| 6780 | |
| 6781 | bool mg_ota_write(const void *buf, size_t len) { |
| 6782 | return mg_ota_flash_write(buf, len, &s_mg_flash_stm32f); |
| 6783 | } |
| 6784 | |
| 6785 | bool mg_ota_end(void) { |
| 6786 | if (mg_ota_flash_end(&s_mg_flash_stm32f)) { |
| 6787 | // Swap partitions. Pray power does not go away |
| 6788 | MG_INFO(("Swapping partitions, size %u (%u sectors)", |
| 6789 | s_mg_flash_stm32f.size, STM_DEV_ID == 0x449 ? 8 : 12)); |
| 6790 | MG_INFO(("Do NOT power off...")); |
| 6791 | mg_log_level = MG_LL_NONE; |
| 6792 | s_flash_irq_disabled = true; |
| 6793 | char *p1 = (char *) s_mg_flash_stm32f.start; |
| 6794 | char *p2 = p1 + s_mg_flash_stm32f.size / 2; |
| 6795 | size_t size = s_mg_flash_stm32f.size / 2; |
| 6796 | // Runs in RAM, will reset when finished |
| 6797 | single_bank_swap(p1, p2, size); |
| 6798 | } |
| 6799 | return false; |
| 6800 | } |
| 6801 | #endif |
| 6802 | |
| 6803 | #ifdef MG_ENABLE_LINES |
| 6804 | #line 1 "src/ota_stm32h5.c" |
| 6805 | #endif |
| 6806 | |
| 6807 | |
| 6808 | |
| 6809 | |
| 6810 | #if MG_OTA == MG_OTA_STM32H5 |
| 6811 | |
| 6812 | static bool mg_stm32h5_write(void *, const void *, size_t); |
| 6813 | static bool mg_stm32h5_swap(void); |
| 6814 | |
| 6815 | static struct mg_flash s_mg_flash_stm32h5 = { |
| 6816 | (void *) 0x08000000, // Start |
| 6817 | 2 * 1024 * 1024, // Size, 2Mb |
| 6818 | 8 * 1024, // Sector size, 8k |
| 6819 | 16, // Align, 128 bit |
| 6820 | mg_stm32h5_write, |
| 6821 | mg_stm32h5_swap, |
| 6822 | }; |
| 6823 | |
| 6824 | #define MG_FLASH_BASE 0x40022000 // Base address of the flash controller |
| 6825 | #define FLASH_KEYR (MG_FLASH_BASE + 0x4) // See RM0481 7.11 |
| 6826 | #define FLASH_OPTKEYR (MG_FLASH_BASE + 0xc) |
| 6827 | #define FLASH_OPTCR (MG_FLASH_BASE + 0x1c) |
| 6828 | #define FLASH_NSSR (MG_FLASH_BASE + 0x20) |
| 6829 | #define FLASH_NSCR (MG_FLASH_BASE + 0x28) |
| 6830 | #define FLASH_NSCCR (MG_FLASH_BASE + 0x30) |
| 6831 | #define FLASH_OPTSR_CUR (MG_FLASH_BASE + 0x50) |
| 6832 | #define FLASH_OPTSR_PRG (MG_FLASH_BASE + 0x54) |
| 6833 | |
| 6834 | static void flash_unlock(void) { |
| 6835 | static bool unlocked = false; |
| 6836 | if (unlocked == false) { |
| 6837 | MG_REG(FLASH_KEYR) = 0x45670123; |
| 6838 | MG_REG(FLASH_KEYR) = 0Xcdef89ab; |
| 6839 | MG_REG(FLASH_OPTKEYR) = 0x08192a3b; |
| 6840 | MG_REG(FLASH_OPTKEYR) = 0x4c5d6e7f; |
| 6841 | unlocked = true; |
| 6842 | } |
| 6843 | } |
| 6844 | |
| 6845 | static int flash_page_start(volatile uint32_t *dst) { |
| 6846 | char *base = (char *) s_mg_flash_stm32h5.start, |
| 6847 | *end = base + s_mg_flash_stm32h5.size; |
| 6848 | volatile char *p = (char *) dst; |
| 6849 | return p >= base && p < end && ((p - base) % s_mg_flash_stm32h5.secsz) == 0; |
| 6850 | } |
| 6851 | |
| 6852 | static bool flash_is_err(void) { |
| 6853 | return MG_REG(FLASH_NSSR) & ((MG_BIT(8) - 1) << 17); // RM0481 7.11.9 |
| 6854 | } |
| 6855 | |
| 6856 | static void flash_wait(void) { |
| 6857 | while ((MG_REG(FLASH_NSSR) & MG_BIT(0)) && |
| 6858 | (MG_REG(FLASH_NSSR) & MG_BIT(16)) == 0) { |
| 6859 | (void) 0; |
| 6860 | } |
| 6861 | } |
| 6862 | |
| 6863 | static void flash_clear_err(void) { |
| 6864 | flash_wait(); // Wait until ready |
| 6865 | MG_REG(FLASH_NSCCR) = ((MG_BIT(9) - 1) << 16U); // Clear all errors |
| 6866 | } |
| 6867 | |
| 6868 | static bool flash_bank_is_swapped(void) { |
| 6869 | return MG_REG(FLASH_OPTCR) & MG_BIT(31); // RM0481 7.11.8 |
| 6870 | } |
| 6871 | |
| 6872 | static bool mg_stm32h5_erase(void *location) { |
| 6873 | bool ok = false; |
| 6874 | if (flash_page_start(location) == false) { |
| 6875 | MG_ERROR(("%p is not on a sector boundary")); |
| 6876 | } else { |
| 6877 | uintptr_t diff = (char *) location - (char *) s_mg_flash_stm32h5.start; |
| 6878 | uint32_t sector = diff / s_mg_flash_stm32h5.secsz; |
| 6879 | uint32_t saved_cr = MG_REG(FLASH_NSCR); // Save CR value |
| 6880 | flash_unlock(); |
| 6881 | flash_clear_err(); |
| 6882 | MG_REG(FLASH_NSCR) = 0; |
| 6883 | if ((sector < 128 && flash_bank_is_swapped()) || |
| 6884 | (sector > 127 && !flash_bank_is_swapped())) { |
| 6885 | MG_REG(FLASH_NSCR) |= MG_BIT(31); // Set FLASH_CR_BKSEL |
| 6886 | } |
| 6887 | if (sector > 127) sector -= 128; |
| 6888 | MG_REG(FLASH_NSCR) |= MG_BIT(2) | (sector << 6); // Erase | sector_num |
| 6889 | MG_REG(FLASH_NSCR) |= MG_BIT(5); // Start erasing |
| 6890 | flash_wait(); |
| 6891 | ok = !flash_is_err(); |
| 6892 | MG_DEBUG(("Erase sector %lu @ %p: %s. CR %#lx SR %#lx", sector, location, |
| 6893 | ok ? "ok" : "fail", MG_REG(FLASH_NSCR), MG_REG(FLASH_NSSR))); |
| 6894 | // mg_hexdump(location, 32); |
| 6895 | MG_REG(FLASH_NSCR) = saved_cr; // Restore saved CR |
| 6896 | } |
| 6897 | return ok; |
| 6898 | } |
| 6899 | |
| 6900 | static bool mg_stm32h5_swap(void) { |
| 6901 | uint32_t desired = flash_bank_is_swapped() ? 0 : MG_BIT(31); |
| 6902 | flash_unlock(); |
| 6903 | flash_clear_err(); |
| 6904 | // printf("OPTSR_PRG 1 %#lx\n", FLASH->OPTSR_PRG); |
| 6905 | MG_SET_BITS(MG_REG(FLASH_OPTSR_PRG), MG_BIT(31), desired); |
| 6906 | // printf("OPTSR_PRG 2 %#lx\n", FLASH->OPTSR_PRG); |
| 6907 | MG_REG(FLASH_OPTCR) |= MG_BIT(1); // OPTSTART |
| 6908 | while ((MG_REG(FLASH_OPTSR_CUR) & MG_BIT(31)) != desired) (void) 0; |
| 6909 | return true; |
| 6910 | } |
| 6911 | |
| 6912 | static bool mg_stm32h5_write(void *addr, const void *buf, size_t len) { |
| 6913 | if ((len % s_mg_flash_stm32h5.align) != 0) { |
| 6914 | MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_stm32h5.align)); |
| 6915 | return false; |
| 6916 | } |
| 6917 | uint32_t *dst = (uint32_t *) addr; |
| 6918 | uint32_t *src = (uint32_t *) buf; |
| 6919 | uint32_t *end = (uint32_t *) ((char *) buf + len); |
| 6920 | bool ok = true; |
| 6921 | MG_ARM_DISABLE_IRQ(); |
| 6922 | flash_unlock(); |
| 6923 | flash_clear_err(); |
| 6924 | MG_REG(FLASH_NSCR) = MG_BIT(1); // Set programming flag |
| 6925 | while (ok && src < end) { |
| 6926 | if (flash_page_start(dst) && mg_stm32h5_erase(dst) == false) { |
| 6927 | ok = false; |
| 6928 | break; |
| 6929 | } |
| 6930 | *(volatile uint32_t *) dst++ = *src++; |
| 6931 | flash_wait(); |
| 6932 | if (flash_is_err()) ok = false; |
| 6933 | } |
| 6934 | MG_ARM_ENABLE_IRQ(); |
| 6935 | MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst, |
| 6936 | flash_is_err() ? "fail" : "ok", MG_REG(FLASH_NSCR), |
| 6937 | MG_REG(FLASH_NSSR))); |
| 6938 | MG_REG(FLASH_NSCR) = 0; // Clear flags |
| 6939 | return ok; |
| 6940 | } |
| 6941 | |
| 6942 | bool mg_ota_begin(size_t new_firmware_size) { |
| 6943 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32h5); |
| 6944 | } |
| 6945 | |
| 6946 | bool mg_ota_write(const void *buf, size_t len) { |
| 6947 | return mg_ota_flash_write(buf, len, &s_mg_flash_stm32h5); |
| 6948 | } |
| 6949 | |
| 6950 | // Actual bank swap is deferred until reset, it is safe to execute in flash |
| 6951 | bool mg_ota_end(void) { |
| 6952 | if(!mg_ota_flash_end(&s_mg_flash_stm32h5)) return false; |
| 6953 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 6954 | return true; |
| 6955 | } |
| 6956 | #endif |
| 6957 | |
| 6958 | #ifdef MG_ENABLE_LINES |
| 6959 | #line 1 "src/ota_stm32h7.c" |
| 6960 | #endif |
| 6961 | |
| 6962 | |
| 6963 | |
| 6964 | |
| 6965 | #if MG_OTA == MG_OTA_STM32H7 || MG_OTA == MG_OTA_STM32H7_DUAL_CORE |
| 6966 | |
| 6967 | // - H723/735 RM 4.3.3: Note: The application can simultaneously request a read |
| 6968 | // and a write operation through the AXI interface. |
| 6969 | // - We only need IRAM for partition swapping in the H723, however, all |
| 6970 | // related functions must reside in IRAM for this to be possible. |
| 6971 | // - Linker files for other devices won't define a .iram section so there's no |
| 6972 | // associated penalty |
| 6973 | |
| 6974 | static bool mg_stm32h7_write(void *, const void *, size_t); |
| 6975 | static bool mg_stm32h7_swap(void); |
| 6976 | |
| 6977 | static struct mg_flash s_mg_flash_stm32h7 = { |
| 6978 | (void *) 0x08000000, // Start |
| 6979 | 0, // Size, FLASH_SIZE_REG |
| 6980 | 128 * 1024, // Sector size, 128k |
| 6981 | 32, // Align, 256 bit |
| 6982 | mg_stm32h7_write, |
| 6983 | mg_stm32h7_swap, |
| 6984 | }; |
| 6985 | |
| 6986 | #define FLASH_BASE1 0x52002000 // Base address for bank1 |
| 6987 | #define FLASH_BASE2 0x52002100 // Base address for bank2 |
| 6988 | #define FLASH_KEYR 0x04 // See RM0433 4.9.2 |
| 6989 | #define FLASH_OPTKEYR 0x08 |
| 6990 | #define FLASH_OPTCR 0x18 |
| 6991 | #define FLASH_SR 0x10 |
| 6992 | #define FLASH_CR 0x0c |
| 6993 | #define FLASH_CCR 0x14 |
| 6994 | #define FLASH_OPTSR_CUR 0x1c |
| 6995 | #define FLASH_OPTSR_PRG 0x20 |
| 6996 | #define FLASH_SIZE_REG 0x1ff1e880 |
| 6997 | |
| 6998 | #define IS_DUALCORE() (MG_OTA == MG_OTA_STM32H7_DUAL_CORE) |
| 6999 | |
| 7000 | MG_IRAM static bool is_dualbank(void) { |
| 7001 | if (IS_DUALCORE()) { |
| 7002 | // H745/H755 and H747/H757 are running on dual core. |
| 7003 | // Using only the 1st bank (mapped to CM7), in order not to interfere |
| 7004 | // with the 2nd bank (CM4), possibly causing CM4 to boot unexpectedly. |
| 7005 | return false; |
| 7006 | } |
| 7007 | return (s_mg_flash_stm32h7.size < 2 * 1024 * 1024) ? false : true; |
| 7008 | } |
| 7009 | |
| 7010 | MG_IRAM static void flash_unlock(void) { |
| 7011 | static bool unlocked = false; |
| 7012 | if (unlocked == false) { |
| 7013 | MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0x45670123; |
| 7014 | MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0xcdef89ab; |
| 7015 | if (is_dualbank()) { |
| 7016 | MG_REG(FLASH_BASE2 + FLASH_KEYR) = 0x45670123; |
| 7017 | MG_REG(FLASH_BASE2 + FLASH_KEYR) = 0xcdef89ab; |
| 7018 | } |
| 7019 | MG_REG(FLASH_BASE1 + FLASH_OPTKEYR) = 0x08192a3b; // opt reg is "shared" |
| 7020 | MG_REG(FLASH_BASE1 + FLASH_OPTKEYR) = 0x4c5d6e7f; // thus unlock once |
| 7021 | unlocked = true; |
| 7022 | } |
| 7023 | } |
| 7024 | |
| 7025 | MG_IRAM static bool flash_page_start(volatile uint32_t *dst) { |
| 7026 | char *base = (char *) s_mg_flash_stm32h7.start, |
| 7027 | *end = base + s_mg_flash_stm32h7.size; |
| 7028 | volatile char *p = (char *) dst; |
| 7029 | return p >= base && p < end && ((p - base) % s_mg_flash_stm32h7.secsz) == 0; |
| 7030 | } |
| 7031 | |
| 7032 | MG_IRAM static bool flash_is_err(uint32_t bank) { |
| 7033 | return MG_REG(bank + FLASH_SR) & ((MG_BIT(11) - 1) << 17); // RM0433 4.9.5 |
| 7034 | } |
| 7035 | |
| 7036 | MG_IRAM static void flash_wait(uint32_t bank) { |
| 7037 | while (MG_REG(bank + FLASH_SR) & (MG_BIT(0) | MG_BIT(2))) (void) 0; |
| 7038 | } |
| 7039 | |
| 7040 | MG_IRAM static void flash_clear_err(uint32_t bank) { |
| 7041 | flash_wait(bank); // Wait until ready |
| 7042 | MG_REG(bank + FLASH_CCR) = ((MG_BIT(11) - 1) << 16U); // Clear all errors |
| 7043 | } |
| 7044 | |
| 7045 | MG_IRAM static bool flash_bank_is_swapped(uint32_t bank) { |
| 7046 | return MG_REG(bank + FLASH_OPTCR) & MG_BIT(31); // RM0433 4.9.7 |
| 7047 | } |
| 7048 | |
| 7049 | // Figure out flash bank based on the address |
| 7050 | MG_IRAM static uint32_t flash_bank(void *addr) { |
| 7051 | size_t ofs = (char *) addr - (char *) s_mg_flash_stm32h7.start; |
| 7052 | if (!is_dualbank()) return FLASH_BASE1; |
| 7053 | return ofs < s_mg_flash_stm32h7.size / 2 ? FLASH_BASE1 : FLASH_BASE2; |
| 7054 | } |
| 7055 | |
| 7056 | // read-while-write, no need to disable IRQs for standalone usage |
| 7057 | MG_IRAM static bool mg_stm32h7_erase(void *addr) { |
| 7058 | bool ok = false; |
| 7059 | if (flash_page_start(addr) == false) { |
| 7060 | MG_ERROR(("%p is not on a sector boundary", addr)); |
| 7061 | } else { |
| 7062 | uintptr_t diff = (char *) addr - (char *) s_mg_flash_stm32h7.start; |
| 7063 | uint32_t sector = diff / s_mg_flash_stm32h7.secsz; |
| 7064 | uint32_t bank = flash_bank(addr); |
| 7065 | uint32_t saved_cr = MG_REG(bank + FLASH_CR); // Save CR value |
| 7066 | |
| 7067 | flash_unlock(); |
| 7068 | if (sector > 7) sector -= 8; |
| 7069 | |
| 7070 | flash_clear_err(bank); |
| 7071 | MG_REG(bank + FLASH_CR) = MG_BIT(5); // 32-bit write parallelism |
| 7072 | MG_REG(bank + FLASH_CR) |= (sector & 7U) << 8U; // Sector to erase |
| 7073 | MG_REG(bank + FLASH_CR) |= MG_BIT(2); // Sector erase bit |
| 7074 | MG_REG(bank + FLASH_CR) |= MG_BIT(7); // Start erasing |
| 7075 | ok = !flash_is_err(bank); |
| 7076 | MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr, |
| 7077 | ok ? "ok" : "fail", MG_REG(bank + FLASH_CR), |
| 7078 | MG_REG(bank + FLASH_SR))); |
| 7079 | MG_REG(bank + FLASH_CR) = saved_cr; // Restore CR |
| 7080 | } |
| 7081 | return ok; |
| 7082 | } |
| 7083 | |
| 7084 | MG_IRAM static bool mg_stm32h7_swap(void) { |
| 7085 | if (!is_dualbank()) return true; |
| 7086 | uint32_t bank = FLASH_BASE1; |
| 7087 | uint32_t desired = flash_bank_is_swapped(bank) ? 0 : MG_BIT(31); |
| 7088 | flash_unlock(); |
| 7089 | flash_clear_err(bank); |
| 7090 | // printf("OPTSR_PRG 1 %#lx\n", FLASH->OPTSR_PRG); |
| 7091 | MG_SET_BITS(MG_REG(bank + FLASH_OPTSR_PRG), MG_BIT(31), desired); |
| 7092 | // printf("OPTSR_PRG 2 %#lx\n", FLASH->OPTSR_PRG); |
| 7093 | MG_REG(bank + FLASH_OPTCR) |= MG_BIT(1); // OPTSTART |
| 7094 | while ((MG_REG(bank + FLASH_OPTSR_CUR) & MG_BIT(31)) != desired) (void) 0; |
| 7095 | return true; |
| 7096 | } |
| 7097 | |
| 7098 | static bool s_flash_irq_disabled; |
| 7099 | |
| 7100 | MG_IRAM static bool mg_stm32h7_write(void *addr, const void *buf, size_t len) { |
| 7101 | if ((len % s_mg_flash_stm32h7.align) != 0) { |
| 7102 | MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_stm32h7.align)); |
| 7103 | return false; |
| 7104 | } |
| 7105 | uint32_t bank = flash_bank(addr); |
| 7106 | uint32_t *dst = (uint32_t *) addr; |
| 7107 | uint32_t *src = (uint32_t *) buf; |
| 7108 | uint32_t *end = (uint32_t *) ((char *) buf + len); |
| 7109 | bool ok = true; |
| 7110 | MG_ARM_DISABLE_IRQ(); |
| 7111 | flash_unlock(); |
| 7112 | flash_clear_err(bank); |
| 7113 | MG_REG(bank + FLASH_CR) = MG_BIT(1); // Set programming flag |
| 7114 | MG_REG(bank + FLASH_CR) |= MG_BIT(5); // 32-bit write parallelism |
| 7115 | while (ok && src < end) { |
| 7116 | if (flash_page_start(dst) && mg_stm32h7_erase(dst) == false) { |
| 7117 | ok = false; |
| 7118 | break; |
| 7119 | } |
| 7120 | *(volatile uint32_t *) dst++ = *src++; |
| 7121 | flash_wait(bank); |
| 7122 | if (flash_is_err(bank)) ok = false; |
| 7123 | } |
| 7124 | if (!s_flash_irq_disabled) MG_ARM_ENABLE_IRQ(); |
| 7125 | MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst, |
| 7126 | ok ? "ok" : "fail", MG_REG(bank + FLASH_CR), |
| 7127 | MG_REG(bank + FLASH_SR))); |
| 7128 | MG_REG(bank + FLASH_CR) &= ~MG_BIT(1); // Clear programming flag |
| 7129 | return ok; |
| 7130 | } |
| 7131 | |
| 7132 | // just overwrite instead of swap |
| 7133 | MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { |
| 7134 | // no stdlib calls here |
| 7135 | for (size_t ofs = 0; ofs < s; ofs += ss) { |
| 7136 | mg_stm32h7_write(p1 + ofs, p2 + ofs, ss); |
| 7137 | } |
| 7138 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 7139 | } |
| 7140 | |
| 7141 | bool mg_ota_begin(size_t new_firmware_size) { |
| 7142 | s_mg_flash_stm32h7.size = MG_REG(FLASH_SIZE_REG) * 1024; |
| 7143 | if (IS_DUALCORE()) { |
| 7144 | // Using only the 1st bank (mapped to CM7) |
| 7145 | s_mg_flash_stm32h7.size /= 2; |
| 7146 | } |
| 7147 | return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32h7); |
| 7148 | } |
| 7149 | |
| 7150 | bool mg_ota_write(const void *buf, size_t len) { |
| 7151 | return mg_ota_flash_write(buf, len, &s_mg_flash_stm32h7); |
| 7152 | } |
| 7153 | |
| 7154 | bool mg_ota_end(void) { |
| 7155 | if (mg_ota_flash_end(&s_mg_flash_stm32h7)) { |
| 7156 | if (is_dualbank()) { |
| 7157 | // Bank swap is deferred until reset, been executing in flash, reset |
| 7158 | *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; |
| 7159 | } else { |
| 7160 | // Swap partitions. Pray power does not go away |
| 7161 | MG_INFO(("Swapping partitions, size %u (%u sectors)", |
| 7162 | s_mg_flash_stm32h7.size, |
| 7163 | s_mg_flash_stm32h7.size / s_mg_flash_stm32h7.secsz)); |
| 7164 | MG_INFO(("Do NOT power off...")); |
| 7165 | mg_log_level = MG_LL_NONE; |
| 7166 | s_flash_irq_disabled = true; |
| 7167 | // Runs in RAM, will reset when finished |
| 7168 | single_bank_swap( |
| 7169 | (char *) s_mg_flash_stm32h7.start, |
| 7170 | (char *) s_mg_flash_stm32h7.start + s_mg_flash_stm32h7.size / 2, |
| 7171 | s_mg_flash_stm32h7.size / 2, s_mg_flash_stm32h7.secsz); |
| 7172 | } |
| 7173 | } |
| 7174 | return false; |
| 7175 | } |
| 7176 | #endif |
| 7177 | |
| 7178 | #ifdef MG_ENABLE_LINES |
| 7179 | #line 1 "src/printf.c" |
| 7180 | #endif |
| 7181 | |
| 7182 | |
| 7183 | |
| 7184 | |
| 7185 | size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) { |
| 7186 | size_t len = mg_snprintf(NULL, 0, fmt, ap); |
| 7187 | char *buf; |
| 7188 | if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) { |
| 7189 | len = 0; // Nah. Not enough space |
| 7190 | } else { |
| 7191 | len = mg_vsnprintf((char *) buf, len + 1, fmt, ap); |
| 7192 | mg_queue_add(q, len); |
| 7193 | } |
| 7194 | return len; |
| 7195 | } |
| 7196 | |
| 7197 | size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) { |
| 7198 | va_list ap; |
| 7199 | size_t len; |
| 7200 | va_start(ap, fmt); |
| 7201 | len = mg_queue_vprintf(q, fmt, &ap); |
| 7202 | va_end(ap); |
| 7203 | return len; |
| 7204 | } |
| 7205 | |
| 7206 | static void mg_pfn_iobuf_private(char ch, void *param, bool expand) { |
| 7207 | struct mg_iobuf *io = (struct mg_iobuf *) param; |
| 7208 | if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2); |
| 7209 | if (io->len + 2 <= io->size) { |
| 7210 | io->buf[io->len++] = (uint8_t) ch; |
| 7211 | io->buf[io->len] = 0; |
| 7212 | } else if (io->len < io->size) { |
| 7213 | io->buf[io->len++] = 0; // Guarantee to 0-terminate |
| 7214 | } |
| 7215 | } |
| 7216 | |
| 7217 | static void mg_putchar_iobuf_static(char ch, void *param) { |
| 7218 | mg_pfn_iobuf_private(ch, param, false); |
| 7219 | } |
| 7220 | |
| 7221 | void mg_pfn_iobuf(char ch, void *param) { |
| 7222 | mg_pfn_iobuf_private(ch, param, true); |
| 7223 | } |
| 7224 | |
| 7225 | size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) { |
| 7226 | struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0}; |
| 7227 | size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap); |
| 7228 | if (n < len) buf[n] = '\0'; |
| 7229 | return n; |
| 7230 | } |
| 7231 | |
| 7232 | size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { |
| 7233 | va_list ap; |
| 7234 | size_t n; |
| 7235 | va_start(ap, fmt); |
| 7236 | n = mg_vsnprintf(buf, len, fmt, &ap); |
| 7237 | va_end(ap); |
| 7238 | return n; |
| 7239 | } |
| 7240 | |
| 7241 | char *mg_vmprintf(const char *fmt, va_list *ap) { |
| 7242 | struct mg_iobuf io = {0, 0, 0, 256}; |
| 7243 | mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap); |
| 7244 | return (char *) io.buf; |
| 7245 | } |
| 7246 | |
| 7247 | char *mg_mprintf(const char *fmt, ...) { |
| 7248 | char *s; |
| 7249 | va_list ap; |
| 7250 | va_start(ap, fmt); |
| 7251 | s = mg_vmprintf(fmt, &ap); |
| 7252 | va_end(ap); |
| 7253 | return s; |
| 7254 | } |
| 7255 | |
| 7256 | void mg_pfn_stdout(char c, void *param) { |
| 7257 | putchar(c); |
| 7258 | (void) param; |
| 7259 | } |
| 7260 | |
| 7261 | static size_t print_ip4(void (*out)(char, void *), void *arg, uint8_t *p) { |
| 7262 | return mg_xprintf(out, arg, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); |
| 7263 | } |
| 7264 | |
| 7265 | static size_t print_ip6(void (*out)(char, void *), void *arg, uint16_t *p) { |
| 7266 | return mg_xprintf(out, arg, "[%x:%x:%x:%x:%x:%x:%x:%x]", mg_ntohs(p[0]), |
| 7267 | mg_ntohs(p[1]), mg_ntohs(p[2]), mg_ntohs(p[3]), |
| 7268 | mg_ntohs(p[4]), mg_ntohs(p[5]), mg_ntohs(p[6]), |
| 7269 | mg_ntohs(p[7])); |
| 7270 | } |
| 7271 | |
| 7272 | size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7273 | uint8_t *p = va_arg(*ap, uint8_t *); |
| 7274 | return print_ip4(out, arg, p); |
| 7275 | } |
| 7276 | |
| 7277 | size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7278 | uint16_t *p = va_arg(*ap, uint16_t *); |
| 7279 | return print_ip6(out, arg, p); |
| 7280 | } |
| 7281 | |
| 7282 | size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7283 | struct mg_addr *addr = va_arg(*ap, struct mg_addr *); |
| 7284 | if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip); |
| 7285 | return print_ip4(out, arg, (uint8_t *) &addr->ip); |
| 7286 | } |
| 7287 | |
| 7288 | size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7289 | struct mg_addr *a = va_arg(*ap, struct mg_addr *); |
| 7290 | return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port)); |
| 7291 | } |
| 7292 | |
| 7293 | size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7294 | uint8_t *p = va_arg(*ap, uint8_t *); |
| 7295 | return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2], |
| 7296 | p[3], p[4], p[5]); |
| 7297 | } |
| 7298 | |
| 7299 | static char mg_esc(int c, bool esc) { |
| 7300 | const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\""; |
| 7301 | for (p = esc ? esc1 : esc2; *p != '\0'; p++) { |
| 7302 | if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2]; |
| 7303 | } |
| 7304 | return 0; |
| 7305 | } |
| 7306 | |
| 7307 | static char mg_escape(int c) { |
| 7308 | return mg_esc(c, true); |
| 7309 | } |
| 7310 | |
| 7311 | static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf, |
| 7312 | size_t len) { |
| 7313 | size_t i = 0, extra = 0; |
| 7314 | for (i = 0; i < len && buf[i] != '\0'; i++) { |
| 7315 | char c = mg_escape(buf[i]); |
| 7316 | if (c) { |
| 7317 | out('\\', ptr), out(c, ptr), extra++; |
| 7318 | } else { |
| 7319 | out(buf[i], ptr); |
| 7320 | } |
| 7321 | } |
| 7322 | return i + extra; |
| 7323 | } |
| 7324 | |
| 7325 | static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf, |
| 7326 | size_t len) { |
| 7327 | size_t i, j, n = 0; |
| 7328 | const char *t = |
| 7329 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 7330 | for (i = 0; i < len; i += 3) { |
| 7331 | uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0, |
| 7332 | c3 = i + 2 < len ? buf[i + 2] : 0; |
| 7333 | char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='}; |
| 7334 | if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)]; |
| 7335 | if (i + 2 < len) tmp[3] = t[c3 & 63]; |
| 7336 | for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg); |
| 7337 | n += j; |
| 7338 | } |
| 7339 | return n; |
| 7340 | } |
| 7341 | |
| 7342 | size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7343 | size_t bl = (size_t) va_arg(*ap, int); |
| 7344 | uint8_t *p = va_arg(*ap, uint8_t *); |
| 7345 | const char *hex = "0123456789abcdef"; |
| 7346 | size_t j; |
| 7347 | for (j = 0; j < bl; j++) { |
| 7348 | out(hex[(p[j] >> 4) & 0x0F], arg); |
| 7349 | out(hex[p[j] & 0x0F], arg); |
| 7350 | } |
| 7351 | return 2 * bl; |
| 7352 | } |
| 7353 | size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7354 | size_t len = (size_t) va_arg(*ap, int); |
| 7355 | uint8_t *buf = va_arg(*ap, uint8_t *); |
| 7356 | return bcpy(out, arg, buf, len); |
| 7357 | } |
| 7358 | |
| 7359 | size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) { |
| 7360 | size_t len = (size_t) va_arg(*ap, int); |
| 7361 | char *p = va_arg(*ap, char *); |
| 7362 | if (len == 0) len = p == NULL ? 0 : strlen(p); |
| 7363 | return qcpy(out, arg, p, len); |
| 7364 | } |
| 7365 | |
| 7366 | #ifdef MG_ENABLE_LINES |
| 7367 | #line 1 "src/queue.c" |
| 7368 | #endif |
| 7369 | |
| 7370 | |
| 7371 | |
| 7372 | #if (defined(__GNUC__) && (__GNUC__ > 4) || \ |
| 7373 | (defined(__GNUC_MINOR__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ |
| 7374 | defined(__clang__) |
| 7375 | #define MG_MEMORY_BARRIER() __sync_synchronize() |
| 7376 | #elif defined(_MSC_VER) && _MSC_VER >= 1700 |
| 7377 | #define MG_MEMORY_BARRIER() MemoryBarrier() |
| 7378 | #elif !defined(MG_MEMORY_BARRIER) |
| 7379 | #define MG_MEMORY_BARRIER() |
| 7380 | #endif |
| 7381 | |
| 7382 | // Every message in a queue is prepended by a 32-bit message length (ML). |
| 7383 | // If ML is 0, then it is the end, and reader must wrap to the beginning. |
| 7384 | // |
| 7385 | // Queue when q->tail <= q->head: |
| 7386 | // |----- free -----| ML | message1 | ML | message2 | ----- free ------| |
| 7387 | // ^ ^ ^ ^ |
| 7388 | // buf tail head len |
| 7389 | // |
| 7390 | // Queue when q->tail > q->head: |
| 7391 | // | ML | message2 |----- free ------| ML | message1 | 0 |---- free ----| |
| 7392 | // ^ ^ ^ ^ |
| 7393 | // buf head tail len |
| 7394 | |
| 7395 | void mg_queue_init(struct mg_queue *q, char *buf, size_t size) { |
| 7396 | q->size = size; |
| 7397 | q->buf = buf; |
| 7398 | q->head = q->tail = 0; |
| 7399 | } |
| 7400 | |
| 7401 | static size_t mg_queue_read_len(struct mg_queue *q) { |
| 7402 | uint32_t n = 0; |
| 7403 | MG_MEMORY_BARRIER(); |
| 7404 | memcpy(&n, q->buf + q->tail, sizeof(n)); |
| 7405 | assert(q->tail + n + sizeof(n) <= q->size); |
| 7406 | return n; |
| 7407 | } |
| 7408 | |
| 7409 | static void mg_queue_write_len(struct mg_queue *q, size_t len) { |
| 7410 | uint32_t n = (uint32_t) len; |
| 7411 | memcpy(q->buf + q->head, &n, sizeof(n)); |
| 7412 | MG_MEMORY_BARRIER(); |
| 7413 | } |
| 7414 | |
| 7415 | size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len) { |
| 7416 | size_t space = 0, hs = sizeof(uint32_t) * 2; // *2 is for the 0 marker |
| 7417 | if (q->head >= q->tail && q->head + len + hs <= q->size) { |
| 7418 | space = q->size - q->head - hs; // There is enough space |
| 7419 | } else if (q->head >= q->tail && q->tail > hs) { |
| 7420 | mg_queue_write_len(q, 0); // Not enough space ahead |
| 7421 | q->head = 0; // Wrap head to the beginning |
| 7422 | } |
| 7423 | if (q->head + hs + len < q->tail) space = q->tail - q->head - hs; |
| 7424 | if (buf != NULL) *buf = q->buf + q->head + sizeof(uint32_t); |
| 7425 | return space; |
| 7426 | } |
| 7427 | |
| 7428 | size_t mg_queue_next(struct mg_queue *q, char **buf) { |
| 7429 | size_t len = 0; |
| 7430 | if (q->tail != q->head) { |
| 7431 | len = mg_queue_read_len(q); |
| 7432 | if (len == 0) { // Zero (head wrapped) ? |
| 7433 | q->tail = 0; // Reset tail to the start |
| 7434 | if (q->head > q->tail) len = mg_queue_read_len(q); // Read again |
| 7435 | } |
| 7436 | } |
| 7437 | if (buf != NULL) *buf = q->buf + q->tail + sizeof(uint32_t); |
| 7438 | assert(q->tail + len <= q->size); |
| 7439 | return len; |
| 7440 | } |
| 7441 | |
| 7442 | void mg_queue_add(struct mg_queue *q, size_t len) { |
| 7443 | assert(len > 0); |
| 7444 | mg_queue_write_len(q, len); |
| 7445 | assert(q->head + sizeof(uint32_t) * 2 + len <= q->size); |
| 7446 | q->head += len + sizeof(uint32_t); |
| 7447 | } |
| 7448 | |
| 7449 | void mg_queue_del(struct mg_queue *q, size_t len) { |
| 7450 | q->tail += len + sizeof(uint32_t); |
| 7451 | assert(q->tail + sizeof(uint32_t) <= q->size); |
| 7452 | } |
| 7453 | |
| 7454 | #ifdef MG_ENABLE_LINES |
| 7455 | #line 1 "src/rpc.c" |
| 7456 | #endif |
| 7457 | |
| 7458 | |
| 7459 | |
| 7460 | void mg_rpc_add(struct mg_rpc **head, struct mg_str method, |
| 7461 | void (*fn)(struct mg_rpc_req *), void *fn_data) { |
| 7462 | struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc)); |
| 7463 | if (rpc != NULL) { |
| 7464 | rpc->method = mg_strdup(method); |
| 7465 | rpc->fn = fn; |
| 7466 | rpc->fn_data = fn_data; |
| 7467 | rpc->next = *head, *head = rpc; |
| 7468 | } |
| 7469 | } |
| 7470 | |
| 7471 | void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) { |
| 7472 | struct mg_rpc *r; |
| 7473 | while ((r = *head) != NULL) { |
| 7474 | if (r->fn == fn || fn == NULL) { |
| 7475 | *head = r->next; |
| 7476 | free((void *) r->method.buf); |
| 7477 | free(r); |
| 7478 | } else { |
| 7479 | head = &(*head)->next; |
| 7480 | } |
| 7481 | } |
| 7482 | } |
| 7483 | |
| 7484 | static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) { |
| 7485 | struct mg_rpc *h = r->head == NULL ? NULL : *r->head; |
| 7486 | while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next; |
| 7487 | if (h != NULL) { |
| 7488 | r->rpc = h; |
| 7489 | h->fn(r); |
| 7490 | } else { |
| 7491 | mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.buf); |
| 7492 | } |
| 7493 | } |
| 7494 | |
| 7495 | void mg_rpc_process(struct mg_rpc_req *r) { |
| 7496 | int len, off = mg_json_get(r->frame, "$.method", &len); |
| 7497 | if (off > 0 && r->frame.buf[off] == '"') { |
| 7498 | struct mg_str method = mg_str_n(&r->frame.buf[off + 1], (size_t) len - 2); |
| 7499 | mg_rpc_call(r, method); |
| 7500 | } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 || |
| 7501 | (off = mg_json_get(r->frame, "$.error", &len)) > 0) { |
| 7502 | mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler |
| 7503 | } else { |
| 7504 | mg_rpc_err(r, -32700, "%m", mg_print_esc, (int) r->frame.len, |
| 7505 | r->frame.buf); // Invalid |
| 7506 | } |
| 7507 | } |
| 7508 | |
| 7509 | void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) { |
| 7510 | int len, off = mg_json_get(r->frame, "$.id", &len); |
| 7511 | if (off > 0) { |
| 7512 | mg_xprintf(r->pfn, r->pfn_data, "{%m:%.*s,%m:", mg_print_esc, 0, "id", len, |
| 7513 | &r->frame.buf[off], mg_print_esc, 0, "result"); |
| 7514 | mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap); |
| 7515 | mg_xprintf(r->pfn, r->pfn_data, "}"); |
| 7516 | } |
| 7517 | } |
| 7518 | |
| 7519 | void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) { |
| 7520 | va_list ap; |
| 7521 | va_start(ap, fmt); |
| 7522 | mg_rpc_vok(r, fmt, &ap); |
| 7523 | va_end(ap); |
| 7524 | } |
| 7525 | |
| 7526 | void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) { |
| 7527 | int len, off = mg_json_get(r->frame, "$.id", &len); |
| 7528 | mg_xprintf(r->pfn, r->pfn_data, "{"); |
| 7529 | if (off > 0) { |
| 7530 | mg_xprintf(r->pfn, r->pfn_data, "%m:%.*s,", mg_print_esc, 0, "id", len, |
| 7531 | &r->frame.buf[off]); |
| 7532 | } |
| 7533 | mg_xprintf(r->pfn, r->pfn_data, "%m:{%m:%d,%m:", mg_print_esc, 0, "error", |
| 7534 | mg_print_esc, 0, "code", code, mg_print_esc, 0, "message"); |
| 7535 | mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap); |
| 7536 | mg_xprintf(r->pfn, r->pfn_data, "}}"); |
| 7537 | } |
| 7538 | |
| 7539 | void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) { |
| 7540 | va_list ap; |
| 7541 | va_start(ap, fmt); |
| 7542 | mg_rpc_verr(r, code, fmt, &ap); |
| 7543 | va_end(ap); |
| 7544 | } |
| 7545 | |
| 7546 | static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) { |
| 7547 | struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **); |
| 7548 | size_t len = 0; |
| 7549 | for (h = *head; h != NULL; h = h->next) { |
| 7550 | if (h->method.len == 0) continue; // Ignore response handler |
| 7551 | len += mg_xprintf(pfn, pfn_data, "%s%m", h == *head ? "" : ",", |
| 7552 | mg_print_esc, (int) h->method.len, h->method.buf); |
| 7553 | } |
| 7554 | return len; |
| 7555 | } |
| 7556 | |
| 7557 | void mg_rpc_list(struct mg_rpc_req *r) { |
| 7558 | mg_rpc_ok(r, "[%M]", print_methods, r->head); |
| 7559 | } |
| 7560 | |
| 7561 | #ifdef MG_ENABLE_LINES |
| 7562 | #line 1 "src/sha1.c" |
| 7563 | #endif |
| 7564 | /* Copyright(c) By Steve Reid <steve@edmweb.com> */ |
| 7565 | /* 100% Public Domain */ |
| 7566 | |
| 7567 | |
| 7568 | |
| 7569 | union char64long16 { |
| 7570 | unsigned char c[64]; |
| 7571 | uint32_t l[16]; |
| 7572 | }; |
| 7573 | |
| 7574 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) |
| 7575 | |
| 7576 | static uint32_t blk0(union char64long16 *block, int i) { |
| 7577 | if (MG_BIG_ENDIAN) { |
| 7578 | } else { |
| 7579 | block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | |
| 7580 | (rol(block->l[i], 8) & 0x00FF00FF); |
| 7581 | } |
| 7582 | return block->l[i]; |
| 7583 | } |
| 7584 | |
| 7585 | /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ |
| 7586 | #undef blk |
| 7587 | #undef R0 |
| 7588 | #undef R1 |
| 7589 | #undef R2 |
| 7590 | #undef R3 |
| 7591 | #undef R4 |
| 7592 | |
| 7593 | #define blk(i) \ |
| 7594 | (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ |
| 7595 | block->l[(i + 2) & 15] ^ block->l[i & 15], \ |
| 7596 | 1)) |
| 7597 | #define R0(v, w, x, y, z, i) \ |
| 7598 | z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ |
| 7599 | w = rol(w, 30); |
| 7600 | #define R1(v, w, x, y, z, i) \ |
| 7601 | z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ |
| 7602 | w = rol(w, 30); |
| 7603 | #define R2(v, w, x, y, z, i) \ |
| 7604 | z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ |
| 7605 | w = rol(w, 30); |
| 7606 | #define R3(v, w, x, y, z, i) \ |
| 7607 | z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ |
| 7608 | w = rol(w, 30); |
| 7609 | #define R4(v, w, x, y, z, i) \ |
| 7610 | z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ |
| 7611 | w = rol(w, 30); |
| 7612 | |
| 7613 | static void mg_sha1_transform(uint32_t state[5], |
| 7614 | const unsigned char *buffer) { |
| 7615 | uint32_t a, b, c, d, e; |
| 7616 | union char64long16 block[1]; |
| 7617 | |
| 7618 | memcpy(block, buffer, 64); |
| 7619 | a = state[0]; |
| 7620 | b = state[1]; |
| 7621 | c = state[2]; |
| 7622 | d = state[3]; |
| 7623 | e = state[4]; |
| 7624 | R0(a, b, c, d, e, 0); |
| 7625 | R0(e, a, b, c, d, 1); |
| 7626 | R0(d, e, a, b, c, 2); |
| 7627 | R0(c, d, e, a, b, 3); |
| 7628 | R0(b, c, d, e, a, 4); |
| 7629 | R0(a, b, c, d, e, 5); |
| 7630 | R0(e, a, b, c, d, 6); |
| 7631 | R0(d, e, a, b, c, 7); |
| 7632 | R0(c, d, e, a, b, 8); |
| 7633 | R0(b, c, d, e, a, 9); |
| 7634 | R0(a, b, c, d, e, 10); |
| 7635 | R0(e, a, b, c, d, 11); |
| 7636 | R0(d, e, a, b, c, 12); |
| 7637 | R0(c, d, e, a, b, 13); |
| 7638 | R0(b, c, d, e, a, 14); |
| 7639 | R0(a, b, c, d, e, 15); |
| 7640 | R1(e, a, b, c, d, 16); |
| 7641 | R1(d, e, a, b, c, 17); |
| 7642 | R1(c, d, e, a, b, 18); |
| 7643 | R1(b, c, d, e, a, 19); |
| 7644 | R2(a, b, c, d, e, 20); |
| 7645 | R2(e, a, b, c, d, 21); |
| 7646 | R2(d, e, a, b, c, 22); |
| 7647 | R2(c, d, e, a, b, 23); |
| 7648 | R2(b, c, d, e, a, 24); |
| 7649 | R2(a, b, c, d, e, 25); |
| 7650 | R2(e, a, b, c, d, 26); |
| 7651 | R2(d, e, a, b, c, 27); |
| 7652 | R2(c, d, e, a, b, 28); |
| 7653 | R2(b, c, d, e, a, 29); |
| 7654 | R2(a, b, c, d, e, 30); |
| 7655 | R2(e, a, b, c, d, 31); |
| 7656 | R2(d, e, a, b, c, 32); |
| 7657 | R2(c, d, e, a, b, 33); |
| 7658 | R2(b, c, d, e, a, 34); |
| 7659 | R2(a, b, c, d, e, 35); |
| 7660 | R2(e, a, b, c, d, 36); |
| 7661 | R2(d, e, a, b, c, 37); |
| 7662 | R2(c, d, e, a, b, 38); |
| 7663 | R2(b, c, d, e, a, 39); |
| 7664 | R3(a, b, c, d, e, 40); |
| 7665 | R3(e, a, b, c, d, 41); |
| 7666 | R3(d, e, a, b, c, 42); |
| 7667 | R3(c, d, e, a, b, 43); |
| 7668 | R3(b, c, d, e, a, 44); |
| 7669 | R3(a, b, c, d, e, 45); |
| 7670 | R3(e, a, b, c, d, 46); |
| 7671 | R3(d, e, a, b, c, 47); |
| 7672 | R3(c, d, e, a, b, 48); |
| 7673 | R3(b, c, d, e, a, 49); |
| 7674 | R3(a, b, c, d, e, 50); |
| 7675 | R3(e, a, b, c, d, 51); |
| 7676 | R3(d, e, a, b, c, 52); |
| 7677 | R3(c, d, e, a, b, 53); |
| 7678 | R3(b, c, d, e, a, 54); |
| 7679 | R3(a, b, c, d, e, 55); |
| 7680 | R3(e, a, b, c, d, 56); |
| 7681 | R3(d, e, a, b, c, 57); |
| 7682 | R3(c, d, e, a, b, 58); |
| 7683 | R3(b, c, d, e, a, 59); |
| 7684 | R4(a, b, c, d, e, 60); |
| 7685 | R4(e, a, b, c, d, 61); |
| 7686 | R4(d, e, a, b, c, 62); |
| 7687 | R4(c, d, e, a, b, 63); |
| 7688 | R4(b, c, d, e, a, 64); |
| 7689 | R4(a, b, c, d, e, 65); |
| 7690 | R4(e, a, b, c, d, 66); |
| 7691 | R4(d, e, a, b, c, 67); |
| 7692 | R4(c, d, e, a, b, 68); |
| 7693 | R4(b, c, d, e, a, 69); |
| 7694 | R4(a, b, c, d, e, 70); |
| 7695 | R4(e, a, b, c, d, 71); |
| 7696 | R4(d, e, a, b, c, 72); |
| 7697 | R4(c, d, e, a, b, 73); |
| 7698 | R4(b, c, d, e, a, 74); |
| 7699 | R4(a, b, c, d, e, 75); |
| 7700 | R4(e, a, b, c, d, 76); |
| 7701 | R4(d, e, a, b, c, 77); |
| 7702 | R4(c, d, e, a, b, 78); |
| 7703 | R4(b, c, d, e, a, 79); |
| 7704 | state[0] += a; |
| 7705 | state[1] += b; |
| 7706 | state[2] += c; |
| 7707 | state[3] += d; |
| 7708 | state[4] += e; |
| 7709 | /* Erase working structures. The order of operations is important, |
| 7710 | * used to ensure that compiler doesn't optimize those out. */ |
| 7711 | memset(block, 0, sizeof(block)); |
| 7712 | a = b = c = d = e = 0; |
| 7713 | (void) a; |
| 7714 | (void) b; |
| 7715 | (void) c; |
| 7716 | (void) d; |
| 7717 | (void) e; |
| 7718 | } |
| 7719 | |
| 7720 | void mg_sha1_init(mg_sha1_ctx *context) { |
| 7721 | context->state[0] = 0x67452301; |
| 7722 | context->state[1] = 0xEFCDAB89; |
| 7723 | context->state[2] = 0x98BADCFE; |
| 7724 | context->state[3] = 0x10325476; |
| 7725 | context->state[4] = 0xC3D2E1F0; |
| 7726 | context->count[0] = context->count[1] = 0; |
| 7727 | } |
| 7728 | |
| 7729 | void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data, |
| 7730 | size_t len) { |
| 7731 | size_t i, j; |
| 7732 | |
| 7733 | j = context->count[0]; |
| 7734 | if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++; |
| 7735 | context->count[1] += (uint32_t) (len >> 29); |
| 7736 | j = (j >> 3) & 63; |
| 7737 | if ((j + len) > 63) { |
| 7738 | memcpy(&context->buffer[j], data, (i = 64 - j)); |
| 7739 | mg_sha1_transform(context->state, context->buffer); |
| 7740 | for (; i + 63 < len; i += 64) { |
| 7741 | mg_sha1_transform(context->state, &data[i]); |
| 7742 | } |
| 7743 | j = 0; |
| 7744 | } else |
| 7745 | i = 0; |
| 7746 | memcpy(&context->buffer[j], &data[i], len - i); |
| 7747 | } |
| 7748 | |
| 7749 | void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) { |
| 7750 | unsigned i; |
| 7751 | unsigned char finalcount[8], c; |
| 7752 | |
| 7753 | for (i = 0; i < 8; i++) { |
| 7754 | finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> |
| 7755 | ((3 - (i & 3)) * 8)) & |
| 7756 | 255); |
| 7757 | } |
| 7758 | c = 0200; |
| 7759 | mg_sha1_update(context, &c, 1); |
| 7760 | while ((context->count[0] & 504) != 448) { |
| 7761 | c = 0000; |
| 7762 | mg_sha1_update(context, &c, 1); |
| 7763 | } |
| 7764 | mg_sha1_update(context, finalcount, 8); |
| 7765 | for (i = 0; i < 20; i++) { |
| 7766 | digest[i] = |
| 7767 | (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); |
| 7768 | } |
| 7769 | memset(context, '\0', sizeof(*context)); |
| 7770 | memset(&finalcount, '\0', sizeof(finalcount)); |
| 7771 | } |
| 7772 | |
| 7773 | #ifdef MG_ENABLE_LINES |
| 7774 | #line 1 "src/sha256.c" |
| 7775 | #endif |
| 7776 | // https://github.com/B-Con/crypto-algorithms |
| 7777 | // Author: Brad Conte (brad AT bradconte.com) |
| 7778 | // Disclaimer: This code is presented "as is" without any guarantees. |
| 7779 | // Details: Defines the API for the corresponding SHA1 implementation. |
| 7780 | // Copyright: public domain |
| 7781 | |
| 7782 | |
| 7783 | |
| 7784 | #define ror(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) |
| 7785 | #define ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) |
| 7786 | #define maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) |
| 7787 | #define ep0(x) (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)) |
| 7788 | #define ep1(x) (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)) |
| 7789 | #define sig0(x) (ror(x, 7) ^ ror(x, 18) ^ ((x) >> 3)) |
| 7790 | #define sig1(x) (ror(x, 17) ^ ror(x, 19) ^ ((x) >> 10)) |
| 7791 | |
| 7792 | static const uint32_t mg_sha256_k[64] = { |
| 7793 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, |
| 7794 | 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, |
| 7795 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, |
| 7796 | 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, |
| 7797 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, |
| 7798 | 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, |
| 7799 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, |
| 7800 | 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, |
| 7801 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, |
| 7802 | 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, |
| 7803 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; |
| 7804 | |
| 7805 | void mg_sha256_init(mg_sha256_ctx *ctx) { |
| 7806 | ctx->len = 0; |
| 7807 | ctx->bits = 0; |
| 7808 | ctx->state[0] = 0x6a09e667; |
| 7809 | ctx->state[1] = 0xbb67ae85; |
| 7810 | ctx->state[2] = 0x3c6ef372; |
| 7811 | ctx->state[3] = 0xa54ff53a; |
| 7812 | ctx->state[4] = 0x510e527f; |
| 7813 | ctx->state[5] = 0x9b05688c; |
| 7814 | ctx->state[6] = 0x1f83d9ab; |
| 7815 | ctx->state[7] = 0x5be0cd19; |
| 7816 | } |
| 7817 | |
| 7818 | static void mg_sha256_chunk(mg_sha256_ctx *ctx) { |
| 7819 | int i, j; |
| 7820 | uint32_t a, b, c, d, e, f, g, h; |
| 7821 | uint32_t m[64]; |
| 7822 | for (i = 0, j = 0; i < 16; ++i, j += 4) |
| 7823 | m[i] = (uint32_t) (((uint32_t) ctx->buffer[j] << 24) | |
| 7824 | ((uint32_t) ctx->buffer[j + 1] << 16) | |
| 7825 | ((uint32_t) ctx->buffer[j + 2] << 8) | |
| 7826 | ((uint32_t) ctx->buffer[j + 3])); |
| 7827 | for (; i < 64; ++i) |
| 7828 | m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16]; |
| 7829 | |
| 7830 | a = ctx->state[0]; |
| 7831 | b = ctx->state[1]; |
| 7832 | c = ctx->state[2]; |
| 7833 | d = ctx->state[3]; |
| 7834 | e = ctx->state[4]; |
| 7835 | f = ctx->state[5]; |
| 7836 | g = ctx->state[6]; |
| 7837 | h = ctx->state[7]; |
| 7838 | |
| 7839 | for (i = 0; i < 64; ++i) { |
| 7840 | uint32_t t1 = h + ep1(e) + ch(e, f, g) + mg_sha256_k[i] + m[i]; |
| 7841 | uint32_t t2 = ep0(a) + maj(a, b, c); |
| 7842 | h = g; |
| 7843 | g = f; |
| 7844 | f = e; |
| 7845 | e = d + t1; |
| 7846 | d = c; |
| 7847 | c = b; |
| 7848 | b = a; |
| 7849 | a = t1 + t2; |
| 7850 | } |
| 7851 | |
| 7852 | ctx->state[0] += a; |
| 7853 | ctx->state[1] += b; |
| 7854 | ctx->state[2] += c; |
| 7855 | ctx->state[3] += d; |
| 7856 | ctx->state[4] += e; |
| 7857 | ctx->state[5] += f; |
| 7858 | ctx->state[6] += g; |
| 7859 | ctx->state[7] += h; |
| 7860 | } |
| 7861 | |
| 7862 | void mg_sha256_update(mg_sha256_ctx *ctx, const unsigned char *data, |
| 7863 | size_t len) { |
| 7864 | size_t i; |
| 7865 | for (i = 0; i < len; i++) { |
| 7866 | ctx->buffer[ctx->len] = data[i]; |
| 7867 | if ((++ctx->len) == 64) { |
| 7868 | mg_sha256_chunk(ctx); |
| 7869 | ctx->bits += 512; |
| 7870 | ctx->len = 0; |
| 7871 | } |
| 7872 | } |
| 7873 | } |
| 7874 | |
| 7875 | // TODO: make final reusable (remove side effects) |
| 7876 | void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *ctx) { |
| 7877 | uint32_t i = ctx->len; |
| 7878 | if (i < 56) { |
| 7879 | ctx->buffer[i++] = 0x80; |
| 7880 | while (i < 56) { |
| 7881 | ctx->buffer[i++] = 0x00; |
| 7882 | } |
| 7883 | } else { |
| 7884 | ctx->buffer[i++] = 0x80; |
| 7885 | while (i < 64) { |
| 7886 | ctx->buffer[i++] = 0x00; |
| 7887 | } |
| 7888 | mg_sha256_chunk(ctx); |
| 7889 | memset(ctx->buffer, 0, 56); |
| 7890 | } |
| 7891 | |
| 7892 | ctx->bits += ctx->len * 8; |
| 7893 | ctx->buffer[63] = (uint8_t) ((ctx->bits) & 0xff); |
| 7894 | ctx->buffer[62] = (uint8_t) ((ctx->bits >> 8) & 0xff); |
| 7895 | ctx->buffer[61] = (uint8_t) ((ctx->bits >> 16) & 0xff); |
| 7896 | ctx->buffer[60] = (uint8_t) ((ctx->bits >> 24) & 0xff); |
| 7897 | ctx->buffer[59] = (uint8_t) ((ctx->bits >> 32) & 0xff); |
| 7898 | ctx->buffer[58] = (uint8_t) ((ctx->bits >> 40) & 0xff); |
| 7899 | ctx->buffer[57] = (uint8_t) ((ctx->bits >> 48) & 0xff); |
| 7900 | ctx->buffer[56] = (uint8_t) ((ctx->bits >> 56) & 0xff); |
| 7901 | mg_sha256_chunk(ctx); |
| 7902 | |
| 7903 | for (i = 0; i < 4; ++i) { |
| 7904 | digest[i] = (uint8_t) ((ctx->state[0] >> (24 - i * 8)) & 0xff); |
| 7905 | digest[i + 4] = (uint8_t) ((ctx->state[1] >> (24 - i * 8)) & 0xff); |
| 7906 | digest[i + 8] = (uint8_t) ((ctx->state[2] >> (24 - i * 8)) & 0xff); |
| 7907 | digest[i + 12] = (uint8_t) ((ctx->state[3] >> (24 - i * 8)) & 0xff); |
| 7908 | digest[i + 16] = (uint8_t) ((ctx->state[4] >> (24 - i * 8)) & 0xff); |
| 7909 | digest[i + 20] = (uint8_t) ((ctx->state[5] >> (24 - i * 8)) & 0xff); |
| 7910 | digest[i + 24] = (uint8_t) ((ctx->state[6] >> (24 - i * 8)) & 0xff); |
| 7911 | digest[i + 28] = (uint8_t) ((ctx->state[7] >> (24 - i * 8)) & 0xff); |
| 7912 | } |
| 7913 | } |
| 7914 | |
| 7915 | void mg_sha256(uint8_t dst[32], uint8_t *data, size_t datasz) { |
| 7916 | mg_sha256_ctx ctx; |
| 7917 | mg_sha256_init(&ctx); |
| 7918 | mg_sha256_update(&ctx, data, datasz); |
| 7919 | mg_sha256_final(dst, &ctx); |
| 7920 | } |
| 7921 | |
| 7922 | void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, |
| 7923 | size_t datasz) { |
| 7924 | mg_sha256_ctx ctx; |
| 7925 | uint8_t k[64] = {0}; |
| 7926 | uint8_t o_pad[64], i_pad[64]; |
| 7927 | unsigned int i; |
| 7928 | memset(i_pad, 0x36, sizeof(i_pad)); |
| 7929 | memset(o_pad, 0x5c, sizeof(o_pad)); |
| 7930 | if (keysz < 64) { |
| 7931 | if (keysz > 0) memmove(k, key, keysz); |
| 7932 | } else { |
| 7933 | mg_sha256_init(&ctx); |
| 7934 | mg_sha256_update(&ctx, key, keysz); |
| 7935 | mg_sha256_final(k, &ctx); |
| 7936 | } |
| 7937 | for (i = 0; i < sizeof(k); i++) { |
| 7938 | i_pad[i] ^= k[i]; |
| 7939 | o_pad[i] ^= k[i]; |
| 7940 | } |
| 7941 | mg_sha256_init(&ctx); |
| 7942 | mg_sha256_update(&ctx, i_pad, sizeof(i_pad)); |
| 7943 | mg_sha256_update(&ctx, data, datasz); |
| 7944 | mg_sha256_final(dst, &ctx); |
| 7945 | mg_sha256_init(&ctx); |
| 7946 | mg_sha256_update(&ctx, o_pad, sizeof(o_pad)); |
| 7947 | mg_sha256_update(&ctx, dst, 32); |
| 7948 | mg_sha256_final(dst, &ctx); |
| 7949 | } |
| 7950 | |
| 7951 | #define rotr64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) |
| 7952 | #define ep064(x) (rotr64(x, 28) ^ rotr64(x, 34) ^ rotr64(x, 39)) |
| 7953 | #define ep164(x) (rotr64(x, 14) ^ rotr64(x, 18) ^ rotr64(x, 41)) |
| 7954 | #define sig064(x) (rotr64(x, 1) ^ rotr64(x, 8) ^ ((x) >> 7)) |
| 7955 | #define sig164(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ ((x) >> 6)) |
| 7956 | |
| 7957 | static const uint64_t mg_sha256_k2[80] = { |
| 7958 | 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, |
| 7959 | 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, |
| 7960 | 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, |
| 7961 | 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, |
| 7962 | 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, |
| 7963 | 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, |
| 7964 | 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, |
| 7965 | 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, |
| 7966 | 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, |
| 7967 | 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, |
| 7968 | 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, |
| 7969 | 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, |
| 7970 | 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, |
| 7971 | 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, |
| 7972 | 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, |
| 7973 | 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, |
| 7974 | 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, |
| 7975 | 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, |
| 7976 | 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, |
| 7977 | 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, |
| 7978 | 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, |
| 7979 | 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, |
| 7980 | 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, |
| 7981 | 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, |
| 7982 | 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, |
| 7983 | 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, |
| 7984 | 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; |
| 7985 | |
| 7986 | static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) { |
| 7987 | uint64_t m[80]; |
| 7988 | uint64_t a, b, c, d, e, f, g, h; |
| 7989 | int i, j; |
| 7990 | |
| 7991 | for (i = 0, j = 0; i < 16; ++i, j += 8) |
| 7992 | m[i] = ((uint64_t) data[j] << 56) | ((uint64_t) data[j + 1] << 48) | |
| 7993 | ((uint64_t) data[j + 2] << 40) | ((uint64_t) data[j + 3] << 32) | |
| 7994 | ((uint64_t) data[j + 4] << 24) | ((uint64_t) data[j + 5] << 16) | |
| 7995 | ((uint64_t) data[j + 6] << 8) | ((uint64_t) data[j + 7]); |
| 7996 | for (; i < 80; ++i) |
| 7997 | m[i] = sig164(m[i - 2]) + m[i - 7] + sig064(m[i - 15]) + m[i - 16]; |
| 7998 | |
| 7999 | a = ctx->state[0]; |
| 8000 | b = ctx->state[1]; |
| 8001 | c = ctx->state[2]; |
| 8002 | d = ctx->state[3]; |
| 8003 | e = ctx->state[4]; |
| 8004 | f = ctx->state[5]; |
| 8005 | g = ctx->state[6]; |
| 8006 | h = ctx->state[7]; |
| 8007 | |
| 8008 | for (i = 0; i < 80; ++i) { |
| 8009 | uint64_t t1 = h + ep164(e) + ch(e, f, g) + mg_sha256_k2[i] + m[i]; |
| 8010 | uint64_t t2 = ep064(a) + maj(a, b, c); |
| 8011 | h = g; |
| 8012 | g = f; |
| 8013 | f = e; |
| 8014 | e = d + t1; |
| 8015 | d = c; |
| 8016 | c = b; |
| 8017 | b = a; |
| 8018 | a = t1 + t2; |
| 8019 | } |
| 8020 | |
| 8021 | ctx->state[0] += a; |
| 8022 | ctx->state[1] += b; |
| 8023 | ctx->state[2] += c; |
| 8024 | ctx->state[3] += d; |
| 8025 | ctx->state[4] += e; |
| 8026 | ctx->state[5] += f; |
| 8027 | ctx->state[6] += g; |
| 8028 | ctx->state[7] += h; |
| 8029 | } |
| 8030 | |
| 8031 | void mg_sha384_init(mg_sha384_ctx *ctx) { |
| 8032 | ctx->datalen = 0; |
| 8033 | ctx->bitlen[0] = 0; |
| 8034 | ctx->bitlen[1] = 0; |
| 8035 | ctx->state[0] = 0xcbbb9d5dc1059ed8; |
| 8036 | ctx->state[1] = 0x629a292a367cd507; |
| 8037 | ctx->state[2] = 0x9159015a3070dd17; |
| 8038 | ctx->state[3] = 0x152fecd8f70e5939; |
| 8039 | ctx->state[4] = 0x67332667ffc00b31; |
| 8040 | ctx->state[5] = 0x8eb44a8768581511; |
| 8041 | ctx->state[6] = 0xdb0c2e0d64f98fa7; |
| 8042 | ctx->state[7] = 0x47b5481dbefa4fa4; |
| 8043 | } |
| 8044 | |
| 8045 | void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) { |
| 8046 | size_t i; |
| 8047 | for (i = 0; i < len; ++i) { |
| 8048 | ctx->buffer[ctx->datalen] = data[i]; |
| 8049 | ctx->datalen++; |
| 8050 | if (ctx->datalen == 128) { |
| 8051 | mg_sha384_transform(ctx, ctx->buffer); |
| 8052 | ctx->bitlen[1] += 1024; |
| 8053 | if (ctx->bitlen[1] < 1024) ctx->bitlen[0]++; |
| 8054 | ctx->datalen = 0; |
| 8055 | } |
| 8056 | } |
| 8057 | } |
| 8058 | |
| 8059 | void mg_sha384_final(uint8_t hash[48], mg_sha384_ctx *ctx) { |
| 8060 | size_t i = ctx->datalen; |
| 8061 | |
| 8062 | if (ctx->datalen < 112) { |
| 8063 | ctx->buffer[i++] = 0x80; |
| 8064 | while (i < 112) ctx->buffer[i++] = 0x00; |
| 8065 | } else { |
| 8066 | ctx->buffer[i++] = 0x80; |
| 8067 | while (i < 128) ctx->buffer[i++] = 0x00; |
| 8068 | mg_sha384_transform(ctx, ctx->buffer); |
| 8069 | memset(ctx->buffer, 0, 112); |
| 8070 | } |
| 8071 | |
| 8072 | ctx->bitlen[1] += ctx->datalen * 8; |
| 8073 | if (ctx->bitlen[1] < ctx->datalen * 8) ctx->bitlen[0]++; |
| 8074 | ctx->buffer[127] = (uint8_t) (ctx->bitlen[1]); |
| 8075 | ctx->buffer[126] = (uint8_t) (ctx->bitlen[1] >> 8); |
| 8076 | ctx->buffer[125] = (uint8_t) (ctx->bitlen[1] >> 16); |
| 8077 | ctx->buffer[124] = (uint8_t) (ctx->bitlen[1] >> 24); |
| 8078 | ctx->buffer[123] = (uint8_t) (ctx->bitlen[1] >> 32); |
| 8079 | ctx->buffer[122] = (uint8_t) (ctx->bitlen[1] >> 40); |
| 8080 | ctx->buffer[121] = (uint8_t) (ctx->bitlen[1] >> 48); |
| 8081 | ctx->buffer[120] = (uint8_t) (ctx->bitlen[1] >> 56); |
| 8082 | ctx->buffer[119] = (uint8_t) (ctx->bitlen[0]); |
| 8083 | ctx->buffer[118] = (uint8_t) (ctx->bitlen[0] >> 8); |
| 8084 | ctx->buffer[117] = (uint8_t) (ctx->bitlen[0] >> 16); |
| 8085 | ctx->buffer[116] = (uint8_t) (ctx->bitlen[0] >> 24); |
| 8086 | ctx->buffer[115] = (uint8_t) (ctx->bitlen[0] >> 32); |
| 8087 | ctx->buffer[114] = (uint8_t) (ctx->bitlen[0] >> 40); |
| 8088 | ctx->buffer[113] = (uint8_t) (ctx->bitlen[0] >> 48); |
| 8089 | ctx->buffer[112] = (uint8_t) (ctx->bitlen[0] >> 56); |
| 8090 | mg_sha384_transform(ctx, ctx->buffer); |
| 8091 | |
| 8092 | for (i = 0; i < 6; ++i) { |
| 8093 | hash[i * 8] = (uint8_t) ((ctx->state[i] >> 56) & 0xff); |
| 8094 | hash[i * 8 + 1] = (uint8_t) ((ctx->state[i] >> 48) & 0xff); |
| 8095 | hash[i * 8 + 2] = (uint8_t) ((ctx->state[i] >> 40) & 0xff); |
| 8096 | hash[i * 8 + 3] = (uint8_t) ((ctx->state[i] >> 32) & 0xff); |
| 8097 | hash[i * 8 + 4] = (uint8_t) ((ctx->state[i] >> 24) & 0xff); |
| 8098 | hash[i * 8 + 5] = (uint8_t) ((ctx->state[i] >> 16) & 0xff); |
| 8099 | hash[i * 8 + 6] = (uint8_t) ((ctx->state[i] >> 8) & 0xff); |
| 8100 | hash[i * 8 + 7] = (uint8_t) (ctx->state[i] & 0xff); |
| 8101 | } |
| 8102 | } |
| 8103 | |
| 8104 | void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz) { |
| 8105 | mg_sha384_ctx ctx; |
| 8106 | mg_sha384_init(&ctx); |
| 8107 | mg_sha384_update(&ctx, data, datasz); |
| 8108 | mg_sha384_final(dst, &ctx); |
| 8109 | } |
| 8110 | |
| 8111 | #ifdef MG_ENABLE_LINES |
| 8112 | #line 1 "src/sntp.c" |
| 8113 | #endif |
| 8114 | |
| 8115 | |
| 8116 | |
| 8117 | |
| 8118 | |
| 8119 | |
| 8120 | #define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds |
| 8121 | #define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1 |
| 8122 | |
| 8123 | static uint64_t s_boot_timestamp = 0; // Updated by SNTP |
| 8124 | |
| 8125 | uint64_t mg_now(void) { |
| 8126 | return mg_millis() + s_boot_timestamp; |
| 8127 | } |
| 8128 | |
| 8129 | static int64_t gettimestamp(const uint32_t *data) { |
| 8130 | uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]); |
| 8131 | if (sec) sec -= SNTP_TIME_OFFSET; |
| 8132 | return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0); |
| 8133 | } |
| 8134 | |
| 8135 | int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { |
| 8136 | int64_t epoch_milliseconds = -1; |
| 8137 | int mode = len > 0 ? buf[0] & 7 : 0; |
| 8138 | int version = len > 0 ? (buf[0] >> 3) & 7 : 0; |
| 8139 | if (len < 48) { |
| 8140 | MG_ERROR(("%s", "corrupt packet")); |
| 8141 | } else if (mode != 4 && mode != 5) { |
| 8142 | MG_ERROR(("%s", "not a server reply")); |
| 8143 | } else if (buf[1] == 0) { |
| 8144 | MG_ERROR(("%s", "server sent a kiss of death")); |
| 8145 | } else if (version == 4 || version == 3) { |
| 8146 | // int64_t ref = gettimestamp((uint32_t *) &buf[16]); |
| 8147 | int64_t origin_time = gettimestamp((uint32_t *) &buf[24]); |
| 8148 | int64_t receive_time = gettimestamp((uint32_t *) &buf[32]); |
| 8149 | int64_t transmit_time = gettimestamp((uint32_t *) &buf[40]); |
| 8150 | int64_t now = (int64_t) mg_millis(); |
| 8151 | int64_t latency = (now - origin_time) - (transmit_time - receive_time); |
| 8152 | epoch_milliseconds = transmit_time + latency / 2; |
| 8153 | s_boot_timestamp = (uint64_t) (epoch_milliseconds - now); |
| 8154 | } else { |
| 8155 | MG_ERROR(("unexpected version: %d", version)); |
| 8156 | } |
| 8157 | return epoch_milliseconds; |
| 8158 | } |
| 8159 | |
| 8160 | static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 8161 | uint64_t *expiration_time = (uint64_t *) c->data; |
| 8162 | if (ev == MG_EV_OPEN) { |
| 8163 | *expiration_time = mg_millis() + 3000; // Store expiration time in 3s |
| 8164 | } else if (ev == MG_EV_CONNECT) { |
| 8165 | mg_sntp_request(c); |
| 8166 | } else if (ev == MG_EV_READ) { |
| 8167 | int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len); |
| 8168 | if (milliseconds > 0) { |
| 8169 | s_boot_timestamp = (uint64_t) milliseconds - mg_millis(); |
| 8170 | mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); |
| 8171 | MG_DEBUG(("%lu got time: %lld ms from epoch", c->id, milliseconds)); |
| 8172 | } |
| 8173 | // mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer |
| 8174 | c->is_closing = 1; |
| 8175 | } else if (ev == MG_EV_POLL) { |
| 8176 | if (mg_millis() > *expiration_time) c->is_closing = 1; |
| 8177 | } else if (ev == MG_EV_CLOSE) { |
| 8178 | } |
| 8179 | (void) ev_data; |
| 8180 | } |
| 8181 | |
| 8182 | void mg_sntp_request(struct mg_connection *c) { |
| 8183 | if (c->is_resolving) { |
| 8184 | MG_ERROR(("%lu wait until resolved", c->id)); |
| 8185 | } else { |
| 8186 | int64_t now = (int64_t) mg_millis(); // Use int64_t, for vc98 |
| 8187 | uint8_t buf[48] = {0}; |
| 8188 | uint32_t *t = (uint32_t *) &buf[40]; |
| 8189 | double frac = ((double) (now % 1000)) / 1000.0 * SNTP_MAX_FRAC; |
| 8190 | buf[0] = (0 << 6) | (4 << 3) | 3; |
| 8191 | t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET); |
| 8192 | t[1] = mg_htonl((uint32_t) frac); |
| 8193 | mg_send(c, buf, sizeof(buf)); |
| 8194 | } |
| 8195 | } |
| 8196 | |
| 8197 | struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, |
| 8198 | mg_event_handler_t fn, void *fnd) { |
| 8199 | struct mg_connection *c = NULL; |
| 8200 | if (url == NULL) url = "udp://time.google.com:123"; |
| 8201 | if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) { |
| 8202 | c->pfn = sntp_cb; |
| 8203 | sntp_cb(c, MG_EV_OPEN, (void *) url); |
| 8204 | } |
| 8205 | return c; |
| 8206 | } |
| 8207 | |
| 8208 | #ifdef MG_ENABLE_LINES |
| 8209 | #line 1 "src/sock.c" |
| 8210 | #endif |
| 8211 | |
| 8212 | |
| 8213 | |
| 8214 | |
| 8215 | |
| 8216 | |
| 8217 | |
| 8218 | |
| 8219 | |
| 8220 | |
| 8221 | |
| 8222 | #if MG_ENABLE_SOCKET |
| 8223 | |
| 8224 | #ifndef closesocket |
| 8225 | #define closesocket(x) close(x) |
| 8226 | #endif |
| 8227 | |
| 8228 | #define FD(c_) ((MG_SOCKET_TYPE) (size_t) (c_)->fd) |
| 8229 | #define S2PTR(s_) ((void *) (size_t) (s_)) |
| 8230 | |
| 8231 | #ifndef MSG_NONBLOCKING |
| 8232 | #define MSG_NONBLOCKING 0 |
| 8233 | #endif |
| 8234 | |
| 8235 | #ifndef AF_INET6 |
| 8236 | #define AF_INET6 10 |
| 8237 | #endif |
| 8238 | |
| 8239 | #ifndef MG_SOCK_ERR |
| 8240 | #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? errno : 0) |
| 8241 | #endif |
| 8242 | |
| 8243 | #ifndef MG_SOCK_INTR |
| 8244 | #define MG_SOCK_INTR(fd) (fd == MG_INVALID_SOCKET && MG_SOCK_ERR(-1) == EINTR) |
| 8245 | #endif |
| 8246 | |
| 8247 | #ifndef MG_SOCK_PENDING |
| 8248 | #define MG_SOCK_PENDING(errcode) \ |
| 8249 | (((errcode) < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK)) |
| 8250 | #endif |
| 8251 | |
| 8252 | #ifndef MG_SOCK_RESET |
| 8253 | #define MG_SOCK_RESET(errcode) \ |
| 8254 | (((errcode) < 0) && (errno == EPIPE || errno == ECONNRESET)) |
| 8255 | #endif |
| 8256 | |
| 8257 | union usa { |
| 8258 | struct sockaddr sa; |
| 8259 | struct sockaddr_in sin; |
| 8260 | #if MG_ENABLE_IPV6 |
| 8261 | struct sockaddr_in6 sin6; |
| 8262 | #endif |
| 8263 | }; |
| 8264 | |
| 8265 | static socklen_t tousa(struct mg_addr *a, union usa *usa) { |
| 8266 | socklen_t len = sizeof(usa->sin); |
| 8267 | memset(usa, 0, sizeof(*usa)); |
| 8268 | usa->sin.sin_family = AF_INET; |
| 8269 | usa->sin.sin_port = a->port; |
| 8270 | memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t)); |
| 8271 | #if MG_ENABLE_IPV6 |
| 8272 | if (a->is_ip6) { |
| 8273 | usa->sin.sin_family = AF_INET6; |
| 8274 | usa->sin6.sin6_port = a->port; |
| 8275 | usa->sin6.sin6_scope_id = a->scope_id; |
| 8276 | memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip)); |
| 8277 | len = sizeof(usa->sin6); |
| 8278 | } |
| 8279 | #endif |
| 8280 | return len; |
| 8281 | } |
| 8282 | |
| 8283 | static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) { |
| 8284 | a->is_ip6 = is_ip6; |
| 8285 | a->port = usa->sin.sin_port; |
| 8286 | memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t)); |
| 8287 | #if MG_ENABLE_IPV6 |
| 8288 | if (is_ip6) { |
| 8289 | memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip)); |
| 8290 | a->port = usa->sin6.sin6_port; |
| 8291 | a->scope_id = (uint8_t) usa->sin6.sin6_scope_id; |
| 8292 | } |
| 8293 | #endif |
| 8294 | } |
| 8295 | |
| 8296 | static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) { |
| 8297 | union usa usa; |
| 8298 | socklen_t n = sizeof(usa); |
| 8299 | if (getsockname(fd, &usa.sa, &n) == 0) { |
| 8300 | tomgaddr(&usa, addr, n != sizeof(usa.sin)); |
| 8301 | } |
| 8302 | } |
| 8303 | |
| 8304 | static void iolog(struct mg_connection *c, char *buf, long n, bool r) { |
| 8305 | if (n == MG_IO_WAIT) { |
| 8306 | // Do nothing |
| 8307 | } else if (n <= 0) { |
| 8308 | c->is_closing = 1; // Termination. Don't call mg_error(): #1529 |
| 8309 | } else if (n > 0) { |
| 8310 | if (c->is_hexdumping) { |
| 8311 | MG_INFO(("\n-- %lu %M %s %M %ld", c->id, mg_print_ip_port, &c->loc, |
| 8312 | r ? "<-" : "->", mg_print_ip_port, &c->rem, n)); |
| 8313 | mg_hexdump(buf, (size_t) n); |
| 8314 | } |
| 8315 | if (r) { |
| 8316 | c->recv.len += (size_t) n; |
| 8317 | mg_call(c, MG_EV_READ, &n); |
| 8318 | } else { |
| 8319 | mg_iobuf_del(&c->send, 0, (size_t) n); |
| 8320 | // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); |
| 8321 | if (c->send.len == 0) { |
| 8322 | MG_EPOLL_MOD(c, 0); |
| 8323 | } |
| 8324 | mg_call(c, MG_EV_WRITE, &n); |
| 8325 | } |
| 8326 | } |
| 8327 | } |
| 8328 | |
| 8329 | long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { |
| 8330 | long n; |
| 8331 | if (c->is_udp) { |
| 8332 | union usa usa; |
| 8333 | socklen_t slen = tousa(&c->rem, &usa); |
| 8334 | n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen); |
| 8335 | if (n > 0) setlocaddr(FD(c), &c->loc); |
| 8336 | } else { |
| 8337 | n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING); |
| 8338 | } |
| 8339 | MG_VERBOSE(("%lu %ld %d", c->id, n, MG_SOCK_ERR(n))); |
| 8340 | if (MG_SOCK_PENDING(n)) return MG_IO_WAIT; |
| 8341 | if (MG_SOCK_RESET(n)) return MG_IO_RESET; // MbedTLS, see #1507 |
| 8342 | if (n <= 0) return MG_IO_ERR; |
| 8343 | return n; |
| 8344 | } |
| 8345 | |
| 8346 | bool mg_send(struct mg_connection *c, const void *buf, size_t len) { |
| 8347 | if (c->is_udp) { |
| 8348 | long n = mg_io_send(c, buf, len); |
| 8349 | MG_DEBUG(("%lu %ld %lu:%lu:%lu %ld err %d", c->id, c->fd, c->send.len, |
| 8350 | c->recv.len, c->rtls.len, n, MG_SOCK_ERR(n))); |
| 8351 | iolog(c, (char *) buf, n, false); |
| 8352 | return n > 0; |
| 8353 | } else { |
| 8354 | return mg_iobuf_add(&c->send, c->send.len, buf, len); |
| 8355 | } |
| 8356 | } |
| 8357 | |
| 8358 | static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) { |
| 8359 | #if defined(MG_CUSTOM_NONBLOCK) |
| 8360 | MG_CUSTOM_NONBLOCK(fd); |
| 8361 | #elif MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK |
| 8362 | unsigned long on = 1; |
| 8363 | ioctlsocket(fd, FIONBIO, &on); |
| 8364 | #elif MG_ENABLE_RL |
| 8365 | unsigned long on = 1; |
| 8366 | ioctlsocket(fd, FIONBIO, &on); |
| 8367 | #elif MG_ENABLE_FREERTOS_TCP |
| 8368 | const BaseType_t off = 0; |
| 8369 | if (setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)) != 0) (void) 0; |
| 8370 | if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0; |
| 8371 | #elif MG_ENABLE_LWIP |
| 8372 | lwip_fcntl(fd, F_SETFL, O_NONBLOCK); |
| 8373 | #elif MG_ARCH == MG_ARCH_AZURERTOS |
| 8374 | fcntl(fd, F_SETFL, O_NONBLOCK); |
| 8375 | #elif MG_ARCH == MG_ARCH_TIRTOS |
| 8376 | int val = 0; |
| 8377 | setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val)); |
| 8378 | // SPRU524J section 3.3.3 page 63, SO_SNDLOWAT |
| 8379 | int sz = sizeof(val); |
| 8380 | getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &sz); |
| 8381 | val /= 2; // set send low-water mark at half send buffer size |
| 8382 | setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val)); |
| 8383 | #else |
| 8384 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode |
| 8385 | fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec |
| 8386 | #endif |
| 8387 | } |
| 8388 | |
| 8389 | void mg_multicast_add(struct mg_connection *c, char *ip); |
| 8390 | void mg_multicast_add(struct mg_connection *c, char *ip) { |
| 8391 | #if MG_ENABLE_RL |
| 8392 | #error UNSUPPORTED |
| 8393 | #elif MG_ENABLE_FREERTOS_TCP |
| 8394 | // TODO(): prvAllowIPPacketIPv4() |
| 8395 | #else |
| 8396 | // lwIP, Unix, Windows, Zephyr(, AzureRTOS ?) |
| 8397 | struct ip_mreq mreq; |
| 8398 | mreq.imr_multiaddr.s_addr = inet_addr(ip); |
| 8399 | mreq.imr_interface.s_addr = mg_htonl(INADDR_ANY); |
| 8400 | setsockopt(FD(c), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); |
| 8401 | #endif |
| 8402 | } |
| 8403 | |
| 8404 | bool mg_open_listener(struct mg_connection *c, const char *url) { |
| 8405 | MG_SOCKET_TYPE fd = MG_INVALID_SOCKET; |
| 8406 | bool success = false; |
| 8407 | c->loc.port = mg_htons(mg_url_port(url)); |
| 8408 | if (!mg_aton(mg_url_host(url), &c->loc)) { |
| 8409 | MG_ERROR(("invalid listening URL: %s", url)); |
| 8410 | } else { |
| 8411 | union usa usa; |
| 8412 | socklen_t slen = tousa(&c->loc, &usa); |
| 8413 | int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET; |
| 8414 | int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM; |
| 8415 | int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; |
| 8416 | (void) on; |
| 8417 | |
| 8418 | if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) { |
| 8419 | MG_ERROR(("socket: %d", MG_SOCK_ERR(-1))); |
| 8420 | #if defined(SO_EXCLUSIVEADDRUSE) |
| 8421 | } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, |
| 8422 | (char *) &on, sizeof(on))) != 0) { |
| 8423 | // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" |
| 8424 | MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc))); |
| 8425 | #elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE) |
| 8426 | } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, |
| 8427 | sizeof(on))) != 0) { |
| 8428 | // 1. SO_REUSEADDR semantics on UNIX and Windows is different. On |
| 8429 | // Windows, SO_REUSEADDR allows to bind a socket to a port without error |
| 8430 | // even if the port is already open by another program. This is not the |
| 8431 | // behavior SO_REUSEADDR was designed for, and leads to hard-to-track |
| 8432 | // failure scenarios. |
| 8433 | // |
| 8434 | // 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining |
| 8435 | // SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but |
| 8436 | // won't work! (setsockopt will return EINVAL) |
| 8437 | MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc))); |
| 8438 | #endif |
| 8439 | #if MG_IPV6_V6ONLY |
| 8440 | // Bind only to the V6 address, not V4 address on this port |
| 8441 | } else if (c->loc.is_ip6 && |
| 8442 | (rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, |
| 8443 | sizeof(on))) != 0) { |
| 8444 | // See #2089. Allow to bind v4 and v6 sockets on the same port |
| 8445 | MG_ERROR(("setsockopt(IPV6_V6ONLY): %d", MG_SOCK_ERR(rc))); |
| 8446 | #endif |
| 8447 | } else if ((rc = bind(fd, &usa.sa, slen)) != 0) { |
| 8448 | MG_ERROR(("bind: %d", MG_SOCK_ERR(rc))); |
| 8449 | } else if ((type == SOCK_STREAM && |
| 8450 | (rc = listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE)) != 0)) { |
| 8451 | // NOTE(lsm): FreeRTOS uses backlog value as a connection limit |
| 8452 | // In case port was set to 0, get the real port number |
| 8453 | MG_ERROR(("listen: %d", MG_SOCK_ERR(rc))); |
| 8454 | } else { |
| 8455 | setlocaddr(fd, &c->loc); |
| 8456 | mg_set_non_blocking_mode(fd); |
| 8457 | c->fd = S2PTR(fd); |
| 8458 | MG_EPOLL_ADD(c); |
| 8459 | success = true; |
| 8460 | } |
| 8461 | } |
| 8462 | if (success == false && fd != MG_INVALID_SOCKET) closesocket(fd); |
| 8463 | return success; |
| 8464 | } |
| 8465 | |
| 8466 | static long recv_raw(struct mg_connection *c, void *buf, size_t len) { |
| 8467 | long n = 0; |
| 8468 | if (c->is_udp) { |
| 8469 | union usa usa; |
| 8470 | socklen_t slen = tousa(&c->rem, &usa); |
| 8471 | n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); |
| 8472 | if (n > 0) tomgaddr(&usa, &c->rem, slen != sizeof(usa.sin)); |
| 8473 | } else { |
| 8474 | n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); |
| 8475 | } |
| 8476 | MG_VERBOSE(("%lu %ld %d", c->id, n, MG_SOCK_ERR(n))); |
| 8477 | if (MG_SOCK_PENDING(n)) return MG_IO_WAIT; |
| 8478 | if (MG_SOCK_RESET(n)) return MG_IO_RESET; // MbedTLS, see #1507 |
| 8479 | if (n <= 0) return MG_IO_ERR; |
| 8480 | return n; |
| 8481 | } |
| 8482 | |
| 8483 | static bool ioalloc(struct mg_connection *c, struct mg_iobuf *io) { |
| 8484 | bool res = false; |
| 8485 | if (io->len >= MG_MAX_RECV_SIZE) { |
| 8486 | mg_error(c, "MG_MAX_RECV_SIZE"); |
| 8487 | } else if (io->size <= io->len && |
| 8488 | !mg_iobuf_resize(io, io->size + MG_IO_SIZE)) { |
| 8489 | mg_error(c, "OOM"); |
| 8490 | } else { |
| 8491 | res = true; |
| 8492 | } |
| 8493 | return res; |
| 8494 | } |
| 8495 | |
| 8496 | // NOTE(lsm): do only one iteration of reads, cause some systems |
| 8497 | // (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data |
| 8498 | static void read_conn(struct mg_connection *c) { |
| 8499 | if (ioalloc(c, &c->recv)) { |
| 8500 | char *buf = (char *) &c->recv.buf[c->recv.len]; |
| 8501 | size_t len = c->recv.size - c->recv.len; |
| 8502 | long n = -1; |
| 8503 | if (c->is_tls) { |
| 8504 | // Do not read to the raw TLS buffer if it already has enough. |
| 8505 | // This is to prevent overflowing c->rtls if our reads are slow |
| 8506 | long m; |
| 8507 | if (c->rtls.len < 16 * 1024 + 40) { // TLS record, header, MAC, padding |
| 8508 | if (!ioalloc(c, &c->rtls)) return; |
| 8509 | n = recv_raw(c, (char *) &c->rtls.buf[c->rtls.len], |
| 8510 | c->rtls.size - c->rtls.len); |
| 8511 | if (n > 0) c->rtls.len += (size_t) n; |
| 8512 | } |
| 8513 | // there can still be > 16K from last iteration, always mg_tls_recv() |
| 8514 | m = c->is_tls_hs ? (long) MG_IO_WAIT : mg_tls_recv(c, buf, len); |
| 8515 | if (n == MG_IO_ERR || n == MG_IO_RESET) { // Windows, see #3031 |
| 8516 | if (c->rtls.len == 0 || m < 0) { |
| 8517 | // Close only when we have fully drained both rtls and TLS buffers |
| 8518 | c->is_closing = 1; // or there's nothing we can do about it. |
| 8519 | if (m < 0) m = MG_IO_ERR; // but return last record data, see #3104 |
| 8520 | } else { // see #2885 |
| 8521 | // TLS buffer is capped to max record size, even though, there can |
| 8522 | // be more than one record, give TLS a chance to process them. |
| 8523 | } |
| 8524 | } else if (c->is_tls_hs) { |
| 8525 | mg_tls_handshake(c); |
| 8526 | } |
| 8527 | n = m; |
| 8528 | } else { |
| 8529 | n = recv_raw(c, buf, len); |
| 8530 | } |
| 8531 | MG_DEBUG(("%lu %ld %lu:%lu:%lu %ld err %d", c->id, c->fd, c->send.len, |
| 8532 | c->recv.len, c->rtls.len, n, MG_SOCK_ERR(n))); |
| 8533 | iolog(c, buf, n, true); |
| 8534 | } |
| 8535 | } |
| 8536 | |
| 8537 | static void write_conn(struct mg_connection *c) { |
| 8538 | char *buf = (char *) c->send.buf; |
| 8539 | size_t len = c->send.len; |
| 8540 | long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len); |
| 8541 | MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, |
| 8542 | (long) c->send.len, (long) c->send.size, (long) c->recv.len, |
| 8543 | (long) c->recv.size, n, MG_SOCK_ERR(n))); |
| 8544 | iolog(c, buf, n, false); |
| 8545 | } |
| 8546 | |
| 8547 | static void close_conn(struct mg_connection *c) { |
| 8548 | if (FD(c) != MG_INVALID_SOCKET) { |
| 8549 | #if MG_ENABLE_EPOLL |
| 8550 | epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_DEL, FD(c), NULL); |
| 8551 | #endif |
| 8552 | closesocket(FD(c)); |
| 8553 | #if MG_ENABLE_FREERTOS_TCP |
| 8554 | FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL); |
| 8555 | #endif |
| 8556 | } |
| 8557 | mg_close_conn(c); |
| 8558 | } |
| 8559 | |
| 8560 | static void connect_conn(struct mg_connection *c) { |
| 8561 | union usa usa; |
| 8562 | socklen_t n = sizeof(usa); |
| 8563 | // Use getpeername() to test whether we have connected |
| 8564 | if (getpeername(FD(c), &usa.sa, &n) == 0) { |
| 8565 | c->is_connecting = 0; |
| 8566 | setlocaddr(FD(c), &c->loc); |
| 8567 | mg_call(c, MG_EV_CONNECT, NULL); |
| 8568 | MG_EPOLL_MOD(c, 0); |
| 8569 | if (c->is_tls_hs) mg_tls_handshake(c); |
| 8570 | } else { |
| 8571 | mg_error(c, "socket error"); |
| 8572 | } |
| 8573 | } |
| 8574 | |
| 8575 | static void setsockopts(struct mg_connection *c) { |
| 8576 | #if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \ |
| 8577 | MG_ARCH == MG_ARCH_TIRTOS |
| 8578 | (void) c; |
| 8579 | #else |
| 8580 | int on = 1; |
| 8581 | #if !defined(SOL_TCP) |
| 8582 | #define SOL_TCP IPPROTO_TCP |
| 8583 | #endif |
| 8584 | if (setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) != 0) |
| 8585 | (void) 0; |
| 8586 | if (setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) != |
| 8587 | 0) |
| 8588 | (void) 0; |
| 8589 | #endif |
| 8590 | } |
| 8591 | |
| 8592 | void mg_connect_resolved(struct mg_connection *c) { |
| 8593 | int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; |
| 8594 | int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; |
| 8595 | int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP |
| 8596 | c->fd = S2PTR(socket(af, type, proto)); // Create outbound socket |
| 8597 | c->is_resolving = 0; // Clear resolving flag |
| 8598 | if (FD(c) == MG_INVALID_SOCKET) { |
| 8599 | mg_error(c, "socket(): %d", MG_SOCK_ERR(-1)); |
| 8600 | } else if (c->is_udp) { |
| 8601 | MG_EPOLL_ADD(c); |
| 8602 | #if MG_ARCH == MG_ARCH_TIRTOS |
| 8603 | union usa usa; // TI-RTOS NDK requires binding to receive on UDP sockets |
| 8604 | socklen_t slen = tousa(&c->loc, &usa); |
| 8605 | if ((rc = bind(c->fd, &usa.sa, slen)) != 0) |
| 8606 | MG_ERROR(("bind: %d", MG_SOCK_ERR(rc))); |
| 8607 | #endif |
| 8608 | setlocaddr(FD(c), &c->loc); |
| 8609 | mg_call(c, MG_EV_RESOLVE, NULL); |
| 8610 | mg_call(c, MG_EV_CONNECT, NULL); |
| 8611 | } else { |
| 8612 | union usa usa; |
| 8613 | socklen_t slen = tousa(&c->rem, &usa); |
| 8614 | mg_set_non_blocking_mode(FD(c)); |
| 8615 | setsockopts(c); |
| 8616 | MG_EPOLL_ADD(c); |
| 8617 | mg_call(c, MG_EV_RESOLVE, NULL); |
| 8618 | rc = connect(FD(c), &usa.sa, slen); // Attempt to connect |
| 8619 | if (rc == 0) { // Success |
| 8620 | setlocaddr(FD(c), &c->loc); |
| 8621 | mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user |
| 8622 | } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake |
| 8623 | MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); |
| 8624 | c->is_connecting = 1; |
| 8625 | } else { |
| 8626 | mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); |
| 8627 | } |
| 8628 | } |
| 8629 | } |
| 8630 | |
| 8631 | static MG_SOCKET_TYPE raccept(MG_SOCKET_TYPE sock, union usa *usa, |
| 8632 | socklen_t *len) { |
| 8633 | MG_SOCKET_TYPE fd = MG_INVALID_SOCKET; |
| 8634 | do { |
| 8635 | memset(usa, 0, sizeof(*usa)); |
| 8636 | fd = accept(sock, &usa->sa, len); |
| 8637 | } while (MG_SOCK_INTR(fd)); |
| 8638 | return fd; |
| 8639 | } |
| 8640 | |
| 8641 | static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) { |
| 8642 | struct mg_connection *c = NULL; |
| 8643 | union usa usa; |
| 8644 | socklen_t sa_len = sizeof(usa); |
| 8645 | MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len); |
| 8646 | if (fd == MG_INVALID_SOCKET) { |
| 8647 | #if MG_ARCH == MG_ARCH_AZURERTOS || defined(__ECOS) |
| 8648 | // AzureRTOS, in non-block socket mode can mark listening socket readable |
| 8649 | // even it is not. See comment for 'select' func implementation in |
| 8650 | // nx_bsd.c That's not an error, just should try later |
| 8651 | if (errno != EAGAIN) |
| 8652 | #endif |
| 8653 | MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERR(-1))); |
| 8654 | #if (MG_ARCH != MG_ARCH_WIN32) && !MG_ENABLE_FREERTOS_TCP && \ |
| 8655 | (MG_ARCH != MG_ARCH_TIRTOS) && !MG_ENABLE_POLL && !MG_ENABLE_EPOLL |
| 8656 | } else if ((long) fd >= FD_SETSIZE) { |
| 8657 | MG_ERROR(("%ld > %ld", (long) fd, (long) FD_SETSIZE)); |
| 8658 | closesocket(fd); |
| 8659 | #endif |
| 8660 | } else if ((c = mg_alloc_conn(mgr)) == NULL) { |
| 8661 | MG_ERROR(("%lu OOM", lsn->id)); |
| 8662 | closesocket(fd); |
| 8663 | } else { |
| 8664 | tomgaddr(&usa, &c->rem, sa_len != sizeof(usa.sin)); |
| 8665 | LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); |
| 8666 | c->fd = S2PTR(fd); |
| 8667 | MG_EPOLL_ADD(c); |
| 8668 | mg_set_non_blocking_mode(FD(c)); |
| 8669 | setsockopts(c); |
| 8670 | c->is_accepted = 1; |
| 8671 | c->is_hexdumping = lsn->is_hexdumping; |
| 8672 | c->loc = lsn->loc; |
| 8673 | c->pfn = lsn->pfn; |
| 8674 | c->pfn_data = lsn->pfn_data; |
| 8675 | c->fn = lsn->fn; |
| 8676 | c->fn_data = lsn->fn_data; |
| 8677 | MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port, |
| 8678 | &c->rem, mg_print_ip_port, &c->loc)); |
| 8679 | mg_call(c, MG_EV_OPEN, NULL); |
| 8680 | mg_call(c, MG_EV_ACCEPT, NULL); |
| 8681 | } |
| 8682 | } |
| 8683 | |
| 8684 | static bool can_read(const struct mg_connection *c) { |
| 8685 | return c->is_full == false; |
| 8686 | } |
| 8687 | |
| 8688 | static bool can_write(const struct mg_connection *c) { |
| 8689 | return c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0); |
| 8690 | } |
| 8691 | |
| 8692 | static bool skip_iotest(const struct mg_connection *c) { |
| 8693 | return (c->is_closing || c->is_resolving || FD(c) == MG_INVALID_SOCKET) || |
| 8694 | (can_read(c) == false && can_write(c) == false); |
| 8695 | } |
| 8696 | |
| 8697 | static void mg_iotest(struct mg_mgr *mgr, int ms) { |
| 8698 | #if MG_ENABLE_FREERTOS_TCP |
| 8699 | struct mg_connection *c; |
| 8700 | for (c = mgr->conns; c != NULL; c = c->next) { |
| 8701 | c->is_readable = c->is_writable = 0; |
| 8702 | if (skip_iotest(c)) continue; |
| 8703 | if (can_read(c)) |
| 8704 | FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT); |
| 8705 | if (can_write(c)) FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE); |
| 8706 | if (c->is_closing) ms = 1; |
| 8707 | } |
| 8708 | FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms)); |
| 8709 | for (c = mgr->conns; c != NULL; c = c->next) { |
| 8710 | EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss); |
| 8711 | c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1U : 0; |
| 8712 | c->is_writable = bits & eSELECT_WRITE ? 1U : 0; |
| 8713 | if (c->fd != MG_INVALID_SOCKET) |
| 8714 | FreeRTOS_FD_CLR(c->fd, mgr->ss, |
| 8715 | eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE); |
| 8716 | } |
| 8717 | #elif MG_ENABLE_EPOLL |
| 8718 | size_t max = 1; |
| 8719 | for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { |
| 8720 | c->is_readable = c->is_writable = 0; |
| 8721 | if (c->rtls.len > 0 || mg_tls_pending(c) > 0) ms = 1, c->is_readable = 1; |
| 8722 | if (can_write(c)) MG_EPOLL_MOD(c, 1); |
| 8723 | if (c->is_closing) ms = 1; |
| 8724 | max++; |
| 8725 | } |
| 8726 | struct epoll_event *evs = (struct epoll_event *) alloca(max * sizeof(evs[0])); |
| 8727 | int n = epoll_wait(mgr->epoll_fd, evs, (int) max, ms); |
| 8728 | for (int i = 0; i < n; i++) { |
| 8729 | struct mg_connection *c = (struct mg_connection *) evs[i].data.ptr; |
| 8730 | if (evs[i].events & EPOLLERR) { |
| 8731 | mg_error(c, "socket error"); |
| 8732 | } else if (c->is_readable == 0) { |
| 8733 | bool rd = evs[i].events & (EPOLLIN | EPOLLHUP); |
| 8734 | bool wr = evs[i].events & EPOLLOUT; |
| 8735 | c->is_readable = can_read(c) && rd ? 1U : 0; |
| 8736 | c->is_writable = can_write(c) && wr ? 1U : 0; |
| 8737 | if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; |
| 8738 | } |
| 8739 | } |
| 8740 | (void) skip_iotest; |
| 8741 | #elif MG_ENABLE_POLL |
| 8742 | nfds_t n = 0; |
| 8743 | for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) n++; |
| 8744 | struct pollfd *fds = (struct pollfd *) alloca(n * sizeof(fds[0])); |
| 8745 | memset(fds, 0, n * sizeof(fds[0])); |
| 8746 | n = 0; |
| 8747 | for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { |
| 8748 | c->is_readable = c->is_writable = 0; |
| 8749 | if (c->is_closing) ms = 1; |
| 8750 | if (skip_iotest(c)) { |
| 8751 | // Socket not valid, ignore |
| 8752 | } else { |
| 8753 | // Don't wait if TLS is ready |
| 8754 | if (c->rtls.len > 0 || mg_tls_pending(c) > 0) ms = 1; |
| 8755 | fds[n].fd = FD(c); |
| 8756 | if (can_read(c)) fds[n].events |= POLLIN; |
| 8757 | if (can_write(c)) fds[n].events |= POLLOUT; |
| 8758 | n++; |
| 8759 | } |
| 8760 | } |
| 8761 | |
| 8762 | // MG_INFO(("poll n=%d ms=%d", (int) n, ms)); |
| 8763 | if (poll(fds, n, ms) < 0) { |
| 8764 | #if MG_ARCH == MG_ARCH_WIN32 |
| 8765 | if (n == 0) Sleep(ms); // On Windows, poll fails if no sockets |
| 8766 | #endif |
| 8767 | memset(fds, 0, n * sizeof(fds[0])); |
| 8768 | } |
| 8769 | n = 0; |
| 8770 | for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { |
| 8771 | if (skip_iotest(c)) { |
| 8772 | // Socket not valid, ignore |
| 8773 | } else { |
| 8774 | if (fds[n].revents & POLLERR) { |
| 8775 | mg_error(c, "socket error"); |
| 8776 | } else { |
| 8777 | c->is_readable = |
| 8778 | (unsigned) (fds[n].revents & (POLLIN | POLLHUP) ? 1 : 0); |
| 8779 | c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0); |
| 8780 | if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; |
| 8781 | } |
| 8782 | n++; |
| 8783 | } |
| 8784 | } |
| 8785 | #else |
| 8786 | struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp; |
| 8787 | struct mg_connection *c; |
| 8788 | fd_set rset, wset, eset; |
| 8789 | MG_SOCKET_TYPE maxfd = 0; |
| 8790 | int rc; |
| 8791 | |
| 8792 | FD_ZERO(&rset); |
| 8793 | FD_ZERO(&wset); |
| 8794 | FD_ZERO(&eset); |
| 8795 | tvp = ms < 0 ? NULL : &tv; |
| 8796 | for (c = mgr->conns; c != NULL; c = c->next) { |
| 8797 | c->is_readable = c->is_writable = 0; |
| 8798 | if (skip_iotest(c)) continue; |
| 8799 | FD_SET(FD(c), &eset); |
| 8800 | if (can_read(c)) FD_SET(FD(c), &rset); |
| 8801 | if (can_write(c)) FD_SET(FD(c), &wset); |
| 8802 | if (c->rtls.len > 0 || mg_tls_pending(c) > 0) tvp = &tv_zero; |
| 8803 | if (FD(c) > maxfd) maxfd = FD(c); |
| 8804 | if (c->is_closing) tvp = &tv_zero; |
| 8805 | } |
| 8806 | |
| 8807 | if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) { |
| 8808 | #if MG_ARCH == MG_ARCH_WIN32 |
| 8809 | if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets |
| 8810 | #else |
| 8811 | MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc))); |
| 8812 | #endif |
| 8813 | FD_ZERO(&rset); |
| 8814 | FD_ZERO(&wset); |
| 8815 | FD_ZERO(&eset); |
| 8816 | } |
| 8817 | |
| 8818 | for (c = mgr->conns; c != NULL; c = c->next) { |
| 8819 | if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) { |
| 8820 | mg_error(c, "socket error"); |
| 8821 | } else { |
| 8822 | c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset); |
| 8823 | c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset); |
| 8824 | if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; |
| 8825 | } |
| 8826 | } |
| 8827 | #endif |
| 8828 | } |
| 8829 | |
| 8830 | static bool mg_socketpair(MG_SOCKET_TYPE sp[2], union usa usa[2]) { |
| 8831 | socklen_t n = sizeof(usa[0].sin); |
| 8832 | bool success = false; |
| 8833 | |
| 8834 | sp[0] = sp[1] = MG_INVALID_SOCKET; |
| 8835 | (void) memset(&usa[0], 0, sizeof(usa[0])); |
| 8836 | usa[0].sin.sin_family = AF_INET; |
| 8837 | *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001U); // 127.0.0.1 |
| 8838 | usa[1] = usa[0]; |
| 8839 | |
| 8840 | if ((sp[0] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != MG_INVALID_SOCKET && |
| 8841 | (sp[1] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != MG_INVALID_SOCKET && |
| 8842 | bind(sp[0], &usa[0].sa, n) == 0 && // |
| 8843 | bind(sp[1], &usa[1].sa, n) == 0 && // |
| 8844 | getsockname(sp[0], &usa[0].sa, &n) == 0 && // |
| 8845 | getsockname(sp[1], &usa[1].sa, &n) == 0 && // |
| 8846 | connect(sp[0], &usa[1].sa, n) == 0 && // |
| 8847 | connect(sp[1], &usa[0].sa, n) == 0) { // |
| 8848 | success = true; |
| 8849 | } |
| 8850 | if (!success) { |
| 8851 | if (sp[0] != MG_INVALID_SOCKET) closesocket(sp[0]); |
| 8852 | if (sp[1] != MG_INVALID_SOCKET) closesocket(sp[1]); |
| 8853 | sp[0] = sp[1] = MG_INVALID_SOCKET; |
| 8854 | } |
| 8855 | return success; |
| 8856 | } |
| 8857 | |
| 8858 | // mg_wakeup() event handler |
| 8859 | static void wufn(struct mg_connection *c, int ev, void *ev_data) { |
| 8860 | if (ev == MG_EV_READ) { |
| 8861 | unsigned long *id = (unsigned long *) c->recv.buf; |
| 8862 | // MG_INFO(("Got data")); |
| 8863 | // mg_hexdump(c->recv.buf, c->recv.len); |
| 8864 | if (c->recv.len >= sizeof(*id)) { |
| 8865 | struct mg_connection *t; |
| 8866 | for (t = c->mgr->conns; t != NULL; t = t->next) { |
| 8867 | if (t->id == *id) { |
| 8868 | struct mg_str data = mg_str_n((char *) c->recv.buf + sizeof(*id), |
| 8869 | c->recv.len - sizeof(*id)); |
| 8870 | mg_call(t, MG_EV_WAKEUP, &data); |
| 8871 | } |
| 8872 | } |
| 8873 | } |
| 8874 | c->recv.len = 0; // Consume received data |
| 8875 | } else if (ev == MG_EV_CLOSE) { |
| 8876 | closesocket(c->mgr->pipe); // When we're closing, close the other |
| 8877 | c->mgr->pipe = MG_INVALID_SOCKET; // side of the socketpair, too |
| 8878 | } |
| 8879 | (void) ev_data; |
| 8880 | } |
| 8881 | |
| 8882 | bool mg_wakeup_init(struct mg_mgr *mgr) { |
| 8883 | bool ok = false; |
| 8884 | if (mgr->pipe == MG_INVALID_SOCKET) { |
| 8885 | union usa usa[2]; |
| 8886 | MG_SOCKET_TYPE sp[2] = {MG_INVALID_SOCKET, MG_INVALID_SOCKET}; |
| 8887 | struct mg_connection *c = NULL; |
| 8888 | if (!mg_socketpair(sp, usa)) { |
| 8889 | MG_ERROR(("Cannot create socket pair")); |
| 8890 | } else if ((c = mg_wrapfd(mgr, (int) sp[1], wufn, NULL)) == NULL) { |
| 8891 | closesocket(sp[0]); |
| 8892 | closesocket(sp[1]); |
| 8893 | sp[0] = sp[1] = MG_INVALID_SOCKET; |
| 8894 | } else { |
| 8895 | tomgaddr(&usa[0], &c->rem, false); |
| 8896 | MG_DEBUG(("%lu %p pipe %lu", c->id, c->fd, (unsigned long) sp[0])); |
| 8897 | mgr->pipe = sp[0]; |
| 8898 | ok = true; |
| 8899 | } |
| 8900 | } |
| 8901 | return ok; |
| 8902 | } |
| 8903 | |
| 8904 | bool mg_wakeup(struct mg_mgr *mgr, unsigned long conn_id, const void *buf, |
| 8905 | size_t len) { |
| 8906 | if (mgr->pipe != MG_INVALID_SOCKET && conn_id > 0) { |
| 8907 | char *extended_buf = (char *) alloca(len + sizeof(conn_id)); |
| 8908 | memcpy(extended_buf, &conn_id, sizeof(conn_id)); |
| 8909 | memcpy(extended_buf + sizeof(conn_id), buf, len); |
| 8910 | send(mgr->pipe, extended_buf, len + sizeof(conn_id), MSG_NONBLOCKING); |
| 8911 | return true; |
| 8912 | } |
| 8913 | return false; |
| 8914 | } |
| 8915 | |
| 8916 | void mg_mgr_poll(struct mg_mgr *mgr, int ms) { |
| 8917 | struct mg_connection *c, *tmp; |
| 8918 | uint64_t now; |
| 8919 | |
| 8920 | mg_iotest(mgr, ms); |
| 8921 | now = mg_millis(); |
| 8922 | mg_timer_poll(&mgr->timers, now); |
| 8923 | |
| 8924 | for (c = mgr->conns; c != NULL; c = tmp) { |
| 8925 | bool is_resp = c->is_resp; |
| 8926 | tmp = c->next; |
| 8927 | mg_call(c, MG_EV_POLL, &now); |
| 8928 | if (is_resp && !c->is_resp) { |
| 8929 | long n = 0; |
| 8930 | mg_call(c, MG_EV_READ, &n); |
| 8931 | } |
| 8932 | MG_VERBOSE(("%lu %c%c %c%c%c%c%c %lu %lu", c->id, |
| 8933 | c->is_readable ? 'r' : '-', c->is_writable ? 'w' : '-', |
| 8934 | c->is_tls ? 'T' : 't', c->is_connecting ? 'C' : 'c', |
| 8935 | c->is_tls_hs ? 'H' : 'h', c->is_resolving ? 'R' : 'r', |
| 8936 | c->is_closing ? 'C' : 'c', mg_tls_pending(c), c->rtls.len)); |
| 8937 | if (c->is_resolving || c->is_closing) { |
| 8938 | // Do nothing |
| 8939 | } else if (c->is_listening && c->is_udp == 0) { |
| 8940 | if (c->is_readable) accept_conn(mgr, c); |
| 8941 | } else if (c->is_connecting) { |
| 8942 | if (c->is_readable || c->is_writable) connect_conn(c); |
| 8943 | //} else if (c->is_tls_hs) { |
| 8944 | // if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); |
| 8945 | } else { |
| 8946 | if (c->is_readable) read_conn(c); |
| 8947 | if (c->is_writable) write_conn(c); |
| 8948 | } |
| 8949 | |
| 8950 | if (c->is_draining && c->send.len == 0) c->is_closing = 1; |
| 8951 | if (c->is_closing) close_conn(c); |
| 8952 | } |
| 8953 | } |
| 8954 | #endif |
| 8955 | |
| 8956 | #ifdef MG_ENABLE_LINES |
| 8957 | #line 1 "src/ssi.c" |
| 8958 | #endif |
| 8959 | |
| 8960 | |
| 8961 | |
| 8962 | |
| 8963 | #ifndef MG_MAX_SSI_DEPTH |
| 8964 | #define MG_MAX_SSI_DEPTH 5 |
| 8965 | #endif |
| 8966 | |
| 8967 | #ifndef MG_SSI_BUFSIZ |
| 8968 | #define MG_SSI_BUFSIZ 1024 |
| 8969 | #endif |
| 8970 | |
| 8971 | #if MG_ENABLE_SSI |
| 8972 | static char *mg_ssi(const char *path, const char *root, int depth) { |
| 8973 | struct mg_iobuf b = {NULL, 0, 0, MG_IO_SIZE}; |
| 8974 | FILE *fp = fopen(path, "rb"); |
| 8975 | if (fp != NULL) { |
| 8976 | char buf[MG_SSI_BUFSIZ], arg[sizeof(buf)]; |
| 8977 | int ch, intag = 0; |
| 8978 | size_t len = 0; |
| 8979 | buf[0] = arg[0] = '\0'; |
| 8980 | while ((ch = fgetc(fp)) != EOF) { |
| 8981 | if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { |
| 8982 | buf[len++] = (char) (ch & 0xff); |
| 8983 | buf[len] = '\0'; |
| 8984 | if (sscanf(buf, "<!--#include file=\"%[^\"]", arg) > 0) { |
| 8985 | char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], |
| 8986 | *p = (char *) path + strlen(path), *data; |
| 8987 | while (p > path && p[-1] != MG_DIRSEP && p[-1] != '/') p--; |
| 8988 | mg_snprintf(tmp, sizeof(tmp), "%.*s%s", (int) (p - path), path, arg); |
| 8989 | if (depth < MG_MAX_SSI_DEPTH && |
| 8990 | (data = mg_ssi(tmp, root, depth + 1)) != NULL) { |
| 8991 | mg_iobuf_add(&b, b.len, data, strlen(data)); |
| 8992 | free(data); |
| 8993 | } else { |
| 8994 | MG_ERROR(("%s: file=%s error or too deep", path, arg)); |
| 8995 | } |
| 8996 | } else if (sscanf(buf, "<!--#include virtual=\"%[^\"]", arg) > 0) { |
| 8997 | char tmp[MG_PATH_MAX + MG_SSI_BUFSIZ + 10], *data; |
| 8998 | mg_snprintf(tmp, sizeof(tmp), "%s%s", root, arg); |
| 8999 | if (depth < MG_MAX_SSI_DEPTH && |
| 9000 | (data = mg_ssi(tmp, root, depth + 1)) != NULL) { |
| 9001 | mg_iobuf_add(&b, b.len, data, strlen(data)); |
| 9002 | free(data); |
| 9003 | } else { |
| 9004 | MG_ERROR(("%s: virtual=%s error or too deep", path, arg)); |
| 9005 | } |
| 9006 | } else { |
| 9007 | // Unknown SSI tag |
| 9008 | MG_ERROR(("Unknown SSI tag: %.*s", (int) len, buf)); |
| 9009 | mg_iobuf_add(&b, b.len, buf, len); |
| 9010 | } |
| 9011 | intag = 0; |
| 9012 | len = 0; |
| 9013 | } else if (ch == '<') { |
| 9014 | intag = 1; |
| 9015 | if (len > 0) mg_iobuf_add(&b, b.len, buf, len); |
| 9016 | len = 0; |
| 9017 | buf[len++] = (char) (ch & 0xff); |
| 9018 | } else if (intag) { |
| 9019 | if (len == 5 && strncmp(buf, "<!--#", 5) != 0) { |
| 9020 | intag = 0; |
| 9021 | } else if (len >= sizeof(buf) - 2) { |
| 9022 | MG_ERROR(("%s: SSI tag is too large", path)); |
| 9023 | len = 0; |
| 9024 | } |
| 9025 | buf[len++] = (char) (ch & 0xff); |
| 9026 | } else { |
| 9027 | buf[len++] = (char) (ch & 0xff); |
| 9028 | if (len >= sizeof(buf)) { |
| 9029 | mg_iobuf_add(&b, b.len, buf, len); |
| 9030 | len = 0; |
| 9031 | } |
| 9032 | } |
| 9033 | } |
| 9034 | if (len > 0) mg_iobuf_add(&b, b.len, buf, len); |
| 9035 | if (b.len > 0) mg_iobuf_add(&b, b.len, "", 1); // nul-terminate |
| 9036 | fclose(fp); |
| 9037 | } |
| 9038 | (void) depth; |
| 9039 | (void) root; |
| 9040 | return (char *) b.buf; |
| 9041 | } |
| 9042 | |
| 9043 | void mg_http_serve_ssi(struct mg_connection *c, const char *root, |
| 9044 | const char *fullpath) { |
| 9045 | const char *headers = "Content-Type: text/html; charset=utf-8\r\n"; |
| 9046 | char *data = mg_ssi(fullpath, root, 0); |
| 9047 | mg_http_reply(c, 200, headers, "%s", data == NULL ? "" : data); |
| 9048 | free(data); |
| 9049 | } |
| 9050 | #else |
| 9051 | void mg_http_serve_ssi(struct mg_connection *c, const char *root, |
| 9052 | const char *fullpath) { |
| 9053 | mg_http_reply(c, 501, NULL, "SSI not enabled"); |
| 9054 | (void) root, (void) fullpath; |
| 9055 | } |
| 9056 | #endif |
| 9057 | |
| 9058 | #ifdef MG_ENABLE_LINES |
| 9059 | #line 1 "src/str.c" |
| 9060 | #endif |
| 9061 | |
| 9062 | |
| 9063 | struct mg_str mg_str_s(const char *s) { |
| 9064 | struct mg_str str = {(char *) s, s == NULL ? 0 : strlen(s)}; |
| 9065 | return str; |
| 9066 | } |
| 9067 | |
| 9068 | struct mg_str mg_str_n(const char *s, size_t n) { |
| 9069 | struct mg_str str = {(char *) s, n}; |
| 9070 | return str; |
| 9071 | } |
| 9072 | |
| 9073 | static int mg_tolc(char c) { |
| 9074 | return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c; |
| 9075 | } |
| 9076 | |
| 9077 | int mg_casecmp(const char *s1, const char *s2) { |
| 9078 | int diff = 0; |
| 9079 | do { |
| 9080 | int c = mg_tolc(*s1++), d = mg_tolc(*s2++); |
| 9081 | diff = c - d; |
| 9082 | } while (diff == 0 && s1[-1] != '\0'); |
| 9083 | return diff; |
| 9084 | } |
| 9085 | |
| 9086 | struct mg_str mg_strdup(const struct mg_str s) { |
| 9087 | struct mg_str r = {NULL, 0}; |
| 9088 | if (s.len > 0 && s.buf != NULL) { |
| 9089 | char *sc = (char *) calloc(1, s.len + 1); |
| 9090 | if (sc != NULL) { |
| 9091 | memcpy(sc, s.buf, s.len); |
| 9092 | sc[s.len] = '\0'; |
| 9093 | r.buf = sc; |
| 9094 | r.len = s.len; |
| 9095 | } |
| 9096 | } |
| 9097 | return r; |
| 9098 | } |
| 9099 | |
| 9100 | int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { |
| 9101 | size_t i = 0; |
| 9102 | while (i < str1.len && i < str2.len) { |
| 9103 | int c1 = str1.buf[i]; |
| 9104 | int c2 = str2.buf[i]; |
| 9105 | if (c1 < c2) return -1; |
| 9106 | if (c1 > c2) return 1; |
| 9107 | i++; |
| 9108 | } |
| 9109 | if (i < str1.len) return 1; |
| 9110 | if (i < str2.len) return -1; |
| 9111 | return 0; |
| 9112 | } |
| 9113 | |
| 9114 | int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2) { |
| 9115 | size_t i = 0; |
| 9116 | while (i < str1.len && i < str2.len) { |
| 9117 | int c1 = mg_tolc(str1.buf[i]); |
| 9118 | int c2 = mg_tolc(str2.buf[i]); |
| 9119 | if (c1 < c2) return -1; |
| 9120 | if (c1 > c2) return 1; |
| 9121 | i++; |
| 9122 | } |
| 9123 | if (i < str1.len) return 1; |
| 9124 | if (i < str2.len) return -1; |
| 9125 | return 0; |
| 9126 | } |
| 9127 | |
| 9128 | bool mg_match(struct mg_str s, struct mg_str p, struct mg_str *caps) { |
| 9129 | size_t i = 0, j = 0, ni = 0, nj = 0; |
| 9130 | if (caps) caps->buf = NULL, caps->len = 0; |
| 9131 | while (i < p.len || j < s.len) { |
| 9132 | if (i < p.len && j < s.len && |
| 9133 | (p.buf[i] == '?' || |
| 9134 | (p.buf[i] != '*' && p.buf[i] != '#' && s.buf[j] == p.buf[i]))) { |
| 9135 | if (caps == NULL) { |
| 9136 | } else if (p.buf[i] == '?') { |
| 9137 | caps->buf = &s.buf[j], caps->len = 1; // Finalize `?` cap |
| 9138 | caps++, caps->buf = NULL, caps->len = 0; // Init next cap |
| 9139 | } else if (caps->buf != NULL && caps->len == 0) { |
| 9140 | caps->len = (size_t) (&s.buf[j] - caps->buf); // Finalize current cap |
| 9141 | caps++, caps->len = 0, caps->buf = NULL; // Init next cap |
| 9142 | } |
| 9143 | i++, j++; |
| 9144 | } else if (i < p.len && (p.buf[i] == '*' || p.buf[i] == '#')) { |
| 9145 | if (caps && !caps->buf) caps->len = 0, caps->buf = &s.buf[j]; // Init cap |
| 9146 | ni = i++, nj = j + 1; |
| 9147 | } else if (nj > 0 && nj <= s.len && (p.buf[ni] == '#' || s.buf[j] != '/')) { |
| 9148 | i = ni, j = nj; |
| 9149 | if (caps && caps->buf == NULL && caps->len == 0) { |
| 9150 | caps--, caps->len = 0; // Restart previous cap |
| 9151 | } |
| 9152 | } else { |
| 9153 | return false; |
| 9154 | } |
| 9155 | } |
| 9156 | if (caps && caps->buf && caps->len == 0) { |
| 9157 | caps->len = (size_t) (&s.buf[j] - caps->buf); |
| 9158 | } |
| 9159 | return true; |
| 9160 | } |
| 9161 | |
| 9162 | bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char sep) { |
| 9163 | if (s.len == 0 || s.buf == NULL) { |
| 9164 | return false; // Empty string, nothing to span - fail |
| 9165 | } else { |
| 9166 | size_t len = 0; |
| 9167 | while (len < s.len && s.buf[len] != sep) len++; // Find separator |
| 9168 | if (a) *a = mg_str_n(s.buf, len); // Init a |
| 9169 | if (b) *b = mg_str_n(s.buf + len, s.len - len); // Init b |
| 9170 | if (b && len < s.len) b->buf++, b->len--; // Skip separator |
| 9171 | return true; |
| 9172 | } |
| 9173 | } |
| 9174 | |
| 9175 | bool mg_str_to_num(struct mg_str str, int base, void *val, size_t val_len) { |
| 9176 | size_t i = 0, ndigits = 0; |
| 9177 | uint64_t max = val_len == sizeof(uint8_t) ? 0xFF |
| 9178 | : val_len == sizeof(uint16_t) ? 0xFFFF |
| 9179 | : val_len == sizeof(uint32_t) ? 0xFFFFFFFF |
| 9180 | : (uint64_t) ~0; |
| 9181 | uint64_t result = 0; |
| 9182 | if (max == (uint64_t) ~0 && val_len != sizeof(uint64_t)) return false; |
| 9183 | if (base == 0 && str.len >= 2) { |
| 9184 | if (str.buf[i] == '0') { |
| 9185 | i++; |
| 9186 | base = str.buf[i] == 'b' ? 2 : str.buf[i] == 'x' ? 16 : 10; |
| 9187 | if (base != 10) ++i; |
| 9188 | } else { |
| 9189 | base = 10; |
| 9190 | } |
| 9191 | } |
| 9192 | switch (base) { |
| 9193 | case 2: |
| 9194 | while (i < str.len && (str.buf[i] == '0' || str.buf[i] == '1')) { |
| 9195 | uint64_t digit = (uint64_t) (str.buf[i] - '0'); |
| 9196 | if (result > max / 2) return false; // Overflow |
| 9197 | result *= 2; |
| 9198 | if (result > max - digit) return false; // Overflow |
| 9199 | result += digit; |
| 9200 | i++, ndigits++; |
| 9201 | } |
| 9202 | break; |
| 9203 | case 10: |
| 9204 | while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') { |
| 9205 | uint64_t digit = (uint64_t) (str.buf[i] - '0'); |
| 9206 | if (result > max / 10) return false; // Overflow |
| 9207 | result *= 10; |
| 9208 | if (result > max - digit) return false; // Overflow |
| 9209 | result += digit; |
| 9210 | i++, ndigits++; |
| 9211 | } |
| 9212 | break; |
| 9213 | case 16: |
| 9214 | while (i < str.len) { |
| 9215 | char c = str.buf[i]; |
| 9216 | uint64_t digit = (c >= '0' && c <= '9') ? (uint64_t) (c - '0') |
| 9217 | : (c >= 'A' && c <= 'F') ? (uint64_t) (c - '7') |
| 9218 | : (c >= 'a' && c <= 'f') ? (uint64_t) (c - 'W') |
| 9219 | : (uint64_t) ~0; |
| 9220 | if (digit == (uint64_t) ~0) break; |
| 9221 | if (result > max / 16) return false; // Overflow |
| 9222 | result *= 16; |
| 9223 | if (result > max - digit) return false; // Overflow |
| 9224 | result += digit; |
| 9225 | i++, ndigits++; |
| 9226 | } |
| 9227 | break; |
| 9228 | default: |
| 9229 | return false; |
| 9230 | } |
| 9231 | if (ndigits == 0) return false; |
| 9232 | if (i != str.len) return false; |
| 9233 | if (val_len == 1) { |
| 9234 | *((uint8_t *) val) = (uint8_t) result; |
| 9235 | } else if (val_len == 2) { |
| 9236 | *((uint16_t *) val) = (uint16_t) result; |
| 9237 | } else if (val_len == 4) { |
| 9238 | *((uint32_t *) val) = (uint32_t) result; |
| 9239 | } else { |
| 9240 | *((uint64_t *) val) = (uint64_t) result; |
| 9241 | } |
| 9242 | return true; |
| 9243 | } |
| 9244 | |
| 9245 | #ifdef MG_ENABLE_LINES |
| 9246 | #line 1 "src/timer.c" |
| 9247 | #endif |
| 9248 | |
| 9249 | |
| 9250 | |
| 9251 | void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms, |
| 9252 | unsigned flags, void (*fn)(void *), void *arg) { |
| 9253 | t->period_ms = ms, t->expire = 0; |
| 9254 | t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head; |
| 9255 | *head = t; |
| 9256 | } |
| 9257 | |
| 9258 | void mg_timer_free(struct mg_timer **head, struct mg_timer *t) { |
| 9259 | while (*head && *head != t) head = &(*head)->next; |
| 9260 | if (*head) *head = t->next; |
| 9261 | } |
| 9262 | |
| 9263 | // t: expiration time, prd: period, now: current time. Return true if expired |
| 9264 | bool mg_timer_expired(uint64_t *t, uint64_t prd, uint64_t now) { |
| 9265 | if (now + prd < *t) *t = 0; // Time wrapped? Reset timer |
| 9266 | if (*t == 0) *t = now + prd; // Firt poll? Set expiration |
| 9267 | if (*t > now) return false; // Not expired yet, return |
| 9268 | *t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time |
| 9269 | return true; // Expired, return true |
| 9270 | } |
| 9271 | |
| 9272 | void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) { |
| 9273 | struct mg_timer *t, *tmp; |
| 9274 | for (t = *head; t != NULL; t = tmp) { |
| 9275 | bool once = t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) && |
| 9276 | !(t->flags & MG_TIMER_CALLED); // Handle MG_TIMER_NOW only once |
| 9277 | bool expired = mg_timer_expired(&t->expire, t->period_ms, now_ms); |
| 9278 | tmp = t->next; |
| 9279 | if (!once && !expired) continue; |
| 9280 | if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) { |
| 9281 | t->fn(t->arg); |
| 9282 | } |
| 9283 | t->flags |= MG_TIMER_CALLED; |
| 9284 | |
| 9285 | // If this timer is not repeating and marked AUTODELETE, remove it |
| 9286 | if (!(t->flags & MG_TIMER_REPEAT) && (t->flags & MG_TIMER_AUTODELETE)) { |
| 9287 | mg_timer_free(head, t); |
| 9288 | free(t); |
| 9289 | } |
| 9290 | } |
| 9291 | } |
| 9292 | |
| 9293 | #ifdef MG_ENABLE_LINES |
| 9294 | #line 1 "src/tls_aes128.c" |
| 9295 | #endif |
| 9296 | /****************************************************************************** |
| 9297 | * |
| 9298 | * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL |
| 9299 | * |
| 9300 | * This is a simple and straightforward implementation of the AES Rijndael |
| 9301 | * 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus |
| 9302 | * of this work was correctness & accuracy. It is written in 'C' without any |
| 9303 | * particular focus upon optimization or speed. It should be endian (memory |
| 9304 | * byte order) neutral since the few places that care are handled explicitly. |
| 9305 | * |
| 9306 | * This implementation of Rijndael was created by Steven M. Gibson of GRC.com. |
| 9307 | * |
| 9308 | * It is intended for general purpose use, but was written in support of GRC's |
| 9309 | * reference implementation of the SQRL (Secure Quick Reliable Login) client. |
| 9310 | * |
| 9311 | * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html |
| 9312 | * |
| 9313 | * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE |
| 9314 | * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. |
| 9315 | * |
| 9316 | *******************************************************************************/ |
| 9317 | |
| 9318 | /******************************************************************************/ |
| 9319 | #define AES_DECRYPTION 1 // whether AES decryption is supported |
| 9320 | /******************************************************************************/ |
| 9321 | |
| 9322 | #define MG_ENCRYPT 1 // specify whether we're encrypting |
| 9323 | #define MG_DECRYPT 0 // or decrypting |
| 9324 | |
| 9325 | |
| 9326 | |
| 9327 | |
| 9328 | |
| 9329 | #if MG_TLS == MG_TLS_BUILTIN |
| 9330 | /****************************************************************************** |
| 9331 | * AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use |
| 9332 | ******************************************************************************/ |
| 9333 | static void aes_init_keygen_tables(void); |
| 9334 | |
| 9335 | /****************************************************************************** |
| 9336 | * AES_SETKEY : called to expand the key for encryption or decryption |
| 9337 | ******************************************************************************/ |
| 9338 | static int aes_setkey(aes_context *ctx, // pointer to context |
| 9339 | int mode, // 1 or 0 for Encrypt/Decrypt |
| 9340 | const unsigned char *key, // AES input key |
| 9341 | unsigned int keysize); // size in bytes (must be 16, 24, 32 for |
| 9342 | // 128, 192 or 256-bit keys respectively) |
| 9343 | // returns 0 for success |
| 9344 | |
| 9345 | /****************************************************************************** |
| 9346 | * AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data |
| 9347 | ******************************************************************************/ |
| 9348 | static int aes_cipher(aes_context *ctx, // pointer to context |
| 9349 | const unsigned char input[16], // 128-bit block to en/decipher |
| 9350 | unsigned char output[16]); // 128-bit output result block |
| 9351 | // returns 0 for success |
| 9352 | |
| 9353 | /****************************************************************************** |
| 9354 | * GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx |
| 9355 | ******************************************************************************/ |
| 9356 | typedef struct { |
| 9357 | int mode; // cipher direction: encrypt/decrypt |
| 9358 | uint64_t len; // cipher data length processed so far |
| 9359 | uint64_t add_len; // total add data length |
| 9360 | uint64_t HL[16]; // precalculated lo-half HTable |
| 9361 | uint64_t HH[16]; // precalculated hi-half HTable |
| 9362 | unsigned char base_ectr[16]; // first counter-mode cipher output for tag |
| 9363 | unsigned char y[16]; // the current cipher-input IV|Counter value |
| 9364 | unsigned char buf[16]; // buf working value |
| 9365 | aes_context aes_ctx; // cipher context used |
| 9366 | } gcm_context; |
| 9367 | |
| 9368 | /****************************************************************************** |
| 9369 | * GCM_SETKEY : sets the GCM (and AES) keying material for use |
| 9370 | ******************************************************************************/ |
| 9371 | static int gcm_setkey( |
| 9372 | gcm_context *ctx, // caller-provided context ptr |
| 9373 | const unsigned char *key, // pointer to cipher key |
| 9374 | const unsigned int keysize // size in bytes (must be 16, 24, 32 for |
| 9375 | // 128, 192 or 256-bit keys respectively) |
| 9376 | ); // returns 0 for success |
| 9377 | |
| 9378 | /****************************************************************************** |
| 9379 | * |
| 9380 | * GCM_CRYPT_AND_TAG |
| 9381 | * |
| 9382 | * This either encrypts or decrypts the user-provided data and, either |
| 9383 | * way, generates an authentication tag of the requested length. It must be |
| 9384 | * called with a GCM context whose key has already been set with GCM_SETKEY. |
| 9385 | * |
| 9386 | * The user would typically call this explicitly to ENCRYPT a buffer of data |
| 9387 | * and optional associated data, and produce its an authentication tag. |
| 9388 | * |
| 9389 | * To reverse the process the user would typically call the companion |
| 9390 | * GCM_AUTH_DECRYPT function to decrypt data and verify a user-provided |
| 9391 | * authentication tag. The GCM_AUTH_DECRYPT function calls this function |
| 9392 | * to perform its decryption and tag generation, which it then compares. |
| 9393 | * |
| 9394 | ******************************************************************************/ |
| 9395 | static int gcm_crypt_and_tag( |
| 9396 | gcm_context *ctx, // gcm context with key already setup |
| 9397 | int mode, // cipher direction: MG_ENCRYPT (1) or MG_DECRYPT (0) |
| 9398 | const unsigned char *iv, // pointer to the 12-byte initialization vector |
| 9399 | size_t iv_len, // byte length if the IV. should always be 12 |
| 9400 | const unsigned char *add, // pointer to the non-ciphered additional data |
| 9401 | size_t add_len, // byte length of the additional AEAD data |
| 9402 | const unsigned char *input, // pointer to the cipher data source |
| 9403 | unsigned char *output, // pointer to the cipher data destination |
| 9404 | size_t length, // byte length of the cipher data |
| 9405 | unsigned char *tag, // pointer to the tag to be generated |
| 9406 | size_t tag_len); // byte length of the tag to be generated |
| 9407 | |
| 9408 | /****************************************************************************** |
| 9409 | * |
| 9410 | * GCM_START |
| 9411 | * |
| 9412 | * Given a user-provided GCM context, this initializes it, sets the encryption |
| 9413 | * mode, and preprocesses the initialization vector and additional AEAD data. |
| 9414 | * |
| 9415 | ******************************************************************************/ |
| 9416 | static int gcm_start( |
| 9417 | gcm_context *ctx, // pointer to user-provided GCM context |
| 9418 | int mode, // MG_ENCRYPT (1) or MG_DECRYPT (0) |
| 9419 | const unsigned char *iv, // pointer to initialization vector |
| 9420 | size_t iv_len, // IV length in bytes (should == 12) |
| 9421 | const unsigned char *add, // pointer to additional AEAD data (NULL if none) |
| 9422 | size_t add_len); // length of additional AEAD data (bytes) |
| 9423 | |
| 9424 | /****************************************************************************** |
| 9425 | * |
| 9426 | * GCM_UPDATE |
| 9427 | * |
| 9428 | * This is called once or more to process bulk plaintext or ciphertext data. |
| 9429 | * We give this some number of bytes of input and it returns the same number |
| 9430 | * of output bytes. If called multiple times (which is fine) all but the final |
| 9431 | * invocation MUST be called with length mod 16 == 0. (Only the final call can |
| 9432 | * have a partial block length of < 128 bits.) |
| 9433 | * |
| 9434 | ******************************************************************************/ |
| 9435 | static int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context |
| 9436 | size_t length, // length, in bytes, of data to process |
| 9437 | const unsigned char *input, // pointer to source data |
| 9438 | unsigned char *output); // pointer to destination data |
| 9439 | |
| 9440 | /****************************************************************************** |
| 9441 | * |
| 9442 | * GCM_FINISH |
| 9443 | * |
| 9444 | * This is called once after all calls to GCM_UPDATE to finalize the GCM. |
| 9445 | * It performs the final GHASH to produce the resulting authentication TAG. |
| 9446 | * |
| 9447 | ******************************************************************************/ |
| 9448 | static int gcm_finish( |
| 9449 | gcm_context *ctx, // pointer to user-provided GCM context |
| 9450 | unsigned char *tag, // ptr to tag buffer - NULL if tag_len = 0 |
| 9451 | size_t tag_len); // length, in bytes, of the tag-receiving buf |
| 9452 | |
| 9453 | /****************************************************************************** |
| 9454 | * |
| 9455 | * GCM_ZERO_CTX |
| 9456 | * |
| 9457 | * The GCM context contains both the GCM context and the AES context. |
| 9458 | * This includes keying and key-related material which is security- |
| 9459 | * sensitive, so it MUST be zeroed after use. This function does that. |
| 9460 | * |
| 9461 | ******************************************************************************/ |
| 9462 | static void gcm_zero_ctx(gcm_context *ctx); |
| 9463 | |
| 9464 | /****************************************************************************** |
| 9465 | * |
| 9466 | * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL |
| 9467 | * |
| 9468 | * This is a simple and straightforward implementation of the AES Rijndael |
| 9469 | * 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus |
| 9470 | * of this work was correctness & accuracy. It is written in 'C' without any |
| 9471 | * particular focus upon optimization or speed. It should be endian (memory |
| 9472 | * byte order) neutral since the few places that care are handled explicitly. |
| 9473 | * |
| 9474 | * This implementation of Rijndael was created by Steven M. Gibson of GRC.com. |
| 9475 | * |
| 9476 | * It is intended for general purpose use, but was written in support of GRC's |
| 9477 | * reference implementation of the SQRL (Secure Quick Reliable Login) client. |
| 9478 | * |
| 9479 | * See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html |
| 9480 | * |
| 9481 | * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE |
| 9482 | * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. |
| 9483 | * |
| 9484 | *******************************************************************************/ |
| 9485 | |
| 9486 | static int aes_tables_inited = 0; // run-once flag for performing key |
| 9487 | // expasion table generation (see below) |
| 9488 | /* |
| 9489 | * The following static local tables must be filled-in before the first use of |
| 9490 | * the GCM or AES ciphers. They are used for the AES key expansion/scheduling |
| 9491 | * and once built are read-only and thread safe. The "gcm_initialize" function |
| 9492 | * must be called once during system initialization to populate these arrays |
| 9493 | * for subsequent use by the AES key scheduler. If they have not been built |
| 9494 | * before attempted use, an error will be returned to the caller. |
| 9495 | * |
| 9496 | * NOTE: GCM Encryption/Decryption does NOT REQUIRE AES decryption. Since |
| 9497 | * GCM uses AES in counter-mode, where the AES cipher output is XORed with |
| 9498 | * the GCM input, we ONLY NEED AES encryption. Thus, to save space AES |
| 9499 | * decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h. |
| 9500 | */ |
| 9501 | // We always need our forward tables |
| 9502 | static unsigned char FSb[256]; // Forward substitution box (FSb) |
| 9503 | static uint32_t FT0[256]; // Forward key schedule assembly tables |
| 9504 | static uint32_t FT1[256]; |
| 9505 | static uint32_t FT2[256]; |
| 9506 | static uint32_t FT3[256]; |
| 9507 | |
| 9508 | #if AES_DECRYPTION // We ONLY need reverse for decryption |
| 9509 | static unsigned char RSb[256]; // Reverse substitution box (RSb) |
| 9510 | static uint32_t RT0[256]; // Reverse key schedule assembly tables |
| 9511 | static uint32_t RT1[256]; |
| 9512 | static uint32_t RT2[256]; |
| 9513 | static uint32_t RT3[256]; |
| 9514 | #endif /* AES_DECRYPTION */ |
| 9515 | |
| 9516 | static uint32_t RCON[10]; // AES round constants |
| 9517 | |
| 9518 | /* |
| 9519 | * Platform Endianness Neutralizing Load and Store Macro definitions |
| 9520 | * AES wants platform-neutral Little Endian (LE) byte ordering |
| 9521 | */ |
| 9522 | #define GET_UINT32_LE(n, b, i) \ |
| 9523 | { \ |
| 9524 | (n) = ((uint32_t) (b)[(i)]) | ((uint32_t) (b)[(i) + 1] << 8) | \ |
| 9525 | ((uint32_t) (b)[(i) + 2] << 16) | ((uint32_t) (b)[(i) + 3] << 24); \ |
| 9526 | } |
| 9527 | |
| 9528 | #define PUT_UINT32_LE(n, b, i) \ |
| 9529 | { \ |
| 9530 | (b)[(i)] = (unsigned char) ((n)); \ |
| 9531 | (b)[(i) + 1] = (unsigned char) ((n) >> 8); \ |
| 9532 | (b)[(i) + 2] = (unsigned char) ((n) >> 16); \ |
| 9533 | (b)[(i) + 3] = (unsigned char) ((n) >> 24); \ |
| 9534 | } |
| 9535 | |
| 9536 | /* |
| 9537 | * AES forward and reverse encryption round processing macros |
| 9538 | */ |
| 9539 | #define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ |
| 9540 | { \ |
| 9541 | X0 = *RK++ ^ FT0[(Y0) & 0xFF] ^ FT1[(Y1 >> 8) & 0xFF] ^ \ |
| 9542 | FT2[(Y2 >> 16) & 0xFF] ^ FT3[(Y3 >> 24) & 0xFF]; \ |
| 9543 | \ |
| 9544 | X1 = *RK++ ^ FT0[(Y1) & 0xFF] ^ FT1[(Y2 >> 8) & 0xFF] ^ \ |
| 9545 | FT2[(Y3 >> 16) & 0xFF] ^ FT3[(Y0 >> 24) & 0xFF]; \ |
| 9546 | \ |
| 9547 | X2 = *RK++ ^ FT0[(Y2) & 0xFF] ^ FT1[(Y3 >> 8) & 0xFF] ^ \ |
| 9548 | FT2[(Y0 >> 16) & 0xFF] ^ FT3[(Y1 >> 24) & 0xFF]; \ |
| 9549 | \ |
| 9550 | X3 = *RK++ ^ FT0[(Y3) & 0xFF] ^ FT1[(Y0 >> 8) & 0xFF] ^ \ |
| 9551 | FT2[(Y1 >> 16) & 0xFF] ^ FT3[(Y2 >> 24) & 0xFF]; \ |
| 9552 | } |
| 9553 | |
| 9554 | #define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ |
| 9555 | { \ |
| 9556 | X0 = *RK++ ^ RT0[(Y0) & 0xFF] ^ RT1[(Y3 >> 8) & 0xFF] ^ \ |
| 9557 | RT2[(Y2 >> 16) & 0xFF] ^ RT3[(Y1 >> 24) & 0xFF]; \ |
| 9558 | \ |
| 9559 | X1 = *RK++ ^ RT0[(Y1) & 0xFF] ^ RT1[(Y0 >> 8) & 0xFF] ^ \ |
| 9560 | RT2[(Y3 >> 16) & 0xFF] ^ RT3[(Y2 >> 24) & 0xFF]; \ |
| 9561 | \ |
| 9562 | X2 = *RK++ ^ RT0[(Y2) & 0xFF] ^ RT1[(Y1 >> 8) & 0xFF] ^ \ |
| 9563 | RT2[(Y0 >> 16) & 0xFF] ^ RT3[(Y3 >> 24) & 0xFF]; \ |
| 9564 | \ |
| 9565 | X3 = *RK++ ^ RT0[(Y3) & 0xFF] ^ RT1[(Y2 >> 8) & 0xFF] ^ \ |
| 9566 | RT2[(Y1 >> 16) & 0xFF] ^ RT3[(Y0 >> 24) & 0xFF]; \ |
| 9567 | } |
| 9568 | |
| 9569 | /* |
| 9570 | * These macros improve the readability of the key |
| 9571 | * generation initialization code by collapsing |
| 9572 | * repetitive common operations into logical pieces. |
| 9573 | */ |
| 9574 | #define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24) |
| 9575 | #define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00)) |
| 9576 | #define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0) |
| 9577 | #define MIX(x, y) \ |
| 9578 | { \ |
| 9579 | y = ((y << 1) | (y >> 7)) & 0xFF; \ |
| 9580 | x ^= y; \ |
| 9581 | } |
| 9582 | #define CPY128 \ |
| 9583 | { \ |
| 9584 | *RK++ = *SK++; \ |
| 9585 | *RK++ = *SK++; \ |
| 9586 | *RK++ = *SK++; \ |
| 9587 | *RK++ = *SK++; \ |
| 9588 | } |
| 9589 | |
| 9590 | /****************************************************************************** |
| 9591 | * |
| 9592 | * AES_INIT_KEYGEN_TABLES |
| 9593 | * |
| 9594 | * Fills the AES key expansion tables allocated above with their static |
| 9595 | * data. This is not "per key" data, but static system-wide read-only |
| 9596 | * table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once |
| 9597 | * at system initialization to setup the tables for all subsequent use. |
| 9598 | * |
| 9599 | ******************************************************************************/ |
| 9600 | void aes_init_keygen_tables(void) { |
| 9601 | int i, x, y, z; // general purpose iteration and computation locals |
| 9602 | int pow[256]; |
| 9603 | int log[256]; |
| 9604 | |
| 9605 | if (aes_tables_inited) return; |
| 9606 | |
| 9607 | // fill the 'pow' and 'log' tables over GF(2^8) |
| 9608 | for (i = 0, x = 1; i < 256; i++) { |
| 9609 | pow[i] = x; |
| 9610 | log[x] = i; |
| 9611 | x = (x ^ XTIME(x)) & 0xFF; |
| 9612 | } |
| 9613 | // compute the round constants |
| 9614 | for (i = 0, x = 1; i < 10; i++) { |
| 9615 | RCON[i] = (uint32_t) x; |
| 9616 | x = XTIME(x) & 0xFF; |
| 9617 | } |
| 9618 | // fill the forward and reverse substitution boxes |
| 9619 | FSb[0x00] = 0x63; |
| 9620 | #if AES_DECRYPTION // whether AES decryption is supported |
| 9621 | RSb[0x63] = 0x00; |
| 9622 | #endif /* AES_DECRYPTION */ |
| 9623 | |
| 9624 | for (i = 1; i < 256; i++) { |
| 9625 | x = y = pow[255 - log[i]]; |
| 9626 | MIX(x, y); |
| 9627 | MIX(x, y); |
| 9628 | MIX(x, y); |
| 9629 | MIX(x, y); |
| 9630 | FSb[i] = (unsigned char) (x ^= 0x63); |
| 9631 | #if AES_DECRYPTION // whether AES decryption is supported |
| 9632 | RSb[x] = (unsigned char) i; |
| 9633 | #endif /* AES_DECRYPTION */ |
| 9634 | } |
| 9635 | // generate the forward and reverse key expansion tables |
| 9636 | for (i = 0; i < 256; i++) { |
| 9637 | x = FSb[i]; |
| 9638 | y = XTIME(x) & 0xFF; |
| 9639 | z = (y ^ x) & 0xFF; |
| 9640 | |
| 9641 | FT0[i] = ((uint32_t) y) ^ ((uint32_t) x << 8) ^ ((uint32_t) x << 16) ^ |
| 9642 | ((uint32_t) z << 24); |
| 9643 | |
| 9644 | FT1[i] = ROTL8(FT0[i]); |
| 9645 | FT2[i] = ROTL8(FT1[i]); |
| 9646 | FT3[i] = ROTL8(FT2[i]); |
| 9647 | |
| 9648 | #if AES_DECRYPTION // whether AES decryption is supported |
| 9649 | x = RSb[i]; |
| 9650 | |
| 9651 | RT0[i] = ((uint32_t) MUL(0x0E, x)) ^ ((uint32_t) MUL(0x09, x) << 8) ^ |
| 9652 | ((uint32_t) MUL(0x0D, x) << 16) ^ ((uint32_t) MUL(0x0B, x) << 24); |
| 9653 | |
| 9654 | RT1[i] = ROTL8(RT0[i]); |
| 9655 | RT2[i] = ROTL8(RT1[i]); |
| 9656 | RT3[i] = ROTL8(RT2[i]); |
| 9657 | #endif /* AES_DECRYPTION */ |
| 9658 | } |
| 9659 | aes_tables_inited = 1; // flag that the tables have been generated |
| 9660 | } // to permit subsequent use of the AES cipher |
| 9661 | |
| 9662 | /****************************************************************************** |
| 9663 | * |
| 9664 | * AES_SET_ENCRYPTION_KEY |
| 9665 | * |
| 9666 | * This is called by 'aes_setkey' when we're establishing a key for |
| 9667 | * subsequent encryption. We give it a pointer to the encryption |
| 9668 | * context, a pointer to the key, and the key's length in bytes. |
| 9669 | * Valid lengths are: 16, 24 or 32 bytes (128, 192, 256 bits). |
| 9670 | * |
| 9671 | ******************************************************************************/ |
| 9672 | static int aes_set_encryption_key(aes_context *ctx, const unsigned char *key, |
| 9673 | unsigned int keysize) { |
| 9674 | unsigned int i; // general purpose iteration local |
| 9675 | uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer |
| 9676 | |
| 9677 | for (i = 0; i < (keysize >> 2); i++) { |
| 9678 | GET_UINT32_LE(RK[i], key, i << 2); |
| 9679 | } |
| 9680 | |
| 9681 | switch (ctx->rounds) { |
| 9682 | case 10: |
| 9683 | for (i = 0; i < 10; i++, RK += 4) { |
| 9684 | RK[4] = RK[0] ^ RCON[i] ^ ((uint32_t) FSb[(RK[3] >> 8) & 0xFF]) ^ |
| 9685 | ((uint32_t) FSb[(RK[3] >> 16) & 0xFF] << 8) ^ |
| 9686 | ((uint32_t) FSb[(RK[3] >> 24) & 0xFF] << 16) ^ |
| 9687 | ((uint32_t) FSb[(RK[3]) & 0xFF] << 24); |
| 9688 | |
| 9689 | RK[5] = RK[1] ^ RK[4]; |
| 9690 | RK[6] = RK[2] ^ RK[5]; |
| 9691 | RK[7] = RK[3] ^ RK[6]; |
| 9692 | } |
| 9693 | break; |
| 9694 | |
| 9695 | case 12: |
| 9696 | for (i = 0; i < 8; i++, RK += 6) { |
| 9697 | RK[6] = RK[0] ^ RCON[i] ^ ((uint32_t) FSb[(RK[5] >> 8) & 0xFF]) ^ |
| 9698 | ((uint32_t) FSb[(RK[5] >> 16) & 0xFF] << 8) ^ |
| 9699 | ((uint32_t) FSb[(RK[5] >> 24) & 0xFF] << 16) ^ |
| 9700 | ((uint32_t) FSb[(RK[5]) & 0xFF] << 24); |
| 9701 | |
| 9702 | RK[7] = RK[1] ^ RK[6]; |
| 9703 | RK[8] = RK[2] ^ RK[7]; |
| 9704 | RK[9] = RK[3] ^ RK[8]; |
| 9705 | RK[10] = RK[4] ^ RK[9]; |
| 9706 | RK[11] = RK[5] ^ RK[10]; |
| 9707 | } |
| 9708 | break; |
| 9709 | |
| 9710 | case 14: |
| 9711 | for (i = 0; i < 7; i++, RK += 8) { |
| 9712 | RK[8] = RK[0] ^ RCON[i] ^ ((uint32_t) FSb[(RK[7] >> 8) & 0xFF]) ^ |
| 9713 | ((uint32_t) FSb[(RK[7] >> 16) & 0xFF] << 8) ^ |
| 9714 | ((uint32_t) FSb[(RK[7] >> 24) & 0xFF] << 16) ^ |
| 9715 | ((uint32_t) FSb[(RK[7]) & 0xFF] << 24); |
| 9716 | |
| 9717 | RK[9] = RK[1] ^ RK[8]; |
| 9718 | RK[10] = RK[2] ^ RK[9]; |
| 9719 | RK[11] = RK[3] ^ RK[10]; |
| 9720 | |
| 9721 | RK[12] = RK[4] ^ ((uint32_t) FSb[(RK[11]) & 0xFF]) ^ |
| 9722 | ((uint32_t) FSb[(RK[11] >> 8) & 0xFF] << 8) ^ |
| 9723 | ((uint32_t) FSb[(RK[11] >> 16) & 0xFF] << 16) ^ |
| 9724 | ((uint32_t) FSb[(RK[11] >> 24) & 0xFF] << 24); |
| 9725 | |
| 9726 | RK[13] = RK[5] ^ RK[12]; |
| 9727 | RK[14] = RK[6] ^ RK[13]; |
| 9728 | RK[15] = RK[7] ^ RK[14]; |
| 9729 | } |
| 9730 | break; |
| 9731 | |
| 9732 | default: |
| 9733 | return -1; |
| 9734 | } |
| 9735 | return (0); |
| 9736 | } |
| 9737 | |
| 9738 | #if AES_DECRYPTION // whether AES decryption is supported |
| 9739 | |
| 9740 | /****************************************************************************** |
| 9741 | * |
| 9742 | * AES_SET_DECRYPTION_KEY |
| 9743 | * |
| 9744 | * This is called by 'aes_setkey' when we're establishing a |
| 9745 | * key for subsequent decryption. We give it a pointer to |
| 9746 | * the encryption context, a pointer to the key, and the key's |
| 9747 | * length in bits. Valid lengths are: 128, 192, or 256 bits. |
| 9748 | * |
| 9749 | ******************************************************************************/ |
| 9750 | static int aes_set_decryption_key(aes_context *ctx, const unsigned char *key, |
| 9751 | unsigned int keysize) { |
| 9752 | int i, j; |
| 9753 | aes_context cty; // a calling aes context for set_encryption_key |
| 9754 | uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer |
| 9755 | uint32_t *SK; |
| 9756 | int ret; |
| 9757 | |
| 9758 | cty.rounds = ctx->rounds; // initialize our local aes context |
| 9759 | cty.rk = cty.buf; // round count and key buf pointer |
| 9760 | |
| 9761 | if ((ret = aes_set_encryption_key(&cty, key, keysize)) != 0) return (ret); |
| 9762 | |
| 9763 | SK = cty.rk + cty.rounds * 4; |
| 9764 | |
| 9765 | CPY128 // copy a 128-bit block from *SK to *RK |
| 9766 | |
| 9767 | for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8) { |
| 9768 | for (j = 0; j < 4; j++, SK++) { |
| 9769 | *RK++ = RT0[FSb[(*SK) & 0xFF]] ^ RT1[FSb[(*SK >> 8) & 0xFF]] ^ |
| 9770 | RT2[FSb[(*SK >> 16) & 0xFF]] ^ RT3[FSb[(*SK >> 24) & 0xFF]]; |
| 9771 | } |
| 9772 | } |
| 9773 | CPY128 // copy a 128-bit block from *SK to *RK |
| 9774 | memset(&cty, 0, sizeof(aes_context)); // clear local aes context |
| 9775 | return (0); |
| 9776 | } |
| 9777 | |
| 9778 | #endif /* AES_DECRYPTION */ |
| 9779 | |
| 9780 | /****************************************************************************** |
| 9781 | * |
| 9782 | * AES_SETKEY |
| 9783 | * |
| 9784 | * Invoked to establish the key schedule for subsequent encryption/decryption |
| 9785 | * |
| 9786 | ******************************************************************************/ |
| 9787 | static int aes_setkey(aes_context *ctx, // AES context provided by our caller |
| 9788 | int mode, // ENCRYPT or DECRYPT flag |
| 9789 | const unsigned char *key, // pointer to the key |
| 9790 | unsigned int keysize) // key length in bytes |
| 9791 | { |
| 9792 | // since table initialization is not thread safe, we could either add |
| 9793 | // system-specific mutexes and init the AES key generation tables on |
| 9794 | // demand, or ask the developer to simply call "gcm_initialize" once during |
| 9795 | // application startup before threading begins. That's what we choose. |
| 9796 | if (!aes_tables_inited) return (-1); // fail the call when not inited. |
| 9797 | |
| 9798 | ctx->mode = mode; // capture the key type we're creating |
| 9799 | ctx->rk = ctx->buf; // initialize our round key pointer |
| 9800 | |
| 9801 | switch (keysize) // set the rounds count based upon the keysize |
| 9802 | { |
| 9803 | case 16: |
| 9804 | ctx->rounds = 10; |
| 9805 | break; // 16-byte, 128-bit key |
| 9806 | case 24: |
| 9807 | ctx->rounds = 12; |
| 9808 | break; // 24-byte, 192-bit key |
| 9809 | case 32: |
| 9810 | ctx->rounds = 14; |
| 9811 | break; // 32-byte, 256-bit key |
| 9812 | default: |
| 9813 | return (-1); |
| 9814 | } |
| 9815 | |
| 9816 | #if AES_DECRYPTION |
| 9817 | if (mode == MG_DECRYPT) // expand our key for encryption or decryption |
| 9818 | return (aes_set_decryption_key(ctx, key, keysize)); |
| 9819 | else /* MG_ENCRYPT */ |
| 9820 | #endif /* AES_DECRYPTION */ |
| 9821 | return (aes_set_encryption_key(ctx, key, keysize)); |
| 9822 | } |
| 9823 | |
| 9824 | /****************************************************************************** |
| 9825 | * |
| 9826 | * AES_CIPHER |
| 9827 | * |
| 9828 | * Perform AES encryption and decryption. |
| 9829 | * The AES context will have been setup with the encryption mode |
| 9830 | * and all keying information appropriate for the task. |
| 9831 | * |
| 9832 | ******************************************************************************/ |
| 9833 | static int aes_cipher(aes_context *ctx, const unsigned char input[16], |
| 9834 | unsigned char output[16]) { |
| 9835 | int i; |
| 9836 | uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals |
| 9837 | |
| 9838 | RK = ctx->rk; |
| 9839 | |
| 9840 | GET_UINT32_LE(X0, input, 0); |
| 9841 | X0 ^= *RK++; // load our 128-bit |
| 9842 | GET_UINT32_LE(X1, input, 4); |
| 9843 | X1 ^= *RK++; // input buffer in a storage |
| 9844 | GET_UINT32_LE(X2, input, 8); |
| 9845 | X2 ^= *RK++; // memory endian-neutral way |
| 9846 | GET_UINT32_LE(X3, input, 12); |
| 9847 | X3 ^= *RK++; |
| 9848 | |
| 9849 | #if AES_DECRYPTION // whether AES decryption is supported |
| 9850 | |
| 9851 | if (ctx->mode == MG_DECRYPT) { |
| 9852 | for (i = (ctx->rounds >> 1) - 1; i > 0; i--) { |
| 9853 | AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); |
| 9854 | AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); |
| 9855 | } |
| 9856 | |
| 9857 | AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); |
| 9858 | |
| 9859 | X0 = *RK++ ^ ((uint32_t) RSb[(Y0) & 0xFF]) ^ |
| 9860 | ((uint32_t) RSb[(Y3 >> 8) & 0xFF] << 8) ^ |
| 9861 | ((uint32_t) RSb[(Y2 >> 16) & 0xFF] << 16) ^ |
| 9862 | ((uint32_t) RSb[(Y1 >> 24) & 0xFF] << 24); |
| 9863 | |
| 9864 | X1 = *RK++ ^ ((uint32_t) RSb[(Y1) & 0xFF]) ^ |
| 9865 | ((uint32_t) RSb[(Y0 >> 8) & 0xFF] << 8) ^ |
| 9866 | ((uint32_t) RSb[(Y3 >> 16) & 0xFF] << 16) ^ |
| 9867 | ((uint32_t) RSb[(Y2 >> 24) & 0xFF] << 24); |
| 9868 | |
| 9869 | X2 = *RK++ ^ ((uint32_t) RSb[(Y2) & 0xFF]) ^ |
| 9870 | ((uint32_t) RSb[(Y1 >> 8) & 0xFF] << 8) ^ |
| 9871 | ((uint32_t) RSb[(Y0 >> 16) & 0xFF] << 16) ^ |
| 9872 | ((uint32_t) RSb[(Y3 >> 24) & 0xFF] << 24); |
| 9873 | |
| 9874 | X3 = *RK++ ^ ((uint32_t) RSb[(Y3) & 0xFF]) ^ |
| 9875 | ((uint32_t) RSb[(Y2 >> 8) & 0xFF] << 8) ^ |
| 9876 | ((uint32_t) RSb[(Y1 >> 16) & 0xFF] << 16) ^ |
| 9877 | ((uint32_t) RSb[(Y0 >> 24) & 0xFF] << 24); |
| 9878 | } else /* MG_ENCRYPT */ |
| 9879 | { |
| 9880 | #endif /* AES_DECRYPTION */ |
| 9881 | |
| 9882 | for (i = (ctx->rounds >> 1) - 1; i > 0; i--) { |
| 9883 | AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); |
| 9884 | AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); |
| 9885 | } |
| 9886 | |
| 9887 | AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); |
| 9888 | |
| 9889 | X0 = *RK++ ^ ((uint32_t) FSb[(Y0) & 0xFF]) ^ |
| 9890 | ((uint32_t) FSb[(Y1 >> 8) & 0xFF] << 8) ^ |
| 9891 | ((uint32_t) FSb[(Y2 >> 16) & 0xFF] << 16) ^ |
| 9892 | ((uint32_t) FSb[(Y3 >> 24) & 0xFF] << 24); |
| 9893 | |
| 9894 | X1 = *RK++ ^ ((uint32_t) FSb[(Y1) & 0xFF]) ^ |
| 9895 | ((uint32_t) FSb[(Y2 >> 8) & 0xFF] << 8) ^ |
| 9896 | ((uint32_t) FSb[(Y3 >> 16) & 0xFF] << 16) ^ |
| 9897 | ((uint32_t) FSb[(Y0 >> 24) & 0xFF] << 24); |
| 9898 | |
| 9899 | X2 = *RK++ ^ ((uint32_t) FSb[(Y2) & 0xFF]) ^ |
| 9900 | ((uint32_t) FSb[(Y3 >> 8) & 0xFF] << 8) ^ |
| 9901 | ((uint32_t) FSb[(Y0 >> 16) & 0xFF] << 16) ^ |
| 9902 | ((uint32_t) FSb[(Y1 >> 24) & 0xFF] << 24); |
| 9903 | |
| 9904 | X3 = *RK++ ^ ((uint32_t) FSb[(Y3) & 0xFF]) ^ |
| 9905 | ((uint32_t) FSb[(Y0 >> 8) & 0xFF] << 8) ^ |
| 9906 | ((uint32_t) FSb[(Y1 >> 16) & 0xFF] << 16) ^ |
| 9907 | ((uint32_t) FSb[(Y2 >> 24) & 0xFF] << 24); |
| 9908 | |
| 9909 | #if AES_DECRYPTION // whether AES decryption is supported |
| 9910 | } |
| 9911 | #endif /* AES_DECRYPTION */ |
| 9912 | |
| 9913 | PUT_UINT32_LE(X0, output, 0); |
| 9914 | PUT_UINT32_LE(X1, output, 4); |
| 9915 | PUT_UINT32_LE(X2, output, 8); |
| 9916 | PUT_UINT32_LE(X3, output, 12); |
| 9917 | |
| 9918 | return (0); |
| 9919 | } |
| 9920 | /* end of aes.c */ |
| 9921 | /****************************************************************************** |
| 9922 | * |
| 9923 | * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL |
| 9924 | * |
| 9925 | * This is a simple and straightforward implementation of AES-GCM authenticated |
| 9926 | * encryption. The focus of this work was correctness & accuracy. It is written |
| 9927 | * in straight 'C' without any particular focus upon optimization or speed. It |
| 9928 | * should be endian (memory byte order) neutral since the few places that care |
| 9929 | * are handled explicitly. |
| 9930 | * |
| 9931 | * This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. |
| 9932 | * |
| 9933 | * It is intended for general purpose use, but was written in support of GRC's |
| 9934 | * reference implementation of the SQRL (Secure Quick Reliable Login) client. |
| 9935 | * |
| 9936 | * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf |
| 9937 | * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ |
| 9938 | * gcm/gcm-revised-spec.pdf |
| 9939 | * |
| 9940 | * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE |
| 9941 | * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. |
| 9942 | * |
| 9943 | *******************************************************************************/ |
| 9944 | |
| 9945 | /****************************************************************************** |
| 9946 | * ==== IMPLEMENTATION WARNING ==== |
| 9947 | * |
| 9948 | * This code was developed for use within SQRL's fixed environmnent. Thus, it |
| 9949 | * is somewhat less "general purpose" than it would be if it were designed as |
| 9950 | * a general purpose AES-GCM library. Specifically, it bothers with almost NO |
| 9951 | * error checking on parameter limits, buffer bounds, etc. It assumes that it |
| 9952 | * is being invoked by its author or by someone who understands the values it |
| 9953 | * expects to receive. Its behavior will be undefined otherwise. |
| 9954 | * |
| 9955 | * All functions that might fail are defined to return 'ints' to indicate a |
| 9956 | * problem. Most do not do so now. But this allows for error propagation out |
| 9957 | * of internal functions if robust error checking should ever be desired. |
| 9958 | * |
| 9959 | ******************************************************************************/ |
| 9960 | |
| 9961 | /* Calculating the "GHASH" |
| 9962 | * |
| 9963 | * There are many ways of calculating the so-called GHASH in software, each with |
| 9964 | * a traditional size vs performance tradeoff. The GHASH (Galois field hash) is |
| 9965 | * an intriguing construction which takes two 128-bit strings (also the cipher's |
| 9966 | * block size and the fundamental operation size for the system) and hashes them |
| 9967 | * into a third 128-bit result. |
| 9968 | * |
| 9969 | * Many implementation solutions have been worked out that use large precomputed |
| 9970 | * table lookups in place of more time consuming bit fiddling, and this approach |
| 9971 | * can be scaled easily upward or downward as needed to change the time/space |
| 9972 | * tradeoff. It's been studied extensively and there's a solid body of theory |
| 9973 | * and practice. For example, without using any lookup tables an implementation |
| 9974 | * might obtain 119 cycles per byte throughput, whereas using a simple, though |
| 9975 | * large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13 |
| 9976 | * cycles per byte. |
| 9977 | * |
| 9978 | * And Intel's processors have, since 2010, included an instruction which does |
| 9979 | * the entire 128x128->128 bit job in just several 64x64->128 bit pieces. |
| 9980 | * |
| 9981 | * Since SQRL is interactive, and only processing a few 128-bit blocks, I've |
| 9982 | * settled upon a relatively slower but appealing small-table compromise which |
| 9983 | * folds a bunch of not only time consuming but also bit twiddling into a simple |
| 9984 | * 16-entry table which is attributed to Victor Shoup's 1996 work while at |
| 9985 | * Bellcore: "On Fast and Provably Secure MessageAuthentication Based on |
| 9986 | * Universal Hashing." See: http://www.shoup.net/papers/macs.pdf |
| 9987 | * See, also section 4.1 of the "gcm-revised-spec" cited above. |
| 9988 | */ |
| 9989 | |
| 9990 | /* |
| 9991 | * This 16-entry table of pre-computed constants is used by the |
| 9992 | * GHASH multiplier to improve over a strictly table-free but |
| 9993 | * significantly slower 128x128 bit multiple within GF(2^128). |
| 9994 | */ |
| 9995 | static const uint64_t last4[16] = { |
| 9996 | 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, |
| 9997 | 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0}; |
| 9998 | |
| 9999 | /* |
| 10000 | * Platform Endianness Neutralizing Load and Store Macro definitions |
| 10001 | * GCM wants platform-neutral Big Endian (BE) byte ordering |
| 10002 | */ |
| 10003 | #define GET_UINT32_BE(n, b, i) \ |
| 10004 | { \ |
| 10005 | (n) = ((uint32_t) (b)[(i)] << 24) | ((uint32_t) (b)[(i) + 1] << 16) | \ |
| 10006 | ((uint32_t) (b)[(i) + 2] << 8) | ((uint32_t) (b)[(i) + 3]); \ |
| 10007 | } |
| 10008 | |
| 10009 | #define PUT_UINT32_BE(n, b, i) \ |
| 10010 | { \ |
| 10011 | (b)[(i)] = (unsigned char) ((n) >> 24); \ |
| 10012 | (b)[(i) + 1] = (unsigned char) ((n) >> 16); \ |
| 10013 | (b)[(i) + 2] = (unsigned char) ((n) >> 8); \ |
| 10014 | (b)[(i) + 3] = (unsigned char) ((n)); \ |
| 10015 | } |
| 10016 | |
| 10017 | /****************************************************************************** |
| 10018 | * |
| 10019 | * GCM_INITIALIZE |
| 10020 | * |
| 10021 | * Must be called once to initialize the GCM library. |
| 10022 | * |
| 10023 | * At present, this only calls the AES keygen table generator, which expands |
| 10024 | * the AES keying tables for use. This is NOT A THREAD-SAFE function, so it |
| 10025 | * MUST be called during system initialization before a multi-threading |
| 10026 | * environment is running. |
| 10027 | * |
| 10028 | ******************************************************************************/ |
| 10029 | int mg_gcm_initialize(void) { |
| 10030 | aes_init_keygen_tables(); |
| 10031 | return (0); |
| 10032 | } |
| 10033 | |
| 10034 | /****************************************************************************** |
| 10035 | * |
| 10036 | * GCM_MULT |
| 10037 | * |
| 10038 | * Performs a GHASH operation on the 128-bit input vector 'x', setting |
| 10039 | * the 128-bit output vector to 'x' times H using our precomputed tables. |
| 10040 | * 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field. |
| 10041 | * |
| 10042 | ******************************************************************************/ |
| 10043 | static void gcm_mult(gcm_context *ctx, // pointer to established context |
| 10044 | const unsigned char x[16], // pointer to 128-bit input vector |
| 10045 | unsigned char output[16]) // pointer to 128-bit output vector |
| 10046 | { |
| 10047 | int i; |
| 10048 | unsigned char lo, hi, rem; |
| 10049 | uint64_t zh, zl; |
| 10050 | |
| 10051 | lo = (unsigned char) (x[15] & 0x0f); |
| 10052 | hi = (unsigned char) (x[15] >> 4); |
| 10053 | zh = ctx->HH[lo]; |
| 10054 | zl = ctx->HL[lo]; |
| 10055 | |
| 10056 | for (i = 15; i >= 0; i--) { |
| 10057 | lo = (unsigned char) (x[i] & 0x0f); |
| 10058 | hi = (unsigned char) (x[i] >> 4); |
| 10059 | |
| 10060 | if (i != 15) { |
| 10061 | rem = (unsigned char) (zl & 0x0f); |
| 10062 | zl = (zh << 60) | (zl >> 4); |
| 10063 | zh = (zh >> 4); |
| 10064 | zh ^= (uint64_t) last4[rem] << 48; |
| 10065 | zh ^= ctx->HH[lo]; |
| 10066 | zl ^= ctx->HL[lo]; |
| 10067 | } |
| 10068 | rem = (unsigned char) (zl & 0x0f); |
| 10069 | zl = (zh << 60) | (zl >> 4); |
| 10070 | zh = (zh >> 4); |
| 10071 | zh ^= (uint64_t) last4[rem] << 48; |
| 10072 | zh ^= ctx->HH[hi]; |
| 10073 | zl ^= ctx->HL[hi]; |
| 10074 | } |
| 10075 | PUT_UINT32_BE(zh >> 32, output, 0); |
| 10076 | PUT_UINT32_BE(zh, output, 4); |
| 10077 | PUT_UINT32_BE(zl >> 32, output, 8); |
| 10078 | PUT_UINT32_BE(zl, output, 12); |
| 10079 | } |
| 10080 | |
| 10081 | /****************************************************************************** |
| 10082 | * |
| 10083 | * GCM_SETKEY |
| 10084 | * |
| 10085 | * This is called to set the AES-GCM key. It initializes the AES key |
| 10086 | * and populates the gcm context's pre-calculated HTables. |
| 10087 | * |
| 10088 | ******************************************************************************/ |
| 10089 | static int gcm_setkey( |
| 10090 | gcm_context *ctx, // pointer to caller-provided gcm context |
| 10091 | const unsigned char *key, // pointer to the AES encryption key |
| 10092 | const unsigned int keysize) // size in bytes (must be 16, 24, 32 for |
| 10093 | // 128, 192 or 256-bit keys respectively) |
| 10094 | { |
| 10095 | int ret, i, j; |
| 10096 | uint64_t hi, lo; |
| 10097 | uint64_t vl, vh; |
| 10098 | unsigned char h[16]; |
| 10099 | |
| 10100 | memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context |
| 10101 | memset(h, 0, 16); // initialize the block to encrypt |
| 10102 | |
| 10103 | // encrypt the null 128-bit block to generate a key-based value |
| 10104 | // which is then used to initialize our GHASH lookup tables |
| 10105 | if ((ret = aes_setkey(&ctx->aes_ctx, MG_ENCRYPT, key, keysize)) != 0) |
| 10106 | return (ret); |
| 10107 | if ((ret = aes_cipher(&ctx->aes_ctx, h, h)) != 0) return (ret); |
| 10108 | |
| 10109 | GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian |
| 10110 | GET_UINT32_BE(lo, h, 4); |
| 10111 | vh = (uint64_t) hi << 32 | lo; |
| 10112 | |
| 10113 | GET_UINT32_BE(hi, h, 8); |
| 10114 | GET_UINT32_BE(lo, h, 12); |
| 10115 | vl = (uint64_t) hi << 32 | lo; |
| 10116 | |
| 10117 | ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128) |
| 10118 | ctx->HH[8] = vh; |
| 10119 | ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128) |
| 10120 | ctx->HL[0] = 0; |
| 10121 | |
| 10122 | for (i = 4; i > 0; i >>= 1) { |
| 10123 | uint32_t T = (uint32_t) (vl & 1) * 0xe1000000U; |
| 10124 | vl = (vh << 63) | (vl >> 1); |
| 10125 | vh = (vh >> 1) ^ ((uint64_t) T << 32); |
| 10126 | ctx->HL[i] = vl; |
| 10127 | ctx->HH[i] = vh; |
| 10128 | } |
| 10129 | for (i = 2; i < 16; i <<= 1) { |
| 10130 | uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; |
| 10131 | vh = *HiH; |
| 10132 | vl = *HiL; |
| 10133 | for (j = 1; j < i; j++) { |
| 10134 | HiH[j] = vh ^ ctx->HH[j]; |
| 10135 | HiL[j] = vl ^ ctx->HL[j]; |
| 10136 | } |
| 10137 | } |
| 10138 | return (0); |
| 10139 | } |
| 10140 | |
| 10141 | /****************************************************************************** |
| 10142 | * |
| 10143 | * GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH. |
| 10144 | * |
| 10145 | * SETKEY: |
| 10146 | * |
| 10147 | * START: Sets the Encryption/Decryption mode. |
| 10148 | * Accepts the initialization vector and additional data. |
| 10149 | * |
| 10150 | * UPDATE: Encrypts or decrypts the plaintext or ciphertext. |
| 10151 | * |
| 10152 | * FINISH: Performs a final GHASH to generate the authentication tag. |
| 10153 | * |
| 10154 | ****************************************************************************** |
| 10155 | * |
| 10156 | * GCM_START |
| 10157 | * |
| 10158 | * Given a user-provided GCM context, this initializes it, sets the encryption |
| 10159 | * mode, and preprocesses the initialization vector and additional AEAD data. |
| 10160 | * |
| 10161 | ******************************************************************************/ |
| 10162 | int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context |
| 10163 | int mode, // GCM_ENCRYPT or GCM_DECRYPT |
| 10164 | const unsigned char *iv, // pointer to initialization vector |
| 10165 | size_t iv_len, // IV length in bytes (should == 12) |
| 10166 | const unsigned char *add, // ptr to additional AEAD data (NULL if none) |
| 10167 | size_t add_len) // length of additional AEAD data (bytes) |
| 10168 | { |
| 10169 | int ret; // our error return if the AES encrypt fails |
| 10170 | unsigned char work_buf[16]; // XOR source built from provided IV if len != 16 |
| 10171 | const unsigned char *p; // general purpose array pointer |
| 10172 | size_t use_len; // byte count to process, up to 16 bytes |
| 10173 | size_t i; // local loop iterator |
| 10174 | |
| 10175 | // since the context might be reused under the same key |
| 10176 | // we zero the working buffers for this next new process |
| 10177 | memset(ctx->y, 0x00, sizeof(ctx->y)); |
| 10178 | memset(ctx->buf, 0x00, sizeof(ctx->buf)); |
| 10179 | ctx->len = 0; |
| 10180 | ctx->add_len = 0; |
| 10181 | |
| 10182 | ctx->mode = mode; // set the GCM encryption/decryption mode |
| 10183 | ctx->aes_ctx.mode = MG_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode |
| 10184 | |
| 10185 | if (iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV |
| 10186 | memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff |
| 10187 | ctx->y[15] = 1; // start "counting" from 1 (not 0) |
| 10188 | } else // if we don't have a 12-byte IV, we GHASH whatever we've been given |
| 10189 | { |
| 10190 | memset(work_buf, 0x00, 16); // clear the working buffer |
| 10191 | PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer |
| 10192 | |
| 10193 | p = iv; |
| 10194 | while (iv_len > 0) { |
| 10195 | use_len = (iv_len < 16) ? iv_len : 16; |
| 10196 | for (i = 0; i < use_len; i++) ctx->y[i] ^= p[i]; |
| 10197 | gcm_mult(ctx, ctx->y, ctx->y); |
| 10198 | iv_len -= use_len; |
| 10199 | p += use_len; |
| 10200 | } |
| 10201 | for (i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i]; |
| 10202 | gcm_mult(ctx, ctx->y, ctx->y); |
| 10203 | } |
| 10204 | if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0) |
| 10205 | return (ret); |
| 10206 | |
| 10207 | ctx->add_len = add_len; |
| 10208 | p = add; |
| 10209 | while (add_len > 0) { |
| 10210 | use_len = (add_len < 16) ? add_len : 16; |
| 10211 | for (i = 0; i < use_len; i++) ctx->buf[i] ^= p[i]; |
| 10212 | gcm_mult(ctx, ctx->buf, ctx->buf); |
| 10213 | add_len -= use_len; |
| 10214 | p += use_len; |
| 10215 | } |
| 10216 | return (0); |
| 10217 | } |
| 10218 | |
| 10219 | /****************************************************************************** |
| 10220 | * |
| 10221 | * GCM_UPDATE |
| 10222 | * |
| 10223 | * This is called once or more to process bulk plaintext or ciphertext data. |
| 10224 | * We give this some number of bytes of input and it returns the same number |
| 10225 | * of output bytes. If called multiple times (which is fine) all but the final |
| 10226 | * invocation MUST be called with length mod 16 == 0. (Only the final call can |
| 10227 | * have a partial block length of < 128 bits.) |
| 10228 | * |
| 10229 | ******************************************************************************/ |
| 10230 | int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context |
| 10231 | size_t length, // length, in bytes, of data to process |
| 10232 | const unsigned char *input, // pointer to source data |
| 10233 | unsigned char *output) // pointer to destination data |
| 10234 | { |
| 10235 | int ret; // our error return if the AES encrypt fails |
| 10236 | unsigned char ectr[16]; // counter-mode cipher output for XORing |
| 10237 | size_t use_len; // byte count to process, up to 16 bytes |
| 10238 | size_t i; // local loop iterator |
| 10239 | |
| 10240 | ctx->len += length; // bump the GCM context's running length count |
| 10241 | |
| 10242 | while (length > 0) { |
| 10243 | // clamp the length to process at 16 bytes |
| 10244 | use_len = (length < 16) ? length : 16; |
| 10245 | |
| 10246 | // increment the context's 128-bit IV||Counter 'y' vector |
| 10247 | for (i = 16; i > 12; i--) |
| 10248 | if (++ctx->y[i - 1] != 0) break; |
| 10249 | |
| 10250 | // encrypt the context's 'y' vector under the established key |
| 10251 | if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0) return (ret); |
| 10252 | |
| 10253 | // encrypt or decrypt the input to the output |
| 10254 | if (ctx->mode == MG_ENCRYPT) { |
| 10255 | for (i = 0; i < use_len; i++) { |
| 10256 | // XOR the cipher's ouptut vector (ectr) with our input |
| 10257 | output[i] = (unsigned char) (ectr[i] ^ input[i]); |
| 10258 | // now we mix in our data into the authentication hash. |
| 10259 | // if we're ENcrypting we XOR in the post-XOR (output) |
| 10260 | // results, but if we're DEcrypting we XOR in the input |
| 10261 | // data |
| 10262 | ctx->buf[i] ^= output[i]; |
| 10263 | } |
| 10264 | } else { |
| 10265 | for (i = 0; i < use_len; i++) { |
| 10266 | // but if we're DEcrypting we XOR in the input data first, |
| 10267 | // i.e. before saving to ouput data, otherwise if the input |
| 10268 | // and output buffer are the same (inplace decryption) we |
| 10269 | // would not get the correct auth tag |
| 10270 | |
| 10271 | ctx->buf[i] ^= input[i]; |
| 10272 | |
| 10273 | // XOR the cipher's ouptut vector (ectr) with our input |
| 10274 | output[i] = (unsigned char) (ectr[i] ^ input[i]); |
| 10275 | } |
| 10276 | } |
| 10277 | gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation |
| 10278 | |
| 10279 | length -= use_len; // drop the remaining byte count to process |
| 10280 | input += use_len; // bump our input pointer forward |
| 10281 | output += use_len; // bump our output pointer forward |
| 10282 | } |
| 10283 | return (0); |
| 10284 | } |
| 10285 | |
| 10286 | /****************************************************************************** |
| 10287 | * |
| 10288 | * GCM_FINISH |
| 10289 | * |
| 10290 | * This is called once after all calls to GCM_UPDATE to finalize the GCM. |
| 10291 | * It performs the final GHASH to produce the resulting authentication TAG. |
| 10292 | * |
| 10293 | ******************************************************************************/ |
| 10294 | int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context |
| 10295 | unsigned char *tag, // pointer to buffer which receives the tag |
| 10296 | size_t tag_len) // length, in bytes, of the tag-receiving buf |
| 10297 | { |
| 10298 | unsigned char work_buf[16]; |
| 10299 | uint64_t orig_len = ctx->len * 8; |
| 10300 | uint64_t orig_add_len = ctx->add_len * 8; |
| 10301 | size_t i; |
| 10302 | |
| 10303 | if (tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len); |
| 10304 | |
| 10305 | if (orig_len || orig_add_len) { |
| 10306 | memset(work_buf, 0x00, 16); |
| 10307 | |
| 10308 | PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0); |
| 10309 | PUT_UINT32_BE((orig_add_len), work_buf, 4); |
| 10310 | PUT_UINT32_BE((orig_len >> 32), work_buf, 8); |
| 10311 | PUT_UINT32_BE((orig_len), work_buf, 12); |
| 10312 | |
| 10313 | for (i = 0; i < 16; i++) ctx->buf[i] ^= work_buf[i]; |
| 10314 | gcm_mult(ctx, ctx->buf, ctx->buf); |
| 10315 | for (i = 0; i < tag_len; i++) tag[i] ^= ctx->buf[i]; |
| 10316 | } |
| 10317 | return (0); |
| 10318 | } |
| 10319 | |
| 10320 | /****************************************************************************** |
| 10321 | * |
| 10322 | * GCM_CRYPT_AND_TAG |
| 10323 | * |
| 10324 | * This either encrypts or decrypts the user-provided data and, either |
| 10325 | * way, generates an authentication tag of the requested length. It must be |
| 10326 | * called with a GCM context whose key has already been set with GCM_SETKEY. |
| 10327 | * |
| 10328 | * The user would typically call this explicitly to ENCRYPT a buffer of data |
| 10329 | * and optional associated data, and produce its an authentication tag. |
| 10330 | * |
| 10331 | * To reverse the process the user would typically call the companion |
| 10332 | * GCM_AUTH_DECRYPT function to decrypt data and verify a user-provided |
| 10333 | * authentication tag. The GCM_AUTH_DECRYPT function calls this function |
| 10334 | * to perform its decryption and tag generation, which it then compares. |
| 10335 | * |
| 10336 | ******************************************************************************/ |
| 10337 | int gcm_crypt_and_tag( |
| 10338 | gcm_context *ctx, // gcm context with key already setup |
| 10339 | int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT |
| 10340 | const unsigned char *iv, // pointer to the 12-byte initialization vector |
| 10341 | size_t iv_len, // byte length if the IV. should always be 12 |
| 10342 | const unsigned char *add, // pointer to the non-ciphered additional data |
| 10343 | size_t add_len, // byte length of the additional AEAD data |
| 10344 | const unsigned char *input, // pointer to the cipher data source |
| 10345 | unsigned char *output, // pointer to the cipher data destination |
| 10346 | size_t length, // byte length of the cipher data |
| 10347 | unsigned char *tag, // pointer to the tag to be generated |
| 10348 | size_t tag_len) // byte length of the tag to be generated |
| 10349 | { /* |
| 10350 | assuming that the caller has already invoked gcm_setkey to |
| 10351 | prepare the gcm context with the keying material, we simply |
| 10352 | invoke each of the three GCM sub-functions in turn... |
| 10353 | */ |
| 10354 | gcm_start(ctx, mode, iv, iv_len, add, add_len); |
| 10355 | gcm_update(ctx, length, input, output); |
| 10356 | gcm_finish(ctx, tag, tag_len); |
| 10357 | return (0); |
| 10358 | } |
| 10359 | |
| 10360 | /****************************************************************************** |
| 10361 | * |
| 10362 | * GCM_ZERO_CTX |
| 10363 | * |
| 10364 | * The GCM context contains both the GCM context and the AES context. |
| 10365 | * This includes keying and key-related material which is security- |
| 10366 | * sensitive, so it MUST be zeroed after use. This function does that. |
| 10367 | * |
| 10368 | ******************************************************************************/ |
| 10369 | void gcm_zero_ctx(gcm_context *ctx) { |
| 10370 | // zero the context originally provided to us |
| 10371 | memset(ctx, 0, sizeof(gcm_context)); |
| 10372 | } |
| 10373 | // |
| 10374 | // aes-gcm.c |
| 10375 | // Pods |
| 10376 | // |
| 10377 | // Created by Markus Kosmal on 20/11/14. |
| 10378 | // |
| 10379 | // |
| 10380 | |
| 10381 | int mg_aes_gcm_encrypt(unsigned char *output, // |
| 10382 | const unsigned char *input, size_t input_length, |
| 10383 | const unsigned char *key, const size_t key_len, |
| 10384 | const unsigned char *iv, const size_t iv_len, |
| 10385 | unsigned char *aead, size_t aead_len, unsigned char *tag, |
| 10386 | const size_t tag_len) { |
| 10387 | int ret = 0; // our return value |
| 10388 | gcm_context ctx; // includes the AES context structure |
| 10389 | |
| 10390 | gcm_setkey(&ctx, key, (unsigned int) key_len); |
| 10391 | |
| 10392 | ret = gcm_crypt_and_tag(&ctx, MG_ENCRYPT, iv, iv_len, aead, aead_len, input, |
| 10393 | output, input_length, tag, tag_len); |
| 10394 | |
| 10395 | gcm_zero_ctx(&ctx); |
| 10396 | |
| 10397 | return (ret); |
| 10398 | } |
| 10399 | |
| 10400 | int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input, |
| 10401 | size_t input_length, const unsigned char *key, |
| 10402 | const size_t key_len, const unsigned char *iv, |
| 10403 | const size_t iv_len) { |
| 10404 | int ret = 0; // our return value |
| 10405 | gcm_context ctx; // includes the AES context structure |
| 10406 | |
| 10407 | size_t tag_len = 0; |
| 10408 | unsigned char *tag_buf = NULL; |
| 10409 | |
| 10410 | gcm_setkey(&ctx, key, (unsigned int) key_len); |
| 10411 | |
| 10412 | ret = gcm_crypt_and_tag(&ctx, MG_DECRYPT, iv, iv_len, NULL, 0, input, output, |
| 10413 | input_length, tag_buf, tag_len); |
| 10414 | |
| 10415 | gcm_zero_ctx(&ctx); |
| 10416 | |
| 10417 | return (ret); |
| 10418 | } |
| 10419 | #endif |
| 10420 | // End of aes128 PD |
| 10421 | |
| 10422 | #ifdef MG_ENABLE_LINES |
| 10423 | #line 1 "src/tls_builtin.c" |
| 10424 | #endif |
| 10425 | |
| 10426 | |
| 10427 | |
| 10428 | |
| 10429 | |
| 10430 | |
| 10431 | |
| 10432 | |
| 10433 | |
| 10434 | |
| 10435 | |
| 10436 | |
| 10437 | #if MG_TLS == MG_TLS_BUILTIN |
| 10438 | |
| 10439 | #define CHACHA20 1 |
| 10440 | |
| 10441 | /* TLS 1.3 Record Content Type (RFC8446 B.1) */ |
| 10442 | #define MG_TLS_CHANGE_CIPHER 20 |
| 10443 | #define MG_TLS_ALERT 21 |
| 10444 | #define MG_TLS_HANDSHAKE 22 |
| 10445 | #define MG_TLS_APP_DATA 23 |
| 10446 | #define MG_TLS_HEARTBEAT 24 |
| 10447 | |
| 10448 | /* TLS 1.3 Handshake Message Type (RFC8446 B.3) */ |
| 10449 | #define MG_TLS_CLIENT_HELLO 1 |
| 10450 | #define MG_TLS_SERVER_HELLO 2 |
| 10451 | #define MG_TLS_ENCRYPTED_EXTENSIONS 8 |
| 10452 | #define MG_TLS_CERTIFICATE 11 |
| 10453 | #define MG_TLS_CERTIFICATE_REQUEST 13 |
| 10454 | #define MG_TLS_CERTIFICATE_VERIFY 15 |
| 10455 | #define MG_TLS_FINISHED 20 |
| 10456 | |
| 10457 | // handshake is re-entrant, so we need to keep track of its state state names |
| 10458 | // refer to RFC8446#A.1 |
| 10459 | enum mg_tls_hs_state { |
| 10460 | // Client state machine: |
| 10461 | MG_TLS_STATE_CLIENT_START, // Send ClientHello |
| 10462 | MG_TLS_STATE_CLIENT_WAIT_SH, // Wait for ServerHello |
| 10463 | MG_TLS_STATE_CLIENT_WAIT_EE, // Wait for EncryptedExtensions |
| 10464 | MG_TLS_STATE_CLIENT_WAIT_CERT, // Wait for Certificate |
| 10465 | MG_TLS_STATE_CLIENT_WAIT_CV, // Wait for CertificateVerify |
| 10466 | MG_TLS_STATE_CLIENT_WAIT_FINISHED, // Wait for Finished |
| 10467 | MG_TLS_STATE_CLIENT_CONNECTED, // Done |
| 10468 | |
| 10469 | // Server state machine: |
| 10470 | MG_TLS_STATE_SERVER_START, // Wait for ClientHello |
| 10471 | MG_TLS_STATE_SERVER_NEGOTIATED, // Wait for Finished |
| 10472 | MG_TLS_STATE_SERVER_CONNECTED // Done |
| 10473 | }; |
| 10474 | |
| 10475 | // encryption keys for a TLS connection |
| 10476 | struct tls_enc { |
| 10477 | uint32_t sseq; // server sequence number, used in encryption |
| 10478 | uint32_t cseq; // client sequence number, used in decryption |
| 10479 | // keys for AES encryption or ChaCha20 |
| 10480 | uint8_t handshake_secret[32]; |
| 10481 | uint8_t server_write_key[32]; |
| 10482 | uint8_t server_write_iv[12]; |
| 10483 | uint8_t server_finished_key[32]; |
| 10484 | uint8_t client_write_key[32]; |
| 10485 | uint8_t client_write_iv[12]; |
| 10486 | uint8_t client_finished_key[32]; |
| 10487 | }; |
| 10488 | |
| 10489 | // per-connection TLS data |
| 10490 | struct tls_data { |
| 10491 | enum mg_tls_hs_state state; // keep track of connection handshake progress |
| 10492 | |
| 10493 | struct mg_iobuf send; // For the receive path, we're reusing c->rtls |
| 10494 | size_t recv_offset; // While c->rtls contains full records, reuse that |
| 10495 | size_t recv_len; // buffer but point at individual decrypted messages |
| 10496 | |
| 10497 | uint8_t content_type; // Last received record content type |
| 10498 | |
| 10499 | mg_sha256_ctx sha256; // incremental SHA-256 hash for TLS handshake |
| 10500 | |
| 10501 | uint8_t random[32]; // client random from ClientHello |
| 10502 | uint8_t session_id[32]; // client session ID between the handshake states |
| 10503 | uint8_t x25519_cli[32]; // client X25519 key between the handshake states |
| 10504 | uint8_t x25519_sec[32]; // x25519 secret between the handshake states |
| 10505 | |
| 10506 | int skip_verification; // perform checks on server certificate? |
| 10507 | int cert_requested; // client received a CertificateRequest? |
| 10508 | struct mg_str cert_der; // certificate in DER format |
| 10509 | struct mg_str ca_der; // CA certificate |
| 10510 | uint8_t ec_key[32]; // EC private key |
| 10511 | char hostname[254]; // server hostname (client extension) |
| 10512 | |
| 10513 | int is_ec_pubkey; // EC or RSA? |
| 10514 | uint8_t pubkey[512 + 16]; // server EC (64) or RSA (512+exp) public key to |
| 10515 | // verify cert |
| 10516 | size_t pubkeysz; // size of the server public key |
| 10517 | uint8_t sighash[32]; // calculated signature verification hash |
| 10518 | |
| 10519 | struct tls_enc enc; |
| 10520 | }; |
| 10521 | |
| 10522 | #define TLS_RECHDR_SIZE 5 // 1 byte type, 2 bytes version, 2 bytes length |
| 10523 | #define TLS_MSGHDR_SIZE 4 // 1 byte type, 3 bytes length |
| 10524 | |
| 10525 | #ifdef MG_TLS_SSLKEYLOGFILE |
| 10526 | #include <stdio.h> |
| 10527 | static void mg_ssl_key_log(const char *label, uint8_t client_random[32], |
| 10528 | uint8_t *secret, size_t secretsz) { |
| 10529 | char *keylogfile = getenv("SSLKEYLOGFILE"); |
| 10530 | size_t i; |
| 10531 | if (keylogfile != NULL) { |
| 10532 | MG_DEBUG(("Dumping key log into %s", keylogfile)); |
| 10533 | FILE *f = fopen(keylogfile, "a"); |
| 10534 | if (f != NULL) { |
| 10535 | fprintf(f, "%s ", label); |
| 10536 | for (i = 0; i < 32; i++) { |
| 10537 | fprintf(f, "%02x", client_random[i]); |
| 10538 | } |
| 10539 | fprintf(f, " "); |
| 10540 | for (i = 0; i < secretsz; i++) { |
| 10541 | fprintf(f, "%02x", secret[i]); |
| 10542 | } |
| 10543 | fprintf(f, "\n"); |
| 10544 | fclose(f); |
| 10545 | } else { |
| 10546 | MG_ERROR(("Cannot open %s", keylogfile)); |
| 10547 | } |
| 10548 | } |
| 10549 | } |
| 10550 | #endif |
| 10551 | |
| 10552 | // for derived tls keys we need SHA256([0]*32) |
| 10553 | static uint8_t zeros[32] = {0}; |
| 10554 | static uint8_t zeros_sha256_digest[32] = { |
| 10555 | 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, |
| 10556 | 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, |
| 10557 | 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; |
| 10558 | |
| 10559 | // helper to hexdump buffers inline |
| 10560 | static void mg_tls_hexdump(const char *msg, uint8_t *buf, size_t bufsz) { |
| 10561 | MG_VERBOSE(("%s: %M", msg, mg_print_hex, bufsz, buf)); |
| 10562 | } |
| 10563 | |
| 10564 | // helper utilities to parse ASN.1 DER |
| 10565 | struct mg_der_tlv { |
| 10566 | uint8_t type; |
| 10567 | uint32_t len; |
| 10568 | uint8_t *value; |
| 10569 | }; |
| 10570 | |
| 10571 | static int mg_der_parse(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { |
| 10572 | size_t header_len = 2; |
| 10573 | uint32_t len = dersz < 2 ? 0 : der[1]; |
| 10574 | if (dersz < 2) return -1; // Invalid DER |
| 10575 | tlv->type = der[0]; |
| 10576 | if (len > 0x7F) { // long-form length |
| 10577 | uint8_t len_bytes = len & 0x7F; |
| 10578 | if (dersz < (size_t) (2 + len_bytes)) return -1; |
| 10579 | len = 0; |
| 10580 | for (uint8_t i = 0; i < len_bytes; i++) { |
| 10581 | len = (len << 8) | der[2 + i]; |
| 10582 | } |
| 10583 | header_len += len_bytes; |
| 10584 | } |
| 10585 | if (dersz < header_len + len) return -1; |
| 10586 | tlv->len = len; |
| 10587 | tlv->value = der + header_len; |
| 10588 | return (int) (header_len + len); |
| 10589 | } |
| 10590 | |
| 10591 | static int mg_der_next(struct mg_der_tlv *parent, struct mg_der_tlv *child) { |
| 10592 | if (parent->len == 0) return 0; |
| 10593 | int consumed = mg_der_parse(parent->value, parent->len, child); |
| 10594 | if (consumed < 0) return -1; |
| 10595 | parent->value += consumed; |
| 10596 | parent->len -= (uint32_t) consumed; |
| 10597 | return 1; |
| 10598 | } |
| 10599 | |
| 10600 | static int mg_der_find_oid(struct mg_der_tlv *tlv, const uint8_t *oid, |
| 10601 | size_t oid_len, struct mg_der_tlv *found) { |
| 10602 | struct mg_der_tlv parent, child; |
| 10603 | parent = *tlv; |
| 10604 | while (mg_der_next(&parent, &child) > 0) { |
| 10605 | if (child.type == 0x06 && child.len == oid_len && |
| 10606 | memcmp(child.value, oid, oid_len) == 0) { |
| 10607 | return mg_der_next(&parent, found); |
| 10608 | } else if (child.type & 0x20) { |
| 10609 | struct mg_der_tlv sub_parent = child; |
| 10610 | if (mg_der_find_oid(&sub_parent, oid, oid_len, found)) return 1; |
| 10611 | } |
| 10612 | } |
| 10613 | return 0; |
| 10614 | } |
| 10615 | |
| 10616 | #if 0 |
| 10617 | static void mg_der_debug(struct mg_der_tlv *tlv, int depth) { |
| 10618 | MG_DEBUG(("> %.*sd=%d Type: 0x%02X, Length: %u\n", depth * 4, " ", depth, |
| 10619 | tlv->type, tlv->len)); |
| 10620 | |
| 10621 | if (tlv->type & 0x20) { // Constructed: recurse into children |
| 10622 | struct mg_der_tlv child; |
| 10623 | struct mg_der_tlv parent = *tlv; |
| 10624 | while (mg_der_next(&parent, &child) > 0) { |
| 10625 | mg_der_debug(&child, depth + 1); |
| 10626 | } |
| 10627 | } |
| 10628 | } |
| 10629 | #endif |
| 10630 | |
| 10631 | // parse DER into a TLV record |
| 10632 | static int mg_der_to_tlv(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { |
| 10633 | if (dersz < 2) { |
| 10634 | return -1; |
| 10635 | } |
| 10636 | tlv->type = der[0]; |
| 10637 | tlv->len = der[1]; |
| 10638 | tlv->value = der + 2; |
| 10639 | if (tlv->len > 0x7f) { |
| 10640 | uint32_t i, n = tlv->len - 0x80; |
| 10641 | tlv->len = 0; |
| 10642 | for (i = 0; i < n; i++) { |
| 10643 | tlv->len = (tlv->len << 8) | (der[2 + i]); |
| 10644 | } |
| 10645 | tlv->value = der + 2 + n; |
| 10646 | } |
| 10647 | if (der + dersz < tlv->value + tlv->len) { |
| 10648 | return -1; |
| 10649 | } |
| 10650 | return 0; |
| 10651 | } |
| 10652 | |
| 10653 | // Did we receive a full TLS record in the c->rtls buffer? |
| 10654 | static bool mg_tls_got_record(struct mg_connection *c) { |
| 10655 | return c->rtls.len >= (size_t) TLS_RECHDR_SIZE && |
| 10656 | c->rtls.len >= |
| 10657 | (size_t) (TLS_RECHDR_SIZE + MG_LOAD_BE16(c->rtls.buf + 3)); |
| 10658 | } |
| 10659 | |
| 10660 | // Remove a single TLS record from the recv buffer |
| 10661 | static void mg_tls_drop_record(struct mg_connection *c) { |
| 10662 | struct mg_iobuf *rio = &c->rtls; |
| 10663 | uint16_t n = MG_LOAD_BE16(rio->buf + 3) + TLS_RECHDR_SIZE; |
| 10664 | mg_iobuf_del(rio, 0, n); |
| 10665 | } |
| 10666 | |
| 10667 | // Remove a single TLS message from decrypted buffer, remove the wrapping |
| 10668 | // record if it was the last message within a record |
| 10669 | static void mg_tls_drop_message(struct mg_connection *c) { |
| 10670 | uint32_t len; |
| 10671 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10672 | unsigned char *recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 10673 | if (tls->recv_len == 0) return; |
| 10674 | len = MG_LOAD_BE24(recv_buf + 1) + TLS_MSGHDR_SIZE; |
| 10675 | if (tls->recv_len < len) { |
| 10676 | mg_error(c, "wrong size"); |
| 10677 | return; |
| 10678 | } |
| 10679 | mg_sha256_update(&tls->sha256, recv_buf, len); |
| 10680 | tls->recv_offset += len; |
| 10681 | tls->recv_len -= len; |
| 10682 | if (tls->recv_len == 0) { |
| 10683 | mg_tls_drop_record(c); |
| 10684 | } |
| 10685 | } |
| 10686 | |
| 10687 | // TLS1.3 secret derivation based on the key label |
| 10688 | static void mg_tls_derive_secret(const char *label, uint8_t *key, size_t keysz, |
| 10689 | uint8_t *data, size_t datasz, uint8_t *hash, |
| 10690 | size_t hashsz) { |
| 10691 | size_t labelsz = strlen(label); |
| 10692 | uint8_t secret[32]; |
| 10693 | uint8_t packed[256] = {0, (uint8_t) hashsz, (uint8_t) labelsz}; |
| 10694 | // TODO: assert lengths of label, key, data and hash |
| 10695 | if (labelsz > 0) memmove(packed + 3, label, labelsz); |
| 10696 | packed[3 + labelsz] = (uint8_t) datasz; |
| 10697 | if (datasz > 0) memmove(packed + labelsz + 4, data, datasz); |
| 10698 | packed[4 + labelsz + datasz] = 1; |
| 10699 | |
| 10700 | mg_hmac_sha256(secret, key, keysz, packed, 5 + labelsz + datasz); |
| 10701 | memmove(hash, secret, hashsz); |
| 10702 | } |
| 10703 | |
| 10704 | // at this point we have x25519 shared secret, we can generate a set of derived |
| 10705 | // handshake encryption keys |
| 10706 | static void mg_tls_generate_handshake_keys(struct mg_connection *c) { |
| 10707 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10708 | |
| 10709 | mg_sha256_ctx sha256; |
| 10710 | uint8_t early_secret[32]; |
| 10711 | uint8_t pre_extract_secret[32]; |
| 10712 | uint8_t hello_hash[32]; |
| 10713 | uint8_t server_hs_secret[32]; |
| 10714 | uint8_t client_hs_secret[32]; |
| 10715 | #if CHACHA20 |
| 10716 | const size_t keysz = 32; |
| 10717 | #else |
| 10718 | const size_t keysz = 16; |
| 10719 | #endif |
| 10720 | |
| 10721 | mg_hmac_sha256(early_secret, NULL, 0, zeros, sizeof(zeros)); |
| 10722 | mg_tls_derive_secret("tls13 derived", early_secret, 32, zeros_sha256_digest, |
| 10723 | 32, pre_extract_secret, 32); |
| 10724 | mg_hmac_sha256(tls->enc.handshake_secret, pre_extract_secret, |
| 10725 | sizeof(pre_extract_secret), tls->x25519_sec, |
| 10726 | sizeof(tls->x25519_sec)); |
| 10727 | mg_tls_hexdump("hs secret", tls->enc.handshake_secret, 32); |
| 10728 | |
| 10729 | // mg_sha256_final is not idempotent, need to copy sha256 context to calculate |
| 10730 | // the digest |
| 10731 | memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); |
| 10732 | mg_sha256_final(hello_hash, &sha256); |
| 10733 | |
| 10734 | mg_tls_hexdump("hello hash", hello_hash, 32); |
| 10735 | // derive keys needed for the rest of the handshake |
| 10736 | mg_tls_derive_secret("tls13 s hs traffic", tls->enc.handshake_secret, 32, |
| 10737 | hello_hash, 32, server_hs_secret, 32); |
| 10738 | mg_tls_derive_secret("tls13 c hs traffic", tls->enc.handshake_secret, 32, |
| 10739 | hello_hash, 32, client_hs_secret, 32); |
| 10740 | |
| 10741 | mg_tls_derive_secret("tls13 key", server_hs_secret, 32, NULL, 0, |
| 10742 | tls->enc.server_write_key, keysz); |
| 10743 | mg_tls_derive_secret("tls13 iv", server_hs_secret, 32, NULL, 0, |
| 10744 | tls->enc.server_write_iv, 12); |
| 10745 | mg_tls_derive_secret("tls13 finished", server_hs_secret, 32, NULL, 0, |
| 10746 | tls->enc.server_finished_key, 32); |
| 10747 | |
| 10748 | mg_tls_derive_secret("tls13 key", client_hs_secret, 32, NULL, 0, |
| 10749 | tls->enc.client_write_key, keysz); |
| 10750 | mg_tls_derive_secret("tls13 iv", client_hs_secret, 32, NULL, 0, |
| 10751 | tls->enc.client_write_iv, 12); |
| 10752 | mg_tls_derive_secret("tls13 finished", client_hs_secret, 32, NULL, 0, |
| 10753 | tls->enc.client_finished_key, 32); |
| 10754 | |
| 10755 | mg_tls_hexdump("s hs traffic", server_hs_secret, 32); |
| 10756 | mg_tls_hexdump("s key", tls->enc.server_write_key, keysz); |
| 10757 | mg_tls_hexdump("s iv", tls->enc.server_write_iv, 12); |
| 10758 | mg_tls_hexdump("s finished", tls->enc.server_finished_key, 32); |
| 10759 | mg_tls_hexdump("c hs traffic", client_hs_secret, 32); |
| 10760 | mg_tls_hexdump("c key", tls->enc.client_write_key, keysz); |
| 10761 | mg_tls_hexdump("c iv", tls->enc.client_write_iv, 12); |
| 10762 | mg_tls_hexdump("c finished", tls->enc.client_finished_key, 32); |
| 10763 | |
| 10764 | #ifdef MG_TLS_SSLKEYLOGFILE |
| 10765 | mg_ssl_key_log("SERVER_HANDSHAKE_TRAFFIC_SECRET", tls->random, |
| 10766 | server_hs_secret, 32); |
| 10767 | mg_ssl_key_log("CLIENT_HANDSHAKE_TRAFFIC_SECRET", tls->random, |
| 10768 | client_hs_secret, 32); |
| 10769 | #endif |
| 10770 | } |
| 10771 | |
| 10772 | static void mg_tls_generate_application_keys(struct mg_connection *c) { |
| 10773 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10774 | uint8_t hash[32]; |
| 10775 | uint8_t premaster_secret[32]; |
| 10776 | uint8_t master_secret[32]; |
| 10777 | uint8_t server_secret[32]; |
| 10778 | uint8_t client_secret[32]; |
| 10779 | #if CHACHA20 |
| 10780 | const size_t keysz = 32; |
| 10781 | #else |
| 10782 | const size_t keysz = 16; |
| 10783 | #endif |
| 10784 | |
| 10785 | mg_sha256_ctx sha256; |
| 10786 | memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); |
| 10787 | mg_sha256_final(hash, &sha256); |
| 10788 | |
| 10789 | mg_tls_derive_secret("tls13 derived", tls->enc.handshake_secret, 32, |
| 10790 | zeros_sha256_digest, 32, premaster_secret, 32); |
| 10791 | mg_hmac_sha256(master_secret, premaster_secret, 32, zeros, 32); |
| 10792 | |
| 10793 | mg_tls_derive_secret("tls13 s ap traffic", master_secret, 32, hash, 32, |
| 10794 | server_secret, 32); |
| 10795 | mg_tls_derive_secret("tls13 key", server_secret, 32, NULL, 0, |
| 10796 | tls->enc.server_write_key, keysz); |
| 10797 | mg_tls_derive_secret("tls13 iv", server_secret, 32, NULL, 0, |
| 10798 | tls->enc.server_write_iv, 12); |
| 10799 | mg_tls_derive_secret("tls13 c ap traffic", master_secret, 32, hash, 32, |
| 10800 | client_secret, 32); |
| 10801 | mg_tls_derive_secret("tls13 key", client_secret, 32, NULL, 0, |
| 10802 | tls->enc.client_write_key, keysz); |
| 10803 | mg_tls_derive_secret("tls13 iv", client_secret, 32, NULL, 0, |
| 10804 | tls->enc.client_write_iv, 12); |
| 10805 | |
| 10806 | mg_tls_hexdump("s ap traffic", server_secret, 32); |
| 10807 | mg_tls_hexdump("s key", tls->enc.server_write_key, keysz); |
| 10808 | mg_tls_hexdump("s iv", tls->enc.server_write_iv, 12); |
| 10809 | mg_tls_hexdump("s finished", tls->enc.server_finished_key, 32); |
| 10810 | mg_tls_hexdump("c ap traffic", client_secret, 32); |
| 10811 | mg_tls_hexdump("c key", tls->enc.client_write_key, keysz); |
| 10812 | mg_tls_hexdump("c iv", tls->enc.client_write_iv, 12); |
| 10813 | mg_tls_hexdump("c finished", tls->enc.client_finished_key, 32); |
| 10814 | tls->enc.sseq = tls->enc.cseq = 0; |
| 10815 | |
| 10816 | #ifdef MG_TLS_SSLKEYLOGFILE |
| 10817 | mg_ssl_key_log("SERVER_TRAFFIC_SECRET_0", tls->random, server_secret, 32); |
| 10818 | mg_ssl_key_log("CLIENT_TRAFFIC_SECRET_0", tls->random, client_secret, 32); |
| 10819 | #endif |
| 10820 | } |
| 10821 | |
| 10822 | // AES GCM encryption of the message + put encoded data into the write buffer |
| 10823 | static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg, |
| 10824 | size_t msgsz, uint8_t msgtype) { |
| 10825 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10826 | struct mg_iobuf *wio = &tls->send; |
| 10827 | uint8_t *outmsg; |
| 10828 | uint8_t *tag; |
| 10829 | size_t encsz = msgsz + 16 + 1; |
| 10830 | uint8_t hdr[5] = {MG_TLS_APP_DATA, 0x03, 0x03, |
| 10831 | (uint8_t) ((encsz >> 8) & 0xff), (uint8_t) (encsz & 0xff)}; |
| 10832 | uint8_t associated_data[5] = {MG_TLS_APP_DATA, 0x03, 0x03, |
| 10833 | (uint8_t) ((encsz >> 8) & 0xff), |
| 10834 | (uint8_t) (encsz & 0xff)}; |
| 10835 | uint8_t nonce[12]; |
| 10836 | |
| 10837 | uint32_t seq = c->is_client ? tls->enc.cseq : tls->enc.sseq; |
| 10838 | uint8_t *key = |
| 10839 | c->is_client ? tls->enc.client_write_key : tls->enc.server_write_key; |
| 10840 | uint8_t *iv = |
| 10841 | c->is_client ? tls->enc.client_write_iv : tls->enc.server_write_iv; |
| 10842 | |
| 10843 | #if !CHACHA20 |
| 10844 | mg_gcm_initialize(); |
| 10845 | #endif |
| 10846 | |
| 10847 | memmove(nonce, iv, sizeof(nonce)); |
| 10848 | nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); |
| 10849 | nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); |
| 10850 | nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); |
| 10851 | nonce[11] ^= (uint8_t) ((seq) &255U); |
| 10852 | |
| 10853 | mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)); |
| 10854 | mg_iobuf_resize(wio, wio->len + encsz); |
| 10855 | outmsg = wio->buf + wio->len; |
| 10856 | tag = wio->buf + wio->len + msgsz + 1; |
| 10857 | memmove(outmsg, msg, msgsz); |
| 10858 | outmsg[msgsz] = msgtype; |
| 10859 | #if CHACHA20 |
| 10860 | (void) tag; // tag is only used in aes gcm |
| 10861 | { |
| 10862 | size_t maxlen = MG_IO_SIZE > 16384 ? 16384 : MG_IO_SIZE; |
| 10863 | uint8_t *enc = (uint8_t *) calloc(1, maxlen + 256 + 1); |
| 10864 | if (enc == NULL) { |
| 10865 | mg_error(c, "TLS OOM"); |
| 10866 | return; |
| 10867 | } else { |
| 10868 | size_t n = mg_chacha20_poly1305_encrypt(enc, key, nonce, associated_data, |
| 10869 | sizeof(associated_data), outmsg, |
| 10870 | msgsz + 1); |
| 10871 | memmove(outmsg, enc, n); |
| 10872 | free(enc); |
| 10873 | } |
| 10874 | } |
| 10875 | #else |
| 10876 | mg_aes_gcm_encrypt(outmsg, outmsg, msgsz + 1, key, 16, nonce, sizeof(nonce), |
| 10877 | associated_data, sizeof(associated_data), tag, 16); |
| 10878 | #endif |
| 10879 | c->is_client ? tls->enc.cseq++ : tls->enc.sseq++; |
| 10880 | wio->len += encsz; |
| 10881 | } |
| 10882 | |
| 10883 | // read an encrypted record, decrypt it in place |
| 10884 | static int mg_tls_recv_record(struct mg_connection *c) { |
| 10885 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10886 | struct mg_iobuf *rio = &c->rtls; |
| 10887 | uint16_t msgsz; |
| 10888 | uint8_t *msg; |
| 10889 | uint8_t nonce[12]; |
| 10890 | int r; |
| 10891 | |
| 10892 | uint32_t seq = c->is_client ? tls->enc.sseq : tls->enc.cseq; |
| 10893 | uint8_t *key = |
| 10894 | c->is_client ? tls->enc.server_write_key : tls->enc.client_write_key; |
| 10895 | uint8_t *iv = |
| 10896 | c->is_client ? tls->enc.server_write_iv : tls->enc.client_write_iv; |
| 10897 | |
| 10898 | if (tls->recv_len > 0) { |
| 10899 | return 0; /* some data from previous record is still present */ |
| 10900 | } |
| 10901 | for (;;) { |
| 10902 | if (!mg_tls_got_record(c)) { |
| 10903 | return MG_IO_WAIT; |
| 10904 | } |
| 10905 | if (rio->buf[0] == MG_TLS_APP_DATA) { |
| 10906 | break; |
| 10907 | } else if (rio->buf[0] == |
| 10908 | MG_TLS_CHANGE_CIPHER) { // Skip ChangeCipher messages |
| 10909 | mg_tls_drop_record(c); |
| 10910 | } else if (rio->buf[0] == MG_TLS_ALERT) { // Skip Alerts |
| 10911 | MG_INFO(("TLS ALERT packet received")); |
| 10912 | mg_tls_drop_record(c); |
| 10913 | } else { |
| 10914 | mg_error(c, "unexpected packet"); |
| 10915 | return -1; |
| 10916 | } |
| 10917 | } |
| 10918 | |
| 10919 | msgsz = MG_LOAD_BE16(rio->buf + 3); |
| 10920 | msg = rio->buf + 5; |
| 10921 | if (msgsz < 16) { |
| 10922 | mg_error(c, "wrong size"); |
| 10923 | return -1; |
| 10924 | } |
| 10925 | |
| 10926 | memmove(nonce, iv, sizeof(nonce)); |
| 10927 | nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); |
| 10928 | nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); |
| 10929 | nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); |
| 10930 | nonce[11] ^= (uint8_t) ((seq) &255U); |
| 10931 | #if CHACHA20 |
| 10932 | { |
| 10933 | uint8_t *dec = (uint8_t *) calloc(1, msgsz); |
| 10934 | size_t n; |
| 10935 | if (dec == NULL) { |
| 10936 | mg_error(c, "TLS OOM"); |
| 10937 | return -1; |
| 10938 | } |
| 10939 | n = mg_chacha20_poly1305_decrypt(dec, key, nonce, msg, msgsz); |
| 10940 | memmove(msg, dec, n); |
| 10941 | free(dec); |
| 10942 | } |
| 10943 | #else |
| 10944 | mg_gcm_initialize(); |
| 10945 | mg_aes_gcm_decrypt(msg, msg, msgsz - 16, key, 16, nonce, sizeof(nonce)); |
| 10946 | #endif |
| 10947 | |
| 10948 | r = msgsz - 16 - 1; |
| 10949 | tls->content_type = msg[msgsz - 16 - 1]; |
| 10950 | tls->recv_offset = (size_t) msg - (size_t) rio->buf; |
| 10951 | tls->recv_len = (size_t) msgsz - 16 - 1; |
| 10952 | c->is_client ? tls->enc.sseq++ : tls->enc.cseq++; |
| 10953 | return r; |
| 10954 | } |
| 10955 | |
| 10956 | static void mg_tls_calc_cert_verify_hash(struct mg_connection *c, |
| 10957 | uint8_t hash[32], int is_client) { |
| 10958 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10959 | uint8_t server_context[34] = "TLS 1.3, server CertificateVerify"; |
| 10960 | uint8_t client_context[34] = "TLS 1.3, client CertificateVerify"; |
| 10961 | uint8_t sig_content[130]; |
| 10962 | mg_sha256_ctx sha256; |
| 10963 | |
| 10964 | memset(sig_content, 0x20, 64); |
| 10965 | if (is_client) { |
| 10966 | memmove(sig_content + 64, client_context, sizeof(client_context)); |
| 10967 | } else { |
| 10968 | memmove(sig_content + 64, server_context, sizeof(server_context)); |
| 10969 | } |
| 10970 | |
| 10971 | memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); |
| 10972 | mg_sha256_final(sig_content + 98, &sha256); |
| 10973 | |
| 10974 | mg_sha256_init(&sha256); |
| 10975 | mg_sha256_update(&sha256, sig_content, sizeof(sig_content)); |
| 10976 | mg_sha256_final(hash, &sha256); |
| 10977 | } |
| 10978 | |
| 10979 | // read and parse ClientHello record |
| 10980 | static int mg_tls_server_recv_hello(struct mg_connection *c) { |
| 10981 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 10982 | struct mg_iobuf *rio = &c->rtls; |
| 10983 | uint8_t session_id_len; |
| 10984 | uint16_t j; |
| 10985 | uint16_t cipher_suites_len; |
| 10986 | uint16_t ext_len; |
| 10987 | uint8_t *ext; |
| 10988 | uint16_t msgsz; |
| 10989 | |
| 10990 | if (!mg_tls_got_record(c)) { |
| 10991 | return MG_IO_WAIT; |
| 10992 | } |
| 10993 | if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->buf[5] != MG_TLS_CLIENT_HELLO) { |
| 10994 | mg_error(c, "not a client hello packet"); |
| 10995 | return -1; |
| 10996 | } |
| 10997 | msgsz = MG_LOAD_BE16(rio->buf + 3); |
| 10998 | mg_sha256_update(&tls->sha256, rio->buf + 5, msgsz); |
| 10999 | // store client random |
| 11000 | memmove(tls->random, rio->buf + 11, sizeof(tls->random)); |
| 11001 | // store session_id |
| 11002 | session_id_len = rio->buf[43]; |
| 11003 | if (session_id_len == sizeof(tls->session_id)) { |
| 11004 | memmove(tls->session_id, rio->buf + 44, session_id_len); |
| 11005 | } else if (session_id_len != 0) { |
| 11006 | MG_INFO(("bad session id len")); |
| 11007 | } |
| 11008 | cipher_suites_len = MG_LOAD_BE16(rio->buf + 44 + session_id_len); |
| 11009 | if (cipher_suites_len > (rio->len - 46 - session_id_len)) goto fail; |
| 11010 | ext_len = MG_LOAD_BE16(rio->buf + 48 + session_id_len + cipher_suites_len); |
| 11011 | ext = rio->buf + 50 + session_id_len + cipher_suites_len; |
| 11012 | if (ext_len > (rio->len - 50 - session_id_len - cipher_suites_len)) goto fail; |
| 11013 | for (j = 0; j < ext_len;) { |
| 11014 | uint16_t k; |
| 11015 | uint16_t key_exchange_len; |
| 11016 | uint8_t *key_exchange; |
| 11017 | uint16_t n = MG_LOAD_BE16(ext + j + 2); |
| 11018 | if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore |
| 11019 | j += (uint16_t) (n + 4); |
| 11020 | continue; |
| 11021 | } |
| 11022 | key_exchange_len = MG_LOAD_BE16(ext + j + 4); |
| 11023 | key_exchange = ext + j + 6; |
| 11024 | if (key_exchange_len > |
| 11025 | rio->len - (uint16_t) ((size_t) key_exchange - (size_t) rio->buf)) |
| 11026 | goto fail; |
| 11027 | for (k = 0; k < key_exchange_len;) { |
| 11028 | uint16_t m = MG_LOAD_BE16(key_exchange + k + 2); |
| 11029 | if (m > (key_exchange_len - k - 4)) goto fail; |
| 11030 | if (m == 32 && key_exchange[k] == 0x00 && key_exchange[k + 1] == 0x1d) { |
| 11031 | memmove(tls->x25519_cli, key_exchange + k + 4, m); |
| 11032 | mg_tls_drop_record(c); |
| 11033 | return 0; |
| 11034 | } |
| 11035 | k += (uint16_t) (m + 4); |
| 11036 | } |
| 11037 | j += (uint16_t) (n + 4); |
| 11038 | } |
| 11039 | fail: |
| 11040 | mg_error(c, "bad client hello"); |
| 11041 | return -1; |
| 11042 | } |
| 11043 | |
| 11044 | #define PLACEHOLDER_8B 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' |
| 11045 | #define PLACEHOLDER_16B PLACEHOLDER_8B, PLACEHOLDER_8B |
| 11046 | #define PLACEHOLDER_32B PLACEHOLDER_16B, PLACEHOLDER_16B |
| 11047 | |
| 11048 | // put ServerHello record into wio buffer |
| 11049 | static void mg_tls_server_send_hello(struct mg_connection *c) { |
| 11050 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11051 | struct mg_iobuf *wio = &tls->send; |
| 11052 | |
| 11053 | // clang-format off |
| 11054 | uint8_t msg_server_hello[122] = { |
| 11055 | // server hello, tls 1.2 |
| 11056 | 0x02, 0x00, 0x00, 0x76, 0x03, 0x03, |
| 11057 | // random (32 bytes) |
| 11058 | PLACEHOLDER_32B, |
| 11059 | // session ID length + session ID (32 bytes) |
| 11060 | 0x20, PLACEHOLDER_32B, |
| 11061 | #if defined(CHACHA20) && CHACHA20 |
| 11062 | // TLS_CHACHA20_POLY1305_SHA256 + no compression |
| 11063 | 0x13, 0x03, 0x00, |
| 11064 | #else |
| 11065 | // TLS_AES_128_GCM_SHA256 + no compression |
| 11066 | 0x13, 0x01, 0x00, |
| 11067 | #endif |
| 11068 | // extensions + keyshare |
| 11069 | 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, |
| 11070 | // x25519 keyshare |
| 11071 | PLACEHOLDER_32B, |
| 11072 | // supported versions (tls1.3 == 0x304) |
| 11073 | 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04}; |
| 11074 | // clang-format on |
| 11075 | |
| 11076 | // calculate keyshare |
| 11077 | uint8_t x25519_pub[X25519_BYTES]; |
| 11078 | uint8_t x25519_prv[X25519_BYTES]; |
| 11079 | if (!mg_random(x25519_prv, sizeof(x25519_prv))) mg_error(c, "RNG"); |
| 11080 | mg_tls_x25519(x25519_pub, x25519_prv, X25519_BASE_POINT, 1); |
| 11081 | mg_tls_x25519(tls->x25519_sec, x25519_prv, tls->x25519_cli, 1); |
| 11082 | mg_tls_hexdump("s x25519 sec", tls->x25519_sec, sizeof(tls->x25519_sec)); |
| 11083 | |
| 11084 | // fill in the gaps: random + session ID + keyshare |
| 11085 | memmove(msg_server_hello + 6, tls->random, sizeof(tls->random)); |
| 11086 | memmove(msg_server_hello + 39, tls->session_id, sizeof(tls->session_id)); |
| 11087 | memmove(msg_server_hello + 84, x25519_pub, sizeof(x25519_pub)); |
| 11088 | |
| 11089 | // server hello message |
| 11090 | mg_iobuf_add(wio, wio->len, "\x16\x03\x03\x00\x7a", 5); |
| 11091 | mg_iobuf_add(wio, wio->len, msg_server_hello, sizeof(msg_server_hello)); |
| 11092 | mg_sha256_update(&tls->sha256, msg_server_hello, sizeof(msg_server_hello)); |
| 11093 | |
| 11094 | // change cipher message |
| 11095 | mg_iobuf_add(wio, wio->len, "\x14\x03\x03\x00\x01\x01", 6); |
| 11096 | } |
| 11097 | |
| 11098 | static void mg_tls_server_send_ext(struct mg_connection *c) { |
| 11099 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11100 | // server extensions |
| 11101 | uint8_t ext[6] = {0x08, 0, 0, 2, 0, 0}; |
| 11102 | mg_sha256_update(&tls->sha256, ext, sizeof(ext)); |
| 11103 | mg_tls_encrypt(c, ext, sizeof(ext), MG_TLS_HANDSHAKE); |
| 11104 | } |
| 11105 | |
| 11106 | static void mg_tls_server_send_cert(struct mg_connection *c) { |
| 11107 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11108 | int send_ca = !c->is_client && tls->ca_der.len > 0; |
| 11109 | // server DER certificate + CA (optional) |
| 11110 | size_t n = tls->cert_der.len + (send_ca ? tls->ca_der.len + 5 : 0); |
| 11111 | uint8_t *cert = (uint8_t *) calloc(1, 13 + n); |
| 11112 | if (cert == NULL) { |
| 11113 | mg_error(c, "tls cert oom"); |
| 11114 | return; |
| 11115 | } |
| 11116 | cert[0] = 0x0b; // handshake header |
| 11117 | MG_STORE_BE24(cert + 1, n + 9); |
| 11118 | cert[4] = 0; // request context |
| 11119 | MG_STORE_BE24(cert + 5, n + 5); // 3 bytes: cert (s) length |
| 11120 | MG_STORE_BE24(cert + 8, tls->cert_der.len); // 3 bytes: first cert len |
| 11121 | // bytes 11+ are certificate in DER format |
| 11122 | memmove(cert + 11, tls->cert_der.buf, tls->cert_der.len); |
| 11123 | MG_STORE_BE16(cert + 11 + tls->cert_der.len, |
| 11124 | 0); // certificate extensions (none) |
| 11125 | if (send_ca) { |
| 11126 | size_t offset = 13 + tls->cert_der.len; |
| 11127 | MG_STORE_BE24(cert + offset, tls->ca_der.len); // 3 bytes: CA cert length |
| 11128 | memmove(cert + offset + 3, tls->ca_der.buf, |
| 11129 | tls->ca_der.len); // CA cert data |
| 11130 | MG_STORE_BE16(cert + 11 + n, 0); // certificate extensions (none) |
| 11131 | } |
| 11132 | mg_sha256_update(&tls->sha256, cert, 13 + n); |
| 11133 | mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE); |
| 11134 | free(cert); |
| 11135 | } |
| 11136 | |
| 11137 | // type adapter between uECC hash context and our sha256 implementation |
| 11138 | typedef struct SHA256_HashContext { |
| 11139 | MG_UECC_HashContext uECC; |
| 11140 | mg_sha256_ctx ctx; |
| 11141 | } SHA256_HashContext; |
| 11142 | |
| 11143 | static void init_SHA256(const MG_UECC_HashContext *base) { |
| 11144 | SHA256_HashContext *c = (SHA256_HashContext *) base; |
| 11145 | mg_sha256_init(&c->ctx); |
| 11146 | } |
| 11147 | |
| 11148 | static void update_SHA256(const MG_UECC_HashContext *base, |
| 11149 | const uint8_t *message, unsigned message_size) { |
| 11150 | SHA256_HashContext *c = (SHA256_HashContext *) base; |
| 11151 | mg_sha256_update(&c->ctx, message, message_size); |
| 11152 | } |
| 11153 | static void finish_SHA256(const MG_UECC_HashContext *base, |
| 11154 | uint8_t *hash_result) { |
| 11155 | SHA256_HashContext *c = (SHA256_HashContext *) base; |
| 11156 | mg_sha256_final(hash_result, &c->ctx); |
| 11157 | } |
| 11158 | |
| 11159 | static void mg_tls_send_cert_verify(struct mg_connection *c, int is_client) { |
| 11160 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11161 | // server certificate verify packet |
| 11162 | uint8_t verify[82] = {0x0f, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00}; |
| 11163 | size_t sigsz, verifysz = 0; |
| 11164 | uint8_t hash[32] = {0}, tmp[2 * 32 + 64] = {0}; |
| 11165 | struct SHA256_HashContext ctx = { |
| 11166 | {&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}, |
| 11167 | {{0}, 0, 0, {0}}}; |
| 11168 | int neg1, neg2; |
| 11169 | uint8_t sig[64] = {0}; |
| 11170 | |
| 11171 | mg_tls_calc_cert_verify_hash(c, (uint8_t *) hash, is_client); |
| 11172 | |
| 11173 | mg_uecc_sign_deterministic(tls->ec_key, hash, sizeof(hash), &ctx.uECC, sig, |
| 11174 | mg_uecc_secp256r1()); |
| 11175 | |
| 11176 | neg1 = !!(sig[0] & 0x80); |
| 11177 | neg2 = !!(sig[32] & 0x80); |
| 11178 | verify[8] = 0x30; // ASN.1 SEQUENCE |
| 11179 | verify[9] = (uint8_t) (68 + neg1 + neg2); |
| 11180 | verify[10] = 0x02; // ASN.1 INTEGER |
| 11181 | verify[11] = (uint8_t) (32 + neg1); |
| 11182 | memmove(verify + 12 + neg1, sig, 32); |
| 11183 | verify[12 + 32 + neg1] = 0x02; // ASN.1 INTEGER |
| 11184 | verify[13 + 32 + neg1] = (uint8_t) (32 + neg2); |
| 11185 | memmove(verify + 14 + 32 + neg1 + neg2, sig + 32, 32); |
| 11186 | |
| 11187 | sigsz = (size_t) (70 + neg1 + neg2); |
| 11188 | verifysz = 8U + sigsz; |
| 11189 | verify[3] = (uint8_t) (sigsz + 4); |
| 11190 | verify[7] = (uint8_t) sigsz; |
| 11191 | |
| 11192 | mg_sha256_update(&tls->sha256, verify, verifysz); |
| 11193 | mg_tls_encrypt(c, verify, verifysz, MG_TLS_HANDSHAKE); |
| 11194 | } |
| 11195 | |
| 11196 | static void mg_tls_server_send_finish(struct mg_connection *c) { |
| 11197 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11198 | struct mg_iobuf *wio = &tls->send; |
| 11199 | mg_sha256_ctx sha256; |
| 11200 | uint8_t hash[32]; |
| 11201 | uint8_t finish[36] = {0x14, 0, 0, 32}; |
| 11202 | memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); |
| 11203 | mg_sha256_final(hash, &sha256); |
| 11204 | mg_hmac_sha256(finish + 4, tls->enc.server_finished_key, 32, hash, 32); |
| 11205 | mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); |
| 11206 | mg_io_send(c, wio->buf, wio->len); |
| 11207 | wio->len = 0; |
| 11208 | |
| 11209 | mg_sha256_update(&tls->sha256, finish, sizeof(finish)); |
| 11210 | } |
| 11211 | |
| 11212 | static int mg_tls_server_recv_finish(struct mg_connection *c) { |
| 11213 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11214 | unsigned char *recv_buf; |
| 11215 | // we have to backup sha256 value to restore it later, since Finished record |
| 11216 | // is exceptional and is not supposed to be added to the rolling hash |
| 11217 | // calculation. |
| 11218 | mg_sha256_ctx sha256 = tls->sha256; |
| 11219 | if (mg_tls_recv_record(c) < 0) { |
| 11220 | return -1; |
| 11221 | } |
| 11222 | recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 11223 | if (recv_buf[0] != MG_TLS_FINISHED) { |
| 11224 | mg_error(c, "expected Finish but got msg 0x%02x", recv_buf[0]); |
| 11225 | return -1; |
| 11226 | } |
| 11227 | mg_tls_drop_message(c); |
| 11228 | |
| 11229 | // restore hash |
| 11230 | tls->sha256 = sha256; |
| 11231 | return 0; |
| 11232 | } |
| 11233 | |
| 11234 | static void mg_tls_client_send_hello(struct mg_connection *c) { |
| 11235 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11236 | struct mg_iobuf *wio = &tls->send; |
| 11237 | |
| 11238 | uint8_t x25519_pub[X25519_BYTES]; |
| 11239 | |
| 11240 | // signature algorithms we actually support: |
| 11241 | // rsa_pkcs1_sha256, rsa_pss_rsae_sha256 and ecdsa_secp256r1_sha256 |
| 11242 | uint8_t secp256r1_sig_algs[12] = { |
| 11243 | 0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, |
| 11244 | }; |
| 11245 | // all popular signature algorithms (if we don't care about verification) |
| 11246 | uint8_t all_sig_algs[34] = { |
| 11247 | 0x00, 0x0d, 0x00, 0x1e, 0x00, 0x1c, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, |
| 11248 | 0x08, 0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, |
| 11249 | 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01}; |
| 11250 | uint8_t server_name_ext[9] = {0x00, 0x00, 0x00, 0xfe, 0x00, |
| 11251 | 0xfe, 0x00, 0x00, 0xfe}; |
| 11252 | |
| 11253 | // clang-format off |
| 11254 | uint8_t msg_client_hello[145] = { |
| 11255 | // TLS Client Hello header reported as TLS1.2 (5) |
| 11256 | 0x16, 0x03, 0x03, 0x00, 0xfe, |
| 11257 | // client hello, tls 1.2 (6) |
| 11258 | 0x01, 0x00, 0x00, 0x8c, 0x03, 0x03, |
| 11259 | // random (32 bytes) |
| 11260 | PLACEHOLDER_32B, |
| 11261 | // session ID length + session ID (32 bytes) |
| 11262 | 0x20, PLACEHOLDER_32B, 0x00, |
| 11263 | 0x02, // size = 2 bytes |
| 11264 | #if defined(CHACHA20) && CHACHA20 |
| 11265 | // TLS_CHACHA20_POLY1305_SHA256 |
| 11266 | 0x13, 0x03, |
| 11267 | #else |
| 11268 | // TLS_AES_128_GCM_SHA256 |
| 11269 | 0x13, 0x01, |
| 11270 | #endif |
| 11271 | // no compression |
| 11272 | 0x01, 0x00, |
| 11273 | // extensions + keyshare |
| 11274 | 0x00, 0xfe, |
| 11275 | // x25519 keyshare |
| 11276 | 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, |
| 11277 | PLACEHOLDER_32B, |
| 11278 | // supported groups (x25519) |
| 11279 | 0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x1d, |
| 11280 | // supported versions (tls1.3 == 0x304) |
| 11281 | 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, |
| 11282 | // session ticket (none) |
| 11283 | 0x00, 0x23, 0x00, 0x00, // 144 bytes till here |
| 11284 | }; |
| 11285 | // clang-format on |
| 11286 | const char *hostname = tls->hostname; |
| 11287 | size_t hostnamesz = strlen(tls->hostname); |
| 11288 | size_t hostname_extsz = hostnamesz ? hostnamesz + 9 : 0; |
| 11289 | uint8_t *sig_alg = tls->skip_verification ? all_sig_algs : secp256r1_sig_algs; |
| 11290 | size_t sig_alg_sz = tls->skip_verification ? sizeof(all_sig_algs) |
| 11291 | : sizeof(secp256r1_sig_algs); |
| 11292 | |
| 11293 | // patch ClientHello with correct hostname ext length (if any) |
| 11294 | MG_STORE_BE16(msg_client_hello + 3, |
| 11295 | hostname_extsz + 183 - 9 - 34 + sig_alg_sz); |
| 11296 | MG_STORE_BE16(msg_client_hello + 7, |
| 11297 | hostname_extsz + 179 - 9 - 34 + sig_alg_sz); |
| 11298 | MG_STORE_BE16(msg_client_hello + 82, |
| 11299 | hostname_extsz + 104 - 9 - 34 + sig_alg_sz); |
| 11300 | |
| 11301 | if (hostnamesz > 0) { |
| 11302 | MG_STORE_BE16(server_name_ext + 2, hostnamesz + 5); |
| 11303 | MG_STORE_BE16(server_name_ext + 4, hostnamesz + 3); |
| 11304 | MG_STORE_BE16(server_name_ext + 7, hostnamesz); |
| 11305 | } |
| 11306 | |
| 11307 | // calculate keyshare |
| 11308 | if (!mg_random(tls->x25519_cli, sizeof(tls->x25519_cli))) mg_error(c, "RNG"); |
| 11309 | mg_tls_x25519(x25519_pub, tls->x25519_cli, X25519_BASE_POINT, 1); |
| 11310 | |
| 11311 | // fill in the gaps: random + session ID + keyshare |
| 11312 | if (!mg_random(tls->session_id, sizeof(tls->session_id))) mg_error(c, "RNG"); |
| 11313 | if (!mg_random(tls->random, sizeof(tls->random))) mg_error(c, "RNG"); |
| 11314 | memmove(msg_client_hello + 11, tls->random, sizeof(tls->random)); |
| 11315 | memmove(msg_client_hello + 44, tls->session_id, sizeof(tls->session_id)); |
| 11316 | memmove(msg_client_hello + 94, x25519_pub, sizeof(x25519_pub)); |
| 11317 | |
| 11318 | // client hello message |
| 11319 | mg_iobuf_add(wio, wio->len, msg_client_hello, sizeof(msg_client_hello)); |
| 11320 | mg_sha256_update(&tls->sha256, msg_client_hello + 5, |
| 11321 | sizeof(msg_client_hello) - 5); |
| 11322 | mg_iobuf_add(wio, wio->len, sig_alg, sig_alg_sz); |
| 11323 | mg_sha256_update(&tls->sha256, sig_alg, sig_alg_sz); |
| 11324 | if (hostnamesz > 0) { |
| 11325 | mg_iobuf_add(wio, wio->len, server_name_ext, sizeof(server_name_ext)); |
| 11326 | mg_iobuf_add(wio, wio->len, hostname, hostnamesz); |
| 11327 | mg_sha256_update(&tls->sha256, server_name_ext, sizeof(server_name_ext)); |
| 11328 | mg_sha256_update(&tls->sha256, (uint8_t *) hostname, hostnamesz); |
| 11329 | } |
| 11330 | |
| 11331 | // change cipher message |
| 11332 | mg_iobuf_add(wio, wio->len, (const char *) "\x14\x03\x03\x00\x01\x01", 6); |
| 11333 | mg_io_send(c, wio->buf, wio->len); |
| 11334 | wio->len = 0; |
| 11335 | } |
| 11336 | |
| 11337 | static int mg_tls_client_recv_hello(struct mg_connection *c) { |
| 11338 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11339 | struct mg_iobuf *rio = &c->rtls; |
| 11340 | uint16_t msgsz; |
| 11341 | uint8_t *ext; |
| 11342 | uint16_t ext_len; |
| 11343 | int j; |
| 11344 | |
| 11345 | if (!mg_tls_got_record(c)) { |
| 11346 | return MG_IO_WAIT; |
| 11347 | } |
| 11348 | if (rio->buf[0] != MG_TLS_HANDSHAKE || rio->buf[5] != MG_TLS_SERVER_HELLO) { |
| 11349 | if (rio->buf[0] == MG_TLS_ALERT && rio->len >= 7) { |
| 11350 | mg_error(c, "tls alert %d", rio->buf[6]); |
| 11351 | return -1; |
| 11352 | } |
| 11353 | MG_INFO(("got packet type 0x%02x/0x%02x", rio->buf[0], rio->buf[5])); |
| 11354 | mg_error(c, "not a server hello packet"); |
| 11355 | return -1; |
| 11356 | } |
| 11357 | |
| 11358 | msgsz = MG_LOAD_BE16(rio->buf + 3); |
| 11359 | mg_sha256_update(&tls->sha256, rio->buf + 5, msgsz); |
| 11360 | |
| 11361 | ext_len = MG_LOAD_BE16(rio->buf + 5 + 39 + 32 + 3); |
| 11362 | ext = rio->buf + 5 + 39 + 32 + 3 + 2; |
| 11363 | if (ext_len > (rio->len - (5 + 39 + 32 + 3 + 2))) goto fail; |
| 11364 | |
| 11365 | for (j = 0; j < ext_len;) { |
| 11366 | uint16_t ext_type = MG_LOAD_BE16(ext + j); |
| 11367 | uint16_t ext_len2 = MG_LOAD_BE16(ext + j + 2); |
| 11368 | uint16_t group; |
| 11369 | uint8_t *key_exchange; |
| 11370 | uint16_t key_exchange_len; |
| 11371 | if (ext_len2 > (ext_len - j - 4)) goto fail; |
| 11372 | if (ext_type != 0x0033) { // not a key share extension, ignore |
| 11373 | j += (uint16_t) (ext_len2 + 4); |
| 11374 | continue; |
| 11375 | } |
| 11376 | group = MG_LOAD_BE16(ext + j + 4); |
| 11377 | if (group != 0x001d) { |
| 11378 | mg_error(c, "bad key exchange group"); |
| 11379 | return -1; |
| 11380 | } |
| 11381 | key_exchange_len = MG_LOAD_BE16(ext + j + 6); |
| 11382 | key_exchange = ext + j + 8; |
| 11383 | if (key_exchange_len != 32) { |
| 11384 | mg_error(c, "bad key exchange length"); |
| 11385 | return -1; |
| 11386 | } |
| 11387 | mg_tls_x25519(tls->x25519_sec, tls->x25519_cli, key_exchange, 1); |
| 11388 | mg_tls_hexdump("c x25519 sec", tls->x25519_sec, 32); |
| 11389 | mg_tls_drop_record(c); |
| 11390 | /* generate handshake keys */ |
| 11391 | mg_tls_generate_handshake_keys(c); |
| 11392 | return 0; |
| 11393 | } |
| 11394 | fail: |
| 11395 | mg_error(c, "bad server hello"); |
| 11396 | return -1; |
| 11397 | } |
| 11398 | |
| 11399 | static int mg_tls_client_recv_ext(struct mg_connection *c) { |
| 11400 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11401 | unsigned char *recv_buf; |
| 11402 | if (mg_tls_recv_record(c) < 0) { |
| 11403 | return -1; |
| 11404 | } |
| 11405 | recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 11406 | if (recv_buf[0] != MG_TLS_ENCRYPTED_EXTENSIONS) { |
| 11407 | mg_error(c, "expected server extensions but got msg 0x%02x", recv_buf[0]); |
| 11408 | return -1; |
| 11409 | } |
| 11410 | mg_tls_drop_message(c); |
| 11411 | return 0; |
| 11412 | } |
| 11413 | |
| 11414 | struct mg_tls_cert { |
| 11415 | int is_ec_pubkey; |
| 11416 | struct mg_str sn; |
| 11417 | struct mg_str pubkey; |
| 11418 | struct mg_str sig; // signature |
| 11419 | uint8_t tbshash[48]; // 32b for sha256/secp256, 48b for sha384/secp384 |
| 11420 | size_t tbshashsz; // actual TBS hash size |
| 11421 | }; |
| 11422 | |
| 11423 | static void mg_der_debug_cert_name(const char *name, struct mg_der_tlv *tlv) { |
| 11424 | struct mg_der_tlv v; |
| 11425 | struct mg_str cn, c, o, ou; |
| 11426 | cn = c = o = ou = mg_str(""); |
| 11427 | if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x03", 3, &v)) |
| 11428 | cn = mg_str_n((const char *) v.value, v.len); |
| 11429 | if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x06", 3, &v)) |
| 11430 | c = mg_str_n((const char *) v.value, v.len); |
| 11431 | if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x0a", 3, &v)) |
| 11432 | o = mg_str_n((const char *) v.value, v.len); |
| 11433 | if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x0b", 3, &v)) |
| 11434 | ou = mg_str_n((const char *) v.value, v.len); |
| 11435 | MG_VERBOSE(("%s: CN=%.*s, C=%.*s, O=%.*s, OU=%.*s", name, cn.len, cn.buf, |
| 11436 | c.len, c.buf, o.len, o.buf, ou.len, ou.buf)); |
| 11437 | } |
| 11438 | |
| 11439 | static int mg_tls_parse_cert_der(void *buf, size_t dersz, |
| 11440 | struct mg_tls_cert *cert) { |
| 11441 | uint8_t *tbs, *der = (uint8_t *) buf; |
| 11442 | size_t tbssz; |
| 11443 | struct mg_der_tlv root, tbs_cert, field, algo; // pubkey, signature; |
| 11444 | struct mg_der_tlv pki, pki_algo, pki_key, pki_curve, raw_sig; |
| 11445 | |
| 11446 | // Parse outermost SEQUENCE |
| 11447 | if (mg_der_parse(der, dersz, &root) <= 0 || root.type != 0x30) return -1; |
| 11448 | |
| 11449 | // Parse TBSCertificate SEQUENCE |
| 11450 | tbs = root.value; |
| 11451 | if (mg_der_next(&root, &tbs_cert) <= 0 || tbs_cert.type != 0x30) return -1; |
| 11452 | tbssz = (size_t) (tbs_cert.value + tbs_cert.len - tbs); |
| 11453 | |
| 11454 | // Parse Version (optional field) |
| 11455 | if (mg_der_next(&tbs_cert, &field) <= 0) return -1; |
| 11456 | if (field.type == 0xa0) { // v3 |
| 11457 | if (mg_der_parse(field.value, field.len, &field) <= 0 || field.len != 1 || |
| 11458 | field.value[0] != 2) |
| 11459 | return -1; |
| 11460 | if (mg_der_next(&tbs_cert, &field) <= 0) return -1; |
| 11461 | } |
| 11462 | |
| 11463 | // Parse Serial Number |
| 11464 | if (field.type != 2) return -1; |
| 11465 | cert->sn = mg_str_n((char *) field.value, field.len); |
| 11466 | MG_VERBOSE(("cert s/n: %M", mg_print_hex, cert->sn.len, cert->sn.buf)); |
| 11467 | |
| 11468 | // Parse signature algorithm (first occurrence) |
| 11469 | if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; |
| 11470 | if (mg_der_next(&field, &algo) <= 0 || algo.type != 0x06) return -1; |
| 11471 | |
| 11472 | MG_VERBOSE(("sig algo (oid): %M", mg_print_hex, algo.len, algo.value)); |
| 11473 | // Signature algorithm OID mapping |
| 11474 | if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x02", algo.len) == 0) { |
| 11475 | MG_VERBOSE(("sig algo: ECDSA with SHA256")); |
| 11476 | mg_sha256(cert->tbshash, tbs, tbssz); |
| 11477 | cert->tbshashsz = 32; |
| 11478 | } else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B", |
| 11479 | algo.len) == 0) { |
| 11480 | MG_VERBOSE(("sig algo: RSA with SHA256")); |
| 11481 | mg_sha256(cert->tbshash, tbs, tbssz); |
| 11482 | cert->tbshashsz = 32; |
| 11483 | } else if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x03", algo.len) == |
| 11484 | 0) { |
| 11485 | MG_VERBOSE(("sig algo: ECDSA with SHA384")); |
| 11486 | mg_sha384(cert->tbshash, tbs, tbssz); |
| 11487 | cert->tbshashsz = 48; |
| 11488 | } else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C", |
| 11489 | algo.len) == 0) { |
| 11490 | MG_VERBOSE(("sig algo: RSA with SHA384")); |
| 11491 | mg_sha384(cert->tbshash, tbs, tbssz); |
| 11492 | cert->tbshashsz = 48; |
| 11493 | } else { |
| 11494 | MG_ERROR( |
| 11495 | ("sig algo: unsupported OID: %M", mg_print_hex, algo.len, algo.value)); |
| 11496 | return -1; |
| 11497 | } |
| 11498 | MG_VERBOSE(("tbs hash: %M", mg_print_hex, cert->tbshashsz, cert->tbshash)); |
| 11499 | |
| 11500 | // issuer |
| 11501 | if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; |
| 11502 | mg_der_debug_cert_name("issuer", &field); |
| 11503 | |
| 11504 | // validity dates (before/after) |
| 11505 | if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; |
| 11506 | if (1) { |
| 11507 | struct mg_der_tlv before, after; |
| 11508 | mg_der_next(&field, &before); |
| 11509 | mg_der_next(&field, &after); |
| 11510 | if (memcmp(after.value, "250101000000Z", after.len) < 0) { |
| 11511 | MG_ERROR(("invalid validity dates: before=%M after=%M", mg_print_hex, |
| 11512 | before.len, before.value, mg_print_hex, after.len, |
| 11513 | after.value)); |
| 11514 | return -1; |
| 11515 | } |
| 11516 | } |
| 11517 | |
| 11518 | // subject |
| 11519 | if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; |
| 11520 | mg_der_debug_cert_name("subject", &field); |
| 11521 | |
| 11522 | // subject public key info |
| 11523 | if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; |
| 11524 | |
| 11525 | if (mg_der_next(&field, &pki) <= 0 || pki.type != 0x30) return -1; |
| 11526 | if (mg_der_next(&pki, &pki_algo) <= 0 || pki_algo.type != 0x06) return -1; |
| 11527 | |
| 11528 | // public key algorithm |
| 11529 | MG_VERBOSE(("pk algo (oid): %M", mg_print_hex, pki_algo.len, pki_algo.value)); |
| 11530 | if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x07", |
| 11531 | pki_algo.len) == 0) { |
| 11532 | cert->is_ec_pubkey = 1; |
| 11533 | MG_VERBOSE(("pk algo: ECDSA secp256r1")); |
| 11534 | } else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x08", |
| 11535 | pki_algo.len) == 0) { |
| 11536 | cert->is_ec_pubkey = 1; |
| 11537 | MG_VERBOSE(("pk algo: ECDSA secp384r1")); |
| 11538 | } else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x02\x01", |
| 11539 | pki_algo.len) == 0) { |
| 11540 | cert->is_ec_pubkey = 1; |
| 11541 | MG_VERBOSE(("pk algo: EC public key")); |
| 11542 | } else if (memcmp(pki_algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", |
| 11543 | pki_algo.len) == 0) { |
| 11544 | cert->is_ec_pubkey = 0; |
| 11545 | MG_VERBOSE(("pk algo: RSA")); |
| 11546 | } else { |
| 11547 | MG_ERROR(("unsupported pk algo: %M", mg_print_hex, pki_algo.len, |
| 11548 | pki_algo.value)); |
| 11549 | return -1; |
| 11550 | } |
| 11551 | |
| 11552 | // Parse public key |
| 11553 | if (cert->is_ec_pubkey) { |
| 11554 | if (mg_der_next(&pki, &pki_curve) <= 0 || pki_curve.type != 0x06) return -1; |
| 11555 | } |
| 11556 | if (mg_der_next(&field, &pki_key) <= 0 || pki_key.type != 0x03) return -1; |
| 11557 | |
| 11558 | if (cert->is_ec_pubkey) { // Skip leading 0x00 and 0x04 (=uncompressed) |
| 11559 | cert->pubkey = mg_str_n((char *) pki_key.value + 2, pki_key.len - 2); |
| 11560 | } else { // Skip leading 0x00 byte |
| 11561 | cert->pubkey = mg_str_n((char *) pki_key.value + 1, pki_key.len - 1); |
| 11562 | } |
| 11563 | |
| 11564 | // Parse signature |
| 11565 | if (mg_der_next(&root, &field) <= 0 || field.type != 0x30) return -1; |
| 11566 | if (mg_der_next(&root, &raw_sig) <= 0 || raw_sig.type != 0x03) return -1; |
| 11567 | if (raw_sig.len < 1 || raw_sig.value[0] != 0x00) return -1; |
| 11568 | |
| 11569 | cert->sig = mg_str_n((char *) raw_sig.value + 1, raw_sig.len - 1); |
| 11570 | MG_VERBOSE(("sig: %M", mg_print_hex, cert->sig.len, cert->sig.buf)); |
| 11571 | |
| 11572 | return 0; |
| 11573 | } |
| 11574 | |
| 11575 | static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz, |
| 11576 | const char *server_name) { |
| 11577 | struct mg_der_tlv root, field, name; |
| 11578 | if (mg_der_parse((uint8_t *) der, dersz, &root) < 0 || |
| 11579 | mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) < 0) { |
| 11580 | MG_ERROR(("failed to parse certificate to extract SAN")); |
| 11581 | return -1; |
| 11582 | } |
| 11583 | if (mg_der_parse(field.value, field.len, &field) < 0) { |
| 11584 | MG_ERROR( |
| 11585 | ("certificate subject alternative names is not a constructed object")); |
| 11586 | return -1; |
| 11587 | } |
| 11588 | while (mg_der_next(&field, &name) > 0) { |
| 11589 | if (mg_match(mg_str(server_name), |
| 11590 | mg_str_n((const char *) name.value, name.len), NULL)) { |
| 11591 | // Found SAN that matches the host name |
| 11592 | return 1; |
| 11593 | } |
| 11594 | } |
| 11595 | return -1; |
| 11596 | } |
| 11597 | |
| 11598 | static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert, |
| 11599 | const struct mg_tls_cert *issuer) { |
| 11600 | if (issuer->is_ec_pubkey) { |
| 11601 | uint8_t sig[128]; |
| 11602 | struct mg_der_tlv seq = {0, 0, 0}, a = {0, 0, 0}, b = {0, 0, 0}; |
| 11603 | mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq); |
| 11604 | mg_der_next(&seq, &a); |
| 11605 | mg_der_next(&seq, &b); |
| 11606 | if (a.len == 0 || b.len == 0) { |
| 11607 | MG_ERROR(("cert verification error")); |
| 11608 | return 0; |
| 11609 | } |
| 11610 | if (issuer->pubkey.len == 64) { |
| 11611 | const uint32_t N = 32; |
| 11612 | if (a.len > N) a.value += (a.len - N), a.len = N; |
| 11613 | if (b.len > N) b.value += (b.len - N), b.len = N; |
| 11614 | memmove(sig, a.value, N); |
| 11615 | memmove(sig + N, b.value, N); |
| 11616 | return mg_uecc_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash, |
| 11617 | (unsigned) cert->tbshashsz, sig, |
| 11618 | mg_uecc_secp256r1()); |
| 11619 | } else if (issuer->pubkey.len == 96) { |
| 11620 | MG_DEBUG(("ignore secp386 for now")); |
| 11621 | return 1; |
| 11622 | } else { |
| 11623 | MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len)); |
| 11624 | return 0; |
| 11625 | } |
| 11626 | } else { |
| 11627 | int r; |
| 11628 | uint8_t sig2[256]; // 2048 bits |
| 11629 | struct mg_der_tlv seq, modulus, exponent; |
| 11630 | if (mg_der_parse((uint8_t *) issuer->pubkey.buf, issuer->pubkey.len, |
| 11631 | &seq) <= 0 || |
| 11632 | mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 || |
| 11633 | mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) { |
| 11634 | return -1; |
| 11635 | } |
| 11636 | mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, |
| 11637 | (uint8_t *) cert->sig.buf, cert->sig.len, sig2, |
| 11638 | sizeof(sig2)); |
| 11639 | |
| 11640 | r = memcmp(sig2 + sizeof(sig2) - cert->tbshashsz, cert->tbshash, |
| 11641 | cert->tbshashsz); |
| 11642 | return r == 0; |
| 11643 | } |
| 11644 | } |
| 11645 | |
| 11646 | static int mg_tls_client_recv_cert(struct mg_connection *c) { |
| 11647 | int subj_match = 0; |
| 11648 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11649 | unsigned char *recv_buf; |
| 11650 | (void) subj_match; |
| 11651 | |
| 11652 | if (mg_tls_recv_record(c) < 0) { |
| 11653 | return -1; |
| 11654 | } |
| 11655 | |
| 11656 | recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 11657 | |
| 11658 | if (recv_buf[0] == MG_TLS_CERTIFICATE_REQUEST) { |
| 11659 | MG_VERBOSE(("got certificate request")); |
| 11660 | mg_tls_drop_message(c); |
| 11661 | tls->cert_requested = 1; |
| 11662 | return -1; |
| 11663 | } |
| 11664 | |
| 11665 | if (recv_buf[0] != MG_TLS_CERTIFICATE) { |
| 11666 | mg_error(c, "expected server certificate but got msg 0x%02x", recv_buf[0]); |
| 11667 | return -1; |
| 11668 | } |
| 11669 | |
| 11670 | if (tls->recv_len < 11) { |
| 11671 | mg_error(c, "certificate list too short"); |
| 11672 | return -1; |
| 11673 | } |
| 11674 | |
| 11675 | uint32_t full_cert_chain_len = MG_LOAD_BE24(recv_buf + 1); |
| 11676 | uint32_t cert_chain_len = MG_LOAD_BE24(recv_buf + 5); |
| 11677 | if (cert_chain_len != full_cert_chain_len - 4) { |
| 11678 | MG_ERROR(("full chain length: %d, chain length: %d", full_cert_chain_len, |
| 11679 | cert_chain_len)); |
| 11680 | mg_error(c, "certificate chain length mismatch"); |
| 11681 | return -1; |
| 11682 | } |
| 11683 | |
| 11684 | // Normally, there are 2-3 certs in a chain |
| 11685 | struct mg_tls_cert certs[8]; |
| 11686 | int certnum = 0; |
| 11687 | uint8_t *p = recv_buf + 8; |
| 11688 | // uint8_t *endp = recv_buf + tls->recv_len; |
| 11689 | uint8_t *endp = recv_buf + cert_chain_len; |
| 11690 | |
| 11691 | int found_ca = 0; |
| 11692 | struct mg_tls_cert ca; |
| 11693 | |
| 11694 | memset(certs, 0, sizeof(certs)); |
| 11695 | memset(&ca, 0, sizeof(ca)); |
| 11696 | |
| 11697 | if (tls->ca_der.len > 0) { |
| 11698 | if (mg_tls_parse_cert_der(tls->ca_der.buf, tls->ca_der.len, &ca) < 0) { |
| 11699 | mg_error(c, "failed to parse CA certificate"); |
| 11700 | return -1; |
| 11701 | } |
| 11702 | MG_VERBOSE(("CA serial: %M", mg_print_hex, ca.sn.len, ca.sn.buf)); |
| 11703 | } |
| 11704 | |
| 11705 | while (p < endp) { |
| 11706 | struct mg_tls_cert *ci = &certs[certnum++]; |
| 11707 | uint32_t certsz = MG_LOAD_BE24(p); |
| 11708 | uint8_t *cert = p + 3; |
| 11709 | uint16_t certext = MG_LOAD_BE16(cert + certsz); |
| 11710 | if (certext != 0) { |
| 11711 | mg_error(c, "certificate extensions are not supported"); |
| 11712 | return -1; |
| 11713 | } |
| 11714 | p = cert + certsz + 2; |
| 11715 | |
| 11716 | if (mg_tls_parse_cert_der(cert, certsz, ci) < 0) { |
| 11717 | mg_error(c, "failed to parse certificate"); |
| 11718 | return -1; |
| 11719 | } |
| 11720 | |
| 11721 | if (ci == certs) { |
| 11722 | // First certificate in the chain is peer cert, check SAN and store |
| 11723 | // public key for further CertVerify step |
| 11724 | if (mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0) { |
| 11725 | mg_error(c, "failed to verify hostname"); |
| 11726 | return -1; |
| 11727 | } |
| 11728 | memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len); |
| 11729 | tls->pubkeysz = ci->pubkey.len; |
| 11730 | } else { |
| 11731 | if (!mg_tls_verify_cert_signature(ci - 1, ci)) { |
| 11732 | mg_error(c, "failed to verify certificate chain"); |
| 11733 | return -1; |
| 11734 | } |
| 11735 | } |
| 11736 | |
| 11737 | if (ca.pubkey.len == ci->pubkey.len && |
| 11738 | memcmp(ca.pubkey.buf, ci->pubkey.buf, ca.pubkey.len) == 0) { |
| 11739 | found_ca = 1; |
| 11740 | break; |
| 11741 | } |
| 11742 | |
| 11743 | if (certnum == sizeof(certs) / sizeof(certs[0]) - 1) { |
| 11744 | mg_error(c, "too many certificates in the chain"); |
| 11745 | return -1; |
| 11746 | } |
| 11747 | } |
| 11748 | |
| 11749 | if (!found_ca && tls->ca_der.len > 0) { |
| 11750 | if (certnum < 1 || |
| 11751 | !mg_tls_verify_cert_signature(&certs[certnum - 1], &ca)) { |
| 11752 | mg_error(c, "failed to verify CA"); |
| 11753 | return -1; |
| 11754 | } else { |
| 11755 | MG_VERBOSE( |
| 11756 | ("CA was not in the chain, but verification with builtin CA passed")); |
| 11757 | } |
| 11758 | } |
| 11759 | |
| 11760 | mg_tls_drop_message(c); |
| 11761 | mg_tls_calc_cert_verify_hash(c, tls->sighash, 0); |
| 11762 | return 0; |
| 11763 | } |
| 11764 | |
| 11765 | static int mg_tls_client_recv_cert_verify(struct mg_connection *c) { |
| 11766 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11767 | unsigned char *recv_buf; |
| 11768 | if (mg_tls_recv_record(c) < 0) { |
| 11769 | return -1; |
| 11770 | } |
| 11771 | recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 11772 | if (recv_buf[0] != MG_TLS_CERTIFICATE_VERIFY) { |
| 11773 | mg_error(c, "expected server certificate verify but got msg 0x%02x", |
| 11774 | recv_buf[0]); |
| 11775 | return -1; |
| 11776 | } |
| 11777 | if (tls->recv_len < 8) { |
| 11778 | mg_error(c, "server certificate verify is too short: %d bytes", |
| 11779 | tls->recv_len); |
| 11780 | return -1; |
| 11781 | } |
| 11782 | |
| 11783 | // Ignore CertificateVerify is strict checks are not required |
| 11784 | if (tls->skip_verification) { |
| 11785 | mg_tls_drop_message(c); |
| 11786 | return 0; |
| 11787 | } |
| 11788 | |
| 11789 | uint16_t sigalg = MG_LOAD_BE16(recv_buf + 4); |
| 11790 | uint16_t siglen = MG_LOAD_BE16(recv_buf + 6); |
| 11791 | uint8_t *sigbuf = recv_buf + 8; |
| 11792 | if (siglen > tls->recv_len - 8) { |
| 11793 | mg_error(c, "invalid certverify signature length: %d, expected %d", siglen, |
| 11794 | tls->recv_len - 8); |
| 11795 | return -1; |
| 11796 | } |
| 11797 | MG_VERBOSE( |
| 11798 | ("certificate verification, algo=%04x, siglen=%d", sigalg, siglen)); |
| 11799 | |
| 11800 | if (sigalg == 0x0804) { // rsa_pss_rsae_sha256 |
| 11801 | uint8_t sig2[512]; // 2048 or 4096 bits |
| 11802 | struct mg_der_tlv seq, modulus, exponent; |
| 11803 | |
| 11804 | if (mg_der_parse(tls->pubkey, tls->pubkeysz, &seq) <= 0 || |
| 11805 | mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 || |
| 11806 | mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) { |
| 11807 | mg_error(c, "invalid public key"); |
| 11808 | return -1; |
| 11809 | } |
| 11810 | |
| 11811 | mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, |
| 11812 | sigbuf, siglen, sig2, sizeof(sig2)); |
| 11813 | |
| 11814 | if (sig2[sizeof(sig2) - 1] != 0xbc) { |
| 11815 | mg_error(c, "failed to verify RSA certificate (certverify)"); |
| 11816 | return -1; |
| 11817 | } |
| 11818 | MG_DEBUG(("certificate verification successful (RSA)")); |
| 11819 | } else if (sigalg == 0x0403) { // ecdsa_secp256r1_sha256 |
| 11820 | // Extract certificate signature and verify it using pubkey and sighash |
| 11821 | uint8_t sig[64]; |
| 11822 | struct mg_der_tlv seq, r, s; |
| 11823 | if (mg_der_to_tlv(sigbuf, siglen, &seq) < 0) { |
| 11824 | mg_error(c, "verification message is not an ASN.1 DER sequence"); |
| 11825 | return -1; |
| 11826 | } |
| 11827 | if (mg_der_to_tlv(seq.value, seq.len, &r) < 0) { |
| 11828 | mg_error(c, "missing first part of the signature"); |
| 11829 | return -1; |
| 11830 | } |
| 11831 | if (mg_der_to_tlv(r.value + r.len, seq.len - r.len, &s) < 0) { |
| 11832 | mg_error(c, "missing second part of the signature"); |
| 11833 | return -1; |
| 11834 | } |
| 11835 | // Integers may be padded with zeroes |
| 11836 | if (r.len > 32) r.value = r.value + (r.len - 32), r.len = 32; |
| 11837 | if (s.len > 32) s.value = s.value + (s.len - 32), s.len = 32; |
| 11838 | |
| 11839 | memmove(sig, r.value, r.len); |
| 11840 | memmove(sig + 32, s.value, s.len); |
| 11841 | |
| 11842 | if (mg_uecc_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash), sig, |
| 11843 | mg_uecc_secp256r1()) != 1) { |
| 11844 | mg_error(c, "failed to verify EC certificate (certverify)"); |
| 11845 | return -1; |
| 11846 | } |
| 11847 | MG_DEBUG(("certificate verification successful (EC)")); |
| 11848 | } else { |
| 11849 | // From |
| 11850 | // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml: |
| 11851 | // 0805 = rsa_pss_rsae_sha384 |
| 11852 | // 0806 = rsa_pss_rsae_sha512 |
| 11853 | // 0807 = ed25519 |
| 11854 | // 0808 = ed448 |
| 11855 | // 0809 = rsa_pss_pss_sha256 |
| 11856 | // 080A = rsa_pss_pss_sha384 |
| 11857 | // 080B = rsa_pss_pss_sha512 |
| 11858 | MG_ERROR(("unsupported certverify signature scheme: %x of %d bytes", sigalg, |
| 11859 | siglen)); |
| 11860 | return -1; |
| 11861 | } |
| 11862 | mg_tls_drop_message(c); |
| 11863 | return 0; |
| 11864 | } |
| 11865 | |
| 11866 | static int mg_tls_client_recv_finish(struct mg_connection *c) { |
| 11867 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11868 | unsigned char *recv_buf; |
| 11869 | if (mg_tls_recv_record(c) < 0) { |
| 11870 | return -1; |
| 11871 | } |
| 11872 | recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 11873 | if (recv_buf[0] != MG_TLS_FINISHED) { |
| 11874 | mg_error(c, "expected server finished but got msg 0x%02x", recv_buf[0]); |
| 11875 | return -1; |
| 11876 | } |
| 11877 | mg_tls_drop_message(c); |
| 11878 | return 0; |
| 11879 | } |
| 11880 | |
| 11881 | static void mg_tls_client_send_finish(struct mg_connection *c) { |
| 11882 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11883 | struct mg_iobuf *wio = &tls->send; |
| 11884 | mg_sha256_ctx sha256; |
| 11885 | uint8_t hash[32]; |
| 11886 | uint8_t finish[36] = {0x14, 0, 0, 32}; |
| 11887 | memmove(&sha256, &tls->sha256, sizeof(mg_sha256_ctx)); |
| 11888 | mg_sha256_final(hash, &sha256); |
| 11889 | mg_hmac_sha256(finish + 4, tls->enc.client_finished_key, 32, hash, 32); |
| 11890 | mg_tls_encrypt(c, finish, sizeof(finish), MG_TLS_HANDSHAKE); |
| 11891 | mg_io_send(c, wio->buf, wio->len); |
| 11892 | wio->len = 0; |
| 11893 | } |
| 11894 | |
| 11895 | static void mg_tls_client_handshake(struct mg_connection *c) { |
| 11896 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11897 | switch (tls->state) { |
| 11898 | case MG_TLS_STATE_CLIENT_START: |
| 11899 | mg_tls_client_send_hello(c); |
| 11900 | tls->state = MG_TLS_STATE_CLIENT_WAIT_SH; |
| 11901 | // Fallthrough |
| 11902 | case MG_TLS_STATE_CLIENT_WAIT_SH: |
| 11903 | if (mg_tls_client_recv_hello(c) < 0) { |
| 11904 | break; |
| 11905 | } |
| 11906 | tls->state = MG_TLS_STATE_CLIENT_WAIT_EE; |
| 11907 | // Fallthrough |
| 11908 | case MG_TLS_STATE_CLIENT_WAIT_EE: |
| 11909 | if (mg_tls_client_recv_ext(c) < 0) { |
| 11910 | break; |
| 11911 | } |
| 11912 | tls->state = MG_TLS_STATE_CLIENT_WAIT_CERT; |
| 11913 | // Fallthrough |
| 11914 | case MG_TLS_STATE_CLIENT_WAIT_CERT: |
| 11915 | if (mg_tls_client_recv_cert(c) < 0) { |
| 11916 | break; |
| 11917 | } |
| 11918 | tls->state = MG_TLS_STATE_CLIENT_WAIT_CV; |
| 11919 | // Fallthrough |
| 11920 | case MG_TLS_STATE_CLIENT_WAIT_CV: |
| 11921 | if (mg_tls_client_recv_cert_verify(c) < 0) { |
| 11922 | break; |
| 11923 | } |
| 11924 | tls->state = MG_TLS_STATE_CLIENT_WAIT_FINISHED; |
| 11925 | // Fallthrough |
| 11926 | case MG_TLS_STATE_CLIENT_WAIT_FINISHED: |
| 11927 | if (mg_tls_client_recv_finish(c) < 0) { |
| 11928 | break; |
| 11929 | } |
| 11930 | if (tls->cert_requested) { |
| 11931 | /* for mTLS we should generate application keys at this point |
| 11932 | * but then restore handshake keys and continue with |
| 11933 | * the rest of the handshake */ |
| 11934 | struct tls_enc app_keys; |
| 11935 | struct tls_enc hs_keys = tls->enc; |
| 11936 | mg_tls_generate_application_keys(c); |
| 11937 | app_keys = tls->enc; |
| 11938 | tls->enc = hs_keys; |
| 11939 | mg_tls_server_send_cert(c); |
| 11940 | mg_tls_send_cert_verify(c, 1); |
| 11941 | mg_tls_client_send_finish(c); |
| 11942 | tls->enc = app_keys; |
| 11943 | } else { |
| 11944 | mg_tls_client_send_finish(c); |
| 11945 | mg_tls_generate_application_keys(c); |
| 11946 | } |
| 11947 | tls->state = MG_TLS_STATE_CLIENT_CONNECTED; |
| 11948 | c->is_tls_hs = 0; |
| 11949 | mg_call(c, MG_EV_TLS_HS, NULL); |
| 11950 | break; |
| 11951 | default: |
| 11952 | mg_error(c, "unexpected client state: %d", tls->state); |
| 11953 | break; |
| 11954 | } |
| 11955 | } |
| 11956 | |
| 11957 | static void mg_tls_server_handshake(struct mg_connection *c) { |
| 11958 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 11959 | switch (tls->state) { |
| 11960 | case MG_TLS_STATE_SERVER_START: |
| 11961 | if (mg_tls_server_recv_hello(c) < 0) { |
| 11962 | return; |
| 11963 | } |
| 11964 | mg_tls_server_send_hello(c); |
| 11965 | mg_tls_generate_handshake_keys(c); |
| 11966 | mg_tls_server_send_ext(c); |
| 11967 | mg_tls_server_send_cert(c); |
| 11968 | mg_tls_send_cert_verify(c, 0); |
| 11969 | mg_tls_server_send_finish(c); |
| 11970 | tls->state = MG_TLS_STATE_SERVER_NEGOTIATED; |
| 11971 | // fallthrough |
| 11972 | case MG_TLS_STATE_SERVER_NEGOTIATED: |
| 11973 | if (mg_tls_server_recv_finish(c) < 0) { |
| 11974 | return; |
| 11975 | } |
| 11976 | mg_tls_generate_application_keys(c); |
| 11977 | tls->state = MG_TLS_STATE_SERVER_CONNECTED; |
| 11978 | c->is_tls_hs = 0; |
| 11979 | return; |
| 11980 | default: |
| 11981 | mg_error(c, "unexpected server state: %d", tls->state); |
| 11982 | break; |
| 11983 | } |
| 11984 | } |
| 11985 | |
| 11986 | void mg_tls_handshake(struct mg_connection *c) { |
| 11987 | if (c->is_client) { |
| 11988 | mg_tls_client_handshake(c); |
| 11989 | } else { |
| 11990 | mg_tls_server_handshake(c); |
| 11991 | } |
| 11992 | } |
| 11993 | |
| 11994 | static int mg_parse_pem(const struct mg_str pem, const struct mg_str label, |
| 11995 | struct mg_str *der) { |
| 11996 | size_t n = 0, m = 0; |
| 11997 | char *s; |
| 11998 | const char *c; |
| 11999 | struct mg_str caps[6]; // number of wildcards + 1 |
| 12000 | if (!mg_match(pem, mg_str("#-----BEGIN #-----#-----END #-----#"), caps)) { |
| 12001 | *der = mg_strdup(pem); |
| 12002 | return 0; |
| 12003 | } |
| 12004 | if (mg_strcmp(caps[1], label) != 0 || mg_strcmp(caps[3], label) != 0) { |
| 12005 | return -1; // bad label |
| 12006 | } |
| 12007 | if ((s = (char *) calloc(1, caps[2].len)) == NULL) { |
| 12008 | return -1; |
| 12009 | } |
| 12010 | |
| 12011 | for (c = caps[2].buf; c < caps[2].buf + caps[2].len; c++) { |
| 12012 | if (*c == ' ' || *c == '\n' || *c == '\r' || *c == '\t') { |
| 12013 | continue; |
| 12014 | } |
| 12015 | s[n++] = *c; |
| 12016 | } |
| 12017 | m = mg_base64_decode(s, n, s, n); |
| 12018 | if (m == 0) { |
| 12019 | free(s); |
| 12020 | return -1; |
| 12021 | } |
| 12022 | der->buf = s; |
| 12023 | der->len = m; |
| 12024 | return 0; |
| 12025 | } |
| 12026 | |
| 12027 | void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { |
| 12028 | struct mg_str key; |
| 12029 | struct tls_data *tls = (struct tls_data *) calloc(1, sizeof(struct tls_data)); |
| 12030 | if (tls == NULL) { |
| 12031 | mg_error(c, "tls oom"); |
| 12032 | return; |
| 12033 | } |
| 12034 | |
| 12035 | tls->state = |
| 12036 | c->is_client ? MG_TLS_STATE_CLIENT_START : MG_TLS_STATE_SERVER_START; |
| 12037 | |
| 12038 | tls->skip_verification = opts->skip_verification; |
| 12039 | // tls->send.align = MG_IO_SIZE; |
| 12040 | |
| 12041 | c->tls = tls; |
| 12042 | c->is_tls = c->is_tls_hs = 1; |
| 12043 | mg_sha256_init(&tls->sha256); |
| 12044 | |
| 12045 | // save hostname (client extension) |
| 12046 | if (opts->name.len > 0) { |
| 12047 | if (opts->name.len >= sizeof(tls->hostname) - 1) { |
| 12048 | mg_error(c, "hostname too long"); |
| 12049 | return; |
| 12050 | } |
| 12051 | strncpy((char *) tls->hostname, opts->name.buf, sizeof(tls->hostname) - 1); |
| 12052 | tls->hostname[opts->name.len] = 0; |
| 12053 | } |
| 12054 | // server CA certificate, store serial number |
| 12055 | if (opts->ca.len > 0) { |
| 12056 | if (mg_parse_pem(opts->ca, mg_str_s("CERTIFICATE"), &tls->ca_der) < 0) { |
| 12057 | MG_ERROR(("Failed to load certificate")); |
| 12058 | return; |
| 12059 | } |
| 12060 | } |
| 12061 | |
| 12062 | if (opts->cert.buf == NULL) { |
| 12063 | MG_VERBOSE(("No certificate provided")); |
| 12064 | return; |
| 12065 | } |
| 12066 | |
| 12067 | // parse PEM or DER certificate |
| 12068 | if (mg_parse_pem(opts->cert, mg_str_s("CERTIFICATE"), &tls->cert_der) < 0) { |
| 12069 | MG_ERROR(("Failed to load certificate")); |
| 12070 | return; |
| 12071 | } |
| 12072 | |
| 12073 | // parse PEM or DER EC key |
| 12074 | if (opts->key.buf == NULL) { |
| 12075 | mg_error(c, "Certificate provided without a private key"); |
| 12076 | return; |
| 12077 | } |
| 12078 | |
| 12079 | if (mg_parse_pem(opts->key, mg_str_s("EC PRIVATE KEY"), &key) == 0) { |
| 12080 | if (key.len < 39) { |
| 12081 | MG_ERROR(("EC private key too short")); |
| 12082 | return; |
| 12083 | } |
| 12084 | // expect ASN.1 SEQUENCE=[INTEGER=1, BITSTRING of 32 bytes, ...] |
| 12085 | // 30 nn 02 01 01 04 20 [key] ... |
| 12086 | if (key.buf[0] != 0x30 || (key.buf[1] & 0x80) != 0) { |
| 12087 | MG_ERROR(("EC private key: ASN.1 bad sequence")); |
| 12088 | return; |
| 12089 | } |
| 12090 | if (memcmp(key.buf + 2, "\x02\x01\x01\x04\x20", 5) != 0) { |
| 12091 | MG_ERROR(("EC private key: ASN.1 bad data")); |
| 12092 | } |
| 12093 | memmove(tls->ec_key, key.buf + 7, 32); |
| 12094 | free((void *) key.buf); |
| 12095 | } else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) { |
| 12096 | mg_error(c, "PKCS8 private key format is not supported"); |
| 12097 | } else { |
| 12098 | mg_error(c, "Expected EC PRIVATE KEY or PRIVATE KEY"); |
| 12099 | } |
| 12100 | } |
| 12101 | |
| 12102 | void mg_tls_free(struct mg_connection *c) { |
| 12103 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 12104 | if (tls != NULL) { |
| 12105 | mg_iobuf_free(&tls->send); |
| 12106 | free((void *) tls->cert_der.buf); |
| 12107 | free((void *) tls->ca_der.buf); |
| 12108 | } |
| 12109 | free(c->tls); |
| 12110 | c->tls = NULL; |
| 12111 | } |
| 12112 | |
| 12113 | long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { |
| 12114 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 12115 | long n = MG_IO_WAIT; |
| 12116 | bool was_throttled = c->is_tls_throttled; // see #3074 |
| 12117 | if (!was_throttled) { // encrypt new data |
| 12118 | if (len > MG_IO_SIZE) len = MG_IO_SIZE; |
| 12119 | if (len > 16384) len = 16384; |
| 12120 | mg_tls_encrypt(c, (const uint8_t *) buf, len, MG_TLS_APP_DATA); |
| 12121 | } // else, resend outstanding encrypted data in tls->send |
| 12122 | while (tls->send.len > 0 && |
| 12123 | (n = mg_io_send(c, tls->send.buf, tls->send.len)) > 0) { |
| 12124 | mg_iobuf_del(&tls->send, 0, (size_t) n); |
| 12125 | } |
| 12126 | c->is_tls_throttled = (tls->send.len > 0 && n == MG_IO_WAIT); |
| 12127 | MG_VERBOSE(("%lu %ld %ld %ld %c %c", c->id, (long) len, (long) tls->send.len, |
| 12128 | n, was_throttled ? 'T' : 't', c->is_tls_throttled ? 'T' : 't')); |
| 12129 | if (n == MG_IO_ERR) return MG_IO_ERR; |
| 12130 | if (was_throttled) return MG_IO_WAIT; // sent throttled data instead |
| 12131 | return (long) len; // return len even when throttled, already encripted that |
| 12132 | } |
| 12133 | |
| 12134 | long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) { |
| 12135 | int r = 0; |
| 12136 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 12137 | unsigned char *recv_buf; |
| 12138 | size_t minlen; |
| 12139 | |
| 12140 | r = mg_tls_recv_record(c); |
| 12141 | if (r < 0) { |
| 12142 | return r; |
| 12143 | } |
| 12144 | recv_buf = &c->rtls.buf[tls->recv_offset]; |
| 12145 | |
| 12146 | if (tls->content_type != MG_TLS_APP_DATA) { |
| 12147 | tls->recv_len = 0; |
| 12148 | mg_tls_drop_record(c); |
| 12149 | return MG_IO_WAIT; |
| 12150 | } |
| 12151 | if (buf == NULL || len == 0) return 0L; |
| 12152 | minlen = len < tls->recv_len ? len : tls->recv_len; |
| 12153 | memmove(buf, recv_buf, minlen); |
| 12154 | tls->recv_offset += minlen; |
| 12155 | tls->recv_len -= minlen; |
| 12156 | if (tls->recv_len == 0) { |
| 12157 | mg_tls_drop_record(c); |
| 12158 | } |
| 12159 | return (long) minlen; |
| 12160 | } |
| 12161 | |
| 12162 | size_t mg_tls_pending(struct mg_connection *c) { |
| 12163 | struct tls_data *tls = (struct tls_data *) c->tls; |
| 12164 | return tls != NULL ? tls->recv_len : 0; |
| 12165 | } |
| 12166 | |
| 12167 | void mg_tls_ctx_init(struct mg_mgr *mgr) { |
| 12168 | (void) mgr; |
| 12169 | } |
| 12170 | |
| 12171 | void mg_tls_ctx_free(struct mg_mgr *mgr) { |
| 12172 | (void) mgr; |
| 12173 | } |
| 12174 | #endif |
| 12175 | |
| 12176 | #ifdef MG_ENABLE_LINES |
| 12177 | #line 1 "src/tls_chacha20.c" |
| 12178 | #endif |
| 12179 | // portable8439 v1.0.1 |
| 12180 | // Source: https://github.com/DavyLandman/portable8439 |
| 12181 | // Licensed under CC0-1.0 |
| 12182 | // Contains poly1305-donna e6ad6e091d30d7f4ec2d4f978be1fcfcbce72781 (Public |
| 12183 | // Domain) |
| 12184 | |
| 12185 | |
| 12186 | |
| 12187 | |
| 12188 | #if MG_TLS == MG_TLS_BUILTIN |
| 12189 | // ******* BEGIN: chacha-portable/chacha-portable.h ******** |
| 12190 | |
| 12191 | #if !defined(__cplusplus) && !defined(_MSC_VER) && \ |
| 12192 | (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) |
| 12193 | #error "C99 or newer required" |
| 12194 | #endif |
| 12195 | |
| 12196 | #define CHACHA20_KEY_SIZE (32) |
| 12197 | #define CHACHA20_NONCE_SIZE (12) |
| 12198 | |
| 12199 | #if defined(_MSC_VER) || defined(__cplusplus) |
| 12200 | // add restrict support |
| 12201 | #if (defined(_MSC_VER) && _MSC_VER >= 1900) || defined(__clang__) || \ |
| 12202 | defined(__GNUC__) |
| 12203 | #define restrict __restrict |
| 12204 | #else |
| 12205 | #define restrict |
| 12206 | #endif |
| 12207 | #endif |
| 12208 | |
| 12209 | // xor data with a ChaCha20 keystream as per RFC8439 |
| 12210 | static PORTABLE_8439_DECL void chacha20_xor_stream( |
| 12211 | uint8_t *restrict dest, const uint8_t *restrict source, size_t length, |
| 12212 | const uint8_t key[CHACHA20_KEY_SIZE], |
| 12213 | const uint8_t nonce[CHACHA20_NONCE_SIZE], uint32_t counter); |
| 12214 | |
| 12215 | static PORTABLE_8439_DECL void rfc8439_keygen( |
| 12216 | uint8_t poly_key[32], const uint8_t key[CHACHA20_KEY_SIZE], |
| 12217 | const uint8_t nonce[CHACHA20_NONCE_SIZE]); |
| 12218 | |
| 12219 | // ******* END: chacha-portable/chacha-portable.h ******** |
| 12220 | // ******* BEGIN: poly1305-donna/poly1305-donna.h ******** |
| 12221 | |
| 12222 | #include <stddef.h> |
| 12223 | |
| 12224 | typedef struct poly1305_context { |
| 12225 | size_t aligner; |
| 12226 | unsigned char opaque[136]; |
| 12227 | } poly1305_context; |
| 12228 | |
| 12229 | static PORTABLE_8439_DECL void poly1305_init(poly1305_context *ctx, |
| 12230 | const unsigned char key[32]); |
| 12231 | static PORTABLE_8439_DECL void poly1305_update(poly1305_context *ctx, |
| 12232 | const unsigned char *m, |
| 12233 | size_t bytes); |
| 12234 | static PORTABLE_8439_DECL void poly1305_finish(poly1305_context *ctx, |
| 12235 | unsigned char mac[16]); |
| 12236 | |
| 12237 | // ******* END: poly1305-donna/poly1305-donna.h ******** |
| 12238 | // ******* BEGIN: chacha-portable.c ******** |
| 12239 | |
| 12240 | #include <assert.h> |
| 12241 | #include <string.h> |
| 12242 | |
| 12243 | // this is a fresh implementation of chacha20, based on the description in |
| 12244 | // rfc8349 it's such a nice compact algorithm that it is easy to do. In |
| 12245 | // relationship to other c implementation this implementation: |
| 12246 | // - pure c99 |
| 12247 | // - big & little endian support |
| 12248 | // - safe for architectures that don't support unaligned reads |
| 12249 | // |
| 12250 | // Next to this, we try to be fast as possible without resorting inline |
| 12251 | // assembly. |
| 12252 | |
| 12253 | // based on https://sourceforge.net/p/predef/wiki/Endianness/ |
| 12254 | #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ |
| 12255 | __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| 12256 | #define __HAVE_LITTLE_ENDIAN 1 |
| 12257 | #elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ |
| 12258 | defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ |
| 12259 | defined(__MIPSEL) || defined(__MIPSEL__) || defined(__XTENSA_EL__) || \ |
| 12260 | defined(__AVR__) || defined(LITTLE_ENDIAN) |
| 12261 | #define __HAVE_LITTLE_ENDIAN 1 |
| 12262 | #endif |
| 12263 | |
| 12264 | #ifndef TEST_SLOW_PATH |
| 12265 | #if defined(__HAVE_LITTLE_ENDIAN) |
| 12266 | #define FAST_PATH |
| 12267 | #endif |
| 12268 | #endif |
| 12269 | |
| 12270 | #define CHACHA20_STATE_WORDS (16) |
| 12271 | #define CHACHA20_BLOCK_SIZE (CHACHA20_STATE_WORDS * sizeof(uint32_t)) |
| 12272 | |
| 12273 | #ifdef FAST_PATH |
| 12274 | #define store_32_le(target, source) memcpy(&(target), source, sizeof(uint32_t)) |
| 12275 | #else |
| 12276 | #define store_32_le(target, source) \ |
| 12277 | target = (uint32_t) (source)[0] | ((uint32_t) (source)[1]) << 8 | \ |
| 12278 | ((uint32_t) (source)[2]) << 16 | ((uint32_t) (source)[3]) << 24 |
| 12279 | #endif |
| 12280 | |
| 12281 | static void initialize_state(uint32_t state[CHACHA20_STATE_WORDS], |
| 12282 | const uint8_t key[CHACHA20_KEY_SIZE], |
| 12283 | const uint8_t nonce[CHACHA20_NONCE_SIZE], |
| 12284 | uint32_t counter) { |
| 12285 | #if 0 |
| 12286 | #ifdef static_assert |
| 12287 | static_assert(sizeof(uint32_t) == 4, |
| 12288 | "We don't support systems that do not conform to standard of " |
| 12289 | "uint32_t being exact 32bit wide"); |
| 12290 | #endif |
| 12291 | #endif |
| 12292 | state[0] = 0x61707865; |
| 12293 | state[1] = 0x3320646e; |
| 12294 | state[2] = 0x79622d32; |
| 12295 | state[3] = 0x6b206574; |
| 12296 | store_32_le(state[4], key); |
| 12297 | store_32_le(state[5], key + 4); |
| 12298 | store_32_le(state[6], key + 8); |
| 12299 | store_32_le(state[7], key + 12); |
| 12300 | store_32_le(state[8], key + 16); |
| 12301 | store_32_le(state[9], key + 20); |
| 12302 | store_32_le(state[10], key + 24); |
| 12303 | store_32_le(state[11], key + 28); |
| 12304 | state[12] = counter; |
| 12305 | store_32_le(state[13], nonce); |
| 12306 | store_32_le(state[14], nonce + 4); |
| 12307 | store_32_le(state[15], nonce + 8); |
| 12308 | } |
| 12309 | |
| 12310 | #define increment_counter(state) (state)[12]++ |
| 12311 | |
| 12312 | // source: http://blog.regehr.org/archives/1063 |
| 12313 | #define rotl32a(x, n) ((x) << (n)) | ((x) >> (32 - (n))) |
| 12314 | |
| 12315 | #define Qround(a, b, c, d) \ |
| 12316 | a += b; \ |
| 12317 | d ^= a; \ |
| 12318 | d = rotl32a(d, 16); \ |
| 12319 | c += d; \ |
| 12320 | b ^= c; \ |
| 12321 | b = rotl32a(b, 12); \ |
| 12322 | a += b; \ |
| 12323 | d ^= a; \ |
| 12324 | d = rotl32a(d, 8); \ |
| 12325 | c += d; \ |
| 12326 | b ^= c; \ |
| 12327 | b = rotl32a(b, 7); |
| 12328 | |
| 12329 | #define TIMES16(x) \ |
| 12330 | x(0) x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) x(9) x(10) x(11) x(12) x(13) \ |
| 12331 | x(14) x(15) |
| 12332 | |
| 12333 | static void core_block(const uint32_t *restrict start, |
| 12334 | uint32_t *restrict output) { |
| 12335 | int i; |
| 12336 | // instead of working on the output array, |
| 12337 | // we let the compiler allocate 16 local variables on the stack |
| 12338 | #define __LV(i) uint32_t __t##i = start[i]; |
| 12339 | TIMES16(__LV) |
| 12340 | |
| 12341 | #define __Q(a, b, c, d) Qround(__t##a, __t##b, __t##c, __t##d) |
| 12342 | |
| 12343 | for (i = 0; i < 10; i++) { |
| 12344 | __Q(0, 4, 8, 12); |
| 12345 | __Q(1, 5, 9, 13); |
| 12346 | __Q(2, 6, 10, 14); |
| 12347 | __Q(3, 7, 11, 15); |
| 12348 | __Q(0, 5, 10, 15); |
| 12349 | __Q(1, 6, 11, 12); |
| 12350 | __Q(2, 7, 8, 13); |
| 12351 | __Q(3, 4, 9, 14); |
| 12352 | } |
| 12353 | |
| 12354 | #define __FIN(i) output[i] = start[i] + __t##i; |
| 12355 | TIMES16(__FIN) |
| 12356 | } |
| 12357 | |
| 12358 | #define U8(x) ((uint8_t) ((x) &0xFF)) |
| 12359 | |
| 12360 | #ifdef FAST_PATH |
| 12361 | #define xor32_le(dst, src, pad) \ |
| 12362 | uint32_t __value; \ |
| 12363 | memcpy(&__value, src, sizeof(uint32_t)); \ |
| 12364 | __value ^= *(pad); \ |
| 12365 | memcpy(dst, &__value, sizeof(uint32_t)); |
| 12366 | #else |
| 12367 | #define xor32_le(dst, src, pad) \ |
| 12368 | (dst)[0] = (src)[0] ^ U8(*(pad)); \ |
| 12369 | (dst)[1] = (src)[1] ^ U8(*(pad) >> 8); \ |
| 12370 | (dst)[2] = (src)[2] ^ U8(*(pad) >> 16); \ |
| 12371 | (dst)[3] = (src)[3] ^ U8(*(pad) >> 24); |
| 12372 | #endif |
| 12373 | |
| 12374 | #define index8_32(a, ix) ((a) + ((ix) * sizeof(uint32_t))) |
| 12375 | |
| 12376 | #define xor32_blocks(dest, source, pad, words) \ |
| 12377 | for (i = 0; i < words; i++) { \ |
| 12378 | xor32_le(index8_32(dest, i), index8_32(source, i), (pad) + i) \ |
| 12379 | } |
| 12380 | |
| 12381 | static void xor_block(uint8_t *restrict dest, const uint8_t *restrict source, |
| 12382 | const uint32_t *restrict pad, unsigned int chunk_size) { |
| 12383 | unsigned int i, full_blocks = chunk_size / (unsigned int) sizeof(uint32_t); |
| 12384 | // have to be carefull, we are going back from uint32 to uint8, so endianness |
| 12385 | // matters again |
| 12386 | xor32_blocks(dest, source, pad, full_blocks) |
| 12387 | |
| 12388 | dest += full_blocks * sizeof(uint32_t); |
| 12389 | source += full_blocks * sizeof(uint32_t); |
| 12390 | pad += full_blocks; |
| 12391 | |
| 12392 | switch (chunk_size % sizeof(uint32_t)) { |
| 12393 | case 1: |
| 12394 | dest[0] = source[0] ^ U8(*pad); |
| 12395 | break; |
| 12396 | case 2: |
| 12397 | dest[0] = source[0] ^ U8(*pad); |
| 12398 | dest[1] = source[1] ^ U8(*pad >> 8); |
| 12399 | break; |
| 12400 | case 3: |
| 12401 | dest[0] = source[0] ^ U8(*pad); |
| 12402 | dest[1] = source[1] ^ U8(*pad >> 8); |
| 12403 | dest[2] = source[2] ^ U8(*pad >> 16); |
| 12404 | break; |
| 12405 | } |
| 12406 | } |
| 12407 | |
| 12408 | static void chacha20_xor_stream(uint8_t *restrict dest, |
| 12409 | const uint8_t *restrict source, size_t length, |
| 12410 | const uint8_t key[CHACHA20_KEY_SIZE], |
| 12411 | const uint8_t nonce[CHACHA20_NONCE_SIZE], |
| 12412 | uint32_t counter) { |
| 12413 | uint32_t state[CHACHA20_STATE_WORDS]; |
| 12414 | uint32_t pad[CHACHA20_STATE_WORDS]; |
| 12415 | size_t i, b, last_block, full_blocks = length / CHACHA20_BLOCK_SIZE; |
| 12416 | initialize_state(state, key, nonce, counter); |
| 12417 | for (b = 0; b < full_blocks; b++) { |
| 12418 | core_block(state, pad); |
| 12419 | increment_counter(state); |
| 12420 | xor32_blocks(dest, source, pad, CHACHA20_STATE_WORDS) dest += |
| 12421 | CHACHA20_BLOCK_SIZE; |
| 12422 | source += CHACHA20_BLOCK_SIZE; |
| 12423 | } |
| 12424 | last_block = length % CHACHA20_BLOCK_SIZE; |
| 12425 | if (last_block > 0) { |
| 12426 | core_block(state, pad); |
| 12427 | xor_block(dest, source, pad, (unsigned int) last_block); |
| 12428 | } |
| 12429 | } |
| 12430 | |
| 12431 | #ifdef FAST_PATH |
| 12432 | #define serialize(poly_key, result) memcpy(poly_key, result, 32) |
| 12433 | #else |
| 12434 | #define store32_le(target, source) \ |
| 12435 | (target)[0] = U8(*(source)); \ |
| 12436 | (target)[1] = U8(*(source) >> 8); \ |
| 12437 | (target)[2] = U8(*(source) >> 16); \ |
| 12438 | (target)[3] = U8(*(source) >> 24); |
| 12439 | |
| 12440 | #define serialize(poly_key, result) \ |
| 12441 | for (i = 0; i < 32 / sizeof(uint32_t); i++) { \ |
| 12442 | store32_le(index8_32(poly_key, i), result + i); \ |
| 12443 | } |
| 12444 | #endif |
| 12445 | |
| 12446 | static void rfc8439_keygen(uint8_t poly_key[32], |
| 12447 | const uint8_t key[CHACHA20_KEY_SIZE], |
| 12448 | const uint8_t nonce[CHACHA20_NONCE_SIZE]) { |
| 12449 | uint32_t state[CHACHA20_STATE_WORDS]; |
| 12450 | uint32_t result[CHACHA20_STATE_WORDS]; |
| 12451 | size_t i; |
| 12452 | initialize_state(state, key, nonce, 0); |
| 12453 | core_block(state, result); |
| 12454 | serialize(poly_key, result); |
| 12455 | (void) i; |
| 12456 | } |
| 12457 | // ******* END: chacha-portable.c ******** |
| 12458 | // ******* BEGIN: poly1305-donna.c ******** |
| 12459 | |
| 12460 | /* auto detect between 32bit / 64bit */ |
| 12461 | #if /* uint128 available on 64bit system*/ \ |
| 12462 | (defined(__SIZEOF_INT128__) && \ |
| 12463 | defined(__LP64__)) /* MSVC 64bit compiler */ \ |
| 12464 | || (defined(_MSC_VER) && defined(_M_X64)) /* gcc >= 4.4 64bit */ \ |
| 12465 | || (defined(__GNUC__) && defined(__LP64__) && \ |
| 12466 | ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)))) |
| 12467 | #define __GUESS64 |
| 12468 | #else |
| 12469 | #define __GUESS32 |
| 12470 | #endif |
| 12471 | |
| 12472 | #if defined(POLY1305_8BIT) |
| 12473 | /* |
| 12474 | poly1305 implementation using 8 bit * 8 bit = 16 bit multiplication and |
| 12475 | 32 bit addition |
| 12476 | |
| 12477 | based on the public domain reference version in supercop by djb |
| 12478 | static */ |
| 12479 | |
| 12480 | #if defined(_MSC_VER) && _MSC_VER < 1700 |
| 12481 | #define POLY1305_NOINLINE |
| 12482 | #elif defined(_MSC_VER) |
| 12483 | #define POLY1305_NOINLINE __declspec(noinline) |
| 12484 | #elif defined(__GNUC__) |
| 12485 | #define POLY1305_NOINLINE __attribute__((noinline)) |
| 12486 | #else |
| 12487 | #define POLY1305_NOINLINE |
| 12488 | #endif |
| 12489 | |
| 12490 | #define poly1305_block_size 16 |
| 12491 | |
| 12492 | /* 17 + sizeof(size_t) + 51*sizeof(unsigned char) */ |
| 12493 | typedef struct poly1305_state_internal_t { |
| 12494 | unsigned char buffer[poly1305_block_size]; |
| 12495 | size_t leftover; |
| 12496 | unsigned char h[17]; |
| 12497 | unsigned char r[17]; |
| 12498 | unsigned char pad[17]; |
| 12499 | unsigned char final; |
| 12500 | } poly1305_state_internal_t; |
| 12501 | |
| 12502 | static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { |
| 12503 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 12504 | size_t i; |
| 12505 | |
| 12506 | st->leftover = 0; |
| 12507 | |
| 12508 | /* h = 0 */ |
| 12509 | for (i = 0; i < 17; i++) st->h[i] = 0; |
| 12510 | |
| 12511 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ |
| 12512 | st->r[0] = key[0] & 0xff; |
| 12513 | st->r[1] = key[1] & 0xff; |
| 12514 | st->r[2] = key[2] & 0xff; |
| 12515 | st->r[3] = key[3] & 0x0f; |
| 12516 | st->r[4] = key[4] & 0xfc; |
| 12517 | st->r[5] = key[5] & 0xff; |
| 12518 | st->r[6] = key[6] & 0xff; |
| 12519 | st->r[7] = key[7] & 0x0f; |
| 12520 | st->r[8] = key[8] & 0xfc; |
| 12521 | st->r[9] = key[9] & 0xff; |
| 12522 | st->r[10] = key[10] & 0xff; |
| 12523 | st->r[11] = key[11] & 0x0f; |
| 12524 | st->r[12] = key[12] & 0xfc; |
| 12525 | st->r[13] = key[13] & 0xff; |
| 12526 | st->r[14] = key[14] & 0xff; |
| 12527 | st->r[15] = key[15] & 0x0f; |
| 12528 | st->r[16] = 0; |
| 12529 | |
| 12530 | /* save pad for later */ |
| 12531 | for (i = 0; i < 16; i++) st->pad[i] = key[i + 16]; |
| 12532 | st->pad[16] = 0; |
| 12533 | |
| 12534 | st->final = 0; |
| 12535 | } |
| 12536 | |
| 12537 | static void poly1305_add(unsigned char h[17], const unsigned char c[17]) { |
| 12538 | unsigned short u; |
| 12539 | unsigned int i; |
| 12540 | for (u = 0, i = 0; i < 17; i++) { |
| 12541 | u += (unsigned short) h[i] + (unsigned short) c[i]; |
| 12542 | h[i] = (unsigned char) u & 0xff; |
| 12543 | u >>= 8; |
| 12544 | } |
| 12545 | } |
| 12546 | |
| 12547 | static void poly1305_squeeze(unsigned char h[17], unsigned long hr[17]) { |
| 12548 | unsigned long u; |
| 12549 | unsigned int i; |
| 12550 | u = 0; |
| 12551 | for (i = 0; i < 16; i++) { |
| 12552 | u += hr[i]; |
| 12553 | h[i] = (unsigned char) u & 0xff; |
| 12554 | u >>= 8; |
| 12555 | } |
| 12556 | u += hr[16]; |
| 12557 | h[16] = (unsigned char) u & 0x03; |
| 12558 | u >>= 2; |
| 12559 | u += (u << 2); /* u *= 5; */ |
| 12560 | for (i = 0; i < 16; i++) { |
| 12561 | u += h[i]; |
| 12562 | h[i] = (unsigned char) u & 0xff; |
| 12563 | u >>= 8; |
| 12564 | } |
| 12565 | h[16] += (unsigned char) u; |
| 12566 | } |
| 12567 | |
| 12568 | static void poly1305_freeze(unsigned char h[17]) { |
| 12569 | const unsigned char minusp[17] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 12570 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 12571 | 0x00, 0x00, 0x00, 0x00, 0xfc}; |
| 12572 | unsigned char horig[17], negative; |
| 12573 | unsigned int i; |
| 12574 | |
| 12575 | /* compute h + -p */ |
| 12576 | for (i = 0; i < 17; i++) horig[i] = h[i]; |
| 12577 | poly1305_add(h, minusp); |
| 12578 | |
| 12579 | /* select h if h < p, or h + -p if h >= p */ |
| 12580 | negative = -(h[16] >> 7); |
| 12581 | for (i = 0; i < 17; i++) h[i] ^= negative & (horig[i] ^ h[i]); |
| 12582 | } |
| 12583 | |
| 12584 | static void poly1305_blocks(poly1305_state_internal_t *st, |
| 12585 | const unsigned char *m, size_t bytes) { |
| 12586 | const unsigned char hibit = st->final ^ 1; /* 1 << 128 */ |
| 12587 | |
| 12588 | while (bytes >= poly1305_block_size) { |
| 12589 | unsigned long hr[17], u; |
| 12590 | unsigned char c[17]; |
| 12591 | unsigned int i, j; |
| 12592 | |
| 12593 | /* h += m */ |
| 12594 | for (i = 0; i < 16; i++) c[i] = m[i]; |
| 12595 | c[16] = hibit; |
| 12596 | poly1305_add(st->h, c); |
| 12597 | |
| 12598 | /* h *= r */ |
| 12599 | for (i = 0; i < 17; i++) { |
| 12600 | u = 0; |
| 12601 | for (j = 0; j <= i; j++) { |
| 12602 | u += (unsigned short) st->h[j] * st->r[i - j]; |
| 12603 | } |
| 12604 | for (j = i + 1; j < 17; j++) { |
| 12605 | unsigned long v = (unsigned short) st->h[j] * st->r[i + 17 - j]; |
| 12606 | v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */ |
| 12607 | u += v; |
| 12608 | } |
| 12609 | hr[i] = u; |
| 12610 | } |
| 12611 | |
| 12612 | /* (partial) h %= p */ |
| 12613 | poly1305_squeeze(st->h, hr); |
| 12614 | |
| 12615 | m += poly1305_block_size; |
| 12616 | bytes -= poly1305_block_size; |
| 12617 | } |
| 12618 | } |
| 12619 | |
| 12620 | static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx, |
| 12621 | unsigned char mac[16]) { |
| 12622 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 12623 | size_t i; |
| 12624 | |
| 12625 | /* process the remaining block */ |
| 12626 | if (st->leftover) { |
| 12627 | size_t i = st->leftover; |
| 12628 | st->buffer[i++] = 1; |
| 12629 | for (; i < poly1305_block_size; i++) st->buffer[i] = 0; |
| 12630 | st->final = 1; |
| 12631 | poly1305_blocks(st, st->buffer, poly1305_block_size); |
| 12632 | } |
| 12633 | |
| 12634 | /* fully reduce h */ |
| 12635 | poly1305_freeze(st->h); |
| 12636 | |
| 12637 | /* h = (h + pad) % (1 << 128) */ |
| 12638 | poly1305_add(st->h, st->pad); |
| 12639 | for (i = 0; i < 16; i++) mac[i] = st->h[i]; |
| 12640 | |
| 12641 | /* zero out the state */ |
| 12642 | for (i = 0; i < 17; i++) st->h[i] = 0; |
| 12643 | for (i = 0; i < 17; i++) st->r[i] = 0; |
| 12644 | for (i = 0; i < 17; i++) st->pad[i] = 0; |
| 12645 | } |
| 12646 | #elif defined(POLY1305_16BIT) |
| 12647 | /* |
| 12648 | poly1305 implementation using 16 bit * 16 bit = 32 bit multiplication |
| 12649 | and 32 bit addition static */ |
| 12650 | |
| 12651 | #if defined(_MSC_VER) && _MSC_VER < 1700 |
| 12652 | #define POLY1305_NOINLINE |
| 12653 | #elif defined(_MSC_VER) |
| 12654 | #define POLY1305_NOINLINE __declspec(noinline) |
| 12655 | #elif defined(__GNUC__) |
| 12656 | #define POLY1305_NOINLINE __attribute__((noinline)) |
| 12657 | #else |
| 12658 | #define POLY1305_NOINLINE |
| 12659 | #endif |
| 12660 | |
| 12661 | #define poly1305_block_size 16 |
| 12662 | |
| 12663 | /* 17 + sizeof(size_t) + 18*sizeof(unsigned short) */ |
| 12664 | typedef struct poly1305_state_internal_t { |
| 12665 | unsigned char buffer[poly1305_block_size]; |
| 12666 | size_t leftover; |
| 12667 | unsigned short r[10]; |
| 12668 | unsigned short h[10]; |
| 12669 | unsigned short pad[8]; |
| 12670 | unsigned char final; |
| 12671 | } poly1305_state_internal_t; |
| 12672 | |
| 12673 | /* interpret two 8 bit unsigned integers as a 16 bit unsigned integer in little |
| 12674 | * endian */ |
| 12675 | static unsigned short U8TO16(const unsigned char *p) { |
| 12676 | return (((unsigned short) (p[0] & 0xff)) | |
| 12677 | ((unsigned short) (p[1] & 0xff) << 8)); |
| 12678 | } |
| 12679 | |
| 12680 | /* store a 16 bit unsigned integer as two 8 bit unsigned integers in little |
| 12681 | * endian */ |
| 12682 | static void U16TO8(unsigned char *p, unsigned short v) { |
| 12683 | p[0] = (v) &0xff; |
| 12684 | p[1] = (v >> 8) & 0xff; |
| 12685 | } |
| 12686 | |
| 12687 | static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { |
| 12688 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 12689 | unsigned short t0, t1, t2, t3, t4, t5, t6, t7; |
| 12690 | size_t i; |
| 12691 | |
| 12692 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ |
| 12693 | t0 = U8TO16(&key[0]); |
| 12694 | st->r[0] = (t0) &0x1fff; |
| 12695 | t1 = U8TO16(&key[2]); |
| 12696 | st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff; |
| 12697 | t2 = U8TO16(&key[4]); |
| 12698 | st->r[2] = ((t1 >> 10) | (t2 << 6)) & 0x1f03; |
| 12699 | t3 = U8TO16(&key[6]); |
| 12700 | st->r[3] = ((t2 >> 7) | (t3 << 9)) & 0x1fff; |
| 12701 | t4 = U8TO16(&key[8]); |
| 12702 | st->r[4] = ((t3 >> 4) | (t4 << 12)) & 0x00ff; |
| 12703 | st->r[5] = ((t4 >> 1)) & 0x1ffe; |
| 12704 | t5 = U8TO16(&key[10]); |
| 12705 | st->r[6] = ((t4 >> 14) | (t5 << 2)) & 0x1fff; |
| 12706 | t6 = U8TO16(&key[12]); |
| 12707 | st->r[7] = ((t5 >> 11) | (t6 << 5)) & 0x1f81; |
| 12708 | t7 = U8TO16(&key[14]); |
| 12709 | st->r[8] = ((t6 >> 8) | (t7 << 8)) & 0x1fff; |
| 12710 | st->r[9] = ((t7 >> 5)) & 0x007f; |
| 12711 | |
| 12712 | /* h = 0 */ |
| 12713 | for (i = 0; i < 10; i++) st->h[i] = 0; |
| 12714 | |
| 12715 | /* save pad for later */ |
| 12716 | for (i = 0; i < 8; i++) st->pad[i] = U8TO16(&key[16 + (2 * i)]); |
| 12717 | |
| 12718 | st->leftover = 0; |
| 12719 | st->final = 0; |
| 12720 | } |
| 12721 | |
| 12722 | static void poly1305_blocks(poly1305_state_internal_t *st, |
| 12723 | const unsigned char *m, size_t bytes) { |
| 12724 | const unsigned short hibit = (st->final) ? 0 : (1 << 11); /* 1 << 128 */ |
| 12725 | unsigned short t0, t1, t2, t3, t4, t5, t6, t7; |
| 12726 | unsigned long d[10]; |
| 12727 | unsigned long c; |
| 12728 | |
| 12729 | while (bytes >= poly1305_block_size) { |
| 12730 | size_t i, j; |
| 12731 | |
| 12732 | /* h += m[i] */ |
| 12733 | t0 = U8TO16(&m[0]); |
| 12734 | st->h[0] += (t0) &0x1fff; |
| 12735 | t1 = U8TO16(&m[2]); |
| 12736 | st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff; |
| 12737 | t2 = U8TO16(&m[4]); |
| 12738 | st->h[2] += ((t1 >> 10) | (t2 << 6)) & 0x1fff; |
| 12739 | t3 = U8TO16(&m[6]); |
| 12740 | st->h[3] += ((t2 >> 7) | (t3 << 9)) & 0x1fff; |
| 12741 | t4 = U8TO16(&m[8]); |
| 12742 | st->h[4] += ((t3 >> 4) | (t4 << 12)) & 0x1fff; |
| 12743 | st->h[5] += ((t4 >> 1)) & 0x1fff; |
| 12744 | t5 = U8TO16(&m[10]); |
| 12745 | st->h[6] += ((t4 >> 14) | (t5 << 2)) & 0x1fff; |
| 12746 | t6 = U8TO16(&m[12]); |
| 12747 | st->h[7] += ((t5 >> 11) | (t6 << 5)) & 0x1fff; |
| 12748 | t7 = U8TO16(&m[14]); |
| 12749 | st->h[8] += ((t6 >> 8) | (t7 << 8)) & 0x1fff; |
| 12750 | st->h[9] += ((t7 >> 5)) | hibit; |
| 12751 | |
| 12752 | /* h *= r, (partial) h %= p */ |
| 12753 | for (i = 0, c = 0; i < 10; i++) { |
| 12754 | d[i] = c; |
| 12755 | for (j = 0; j < 10; j++) { |
| 12756 | d[i] += (unsigned long) st->h[j] * |
| 12757 | ((j <= i) ? st->r[i - j] : (5 * st->r[i + 10 - j])); |
| 12758 | /* Sum(h[i] * r[i] * 5) will overflow slightly above 6 products with an |
| 12759 | * unclamped r, so carry at 5 */ |
| 12760 | if (j == 4) { |
| 12761 | c = (d[i] >> 13); |
| 12762 | d[i] &= 0x1fff; |
| 12763 | } |
| 12764 | } |
| 12765 | c += (d[i] >> 13); |
| 12766 | d[i] &= 0x1fff; |
| 12767 | } |
| 12768 | c = ((c << 2) + c); /* c *= 5 */ |
| 12769 | c += d[0]; |
| 12770 | d[0] = ((unsigned short) c & 0x1fff); |
| 12771 | c = (c >> 13); |
| 12772 | d[1] += c; |
| 12773 | |
| 12774 | for (i = 0; i < 10; i++) st->h[i] = (unsigned short) d[i]; |
| 12775 | |
| 12776 | m += poly1305_block_size; |
| 12777 | bytes -= poly1305_block_size; |
| 12778 | } |
| 12779 | } |
| 12780 | |
| 12781 | static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx, |
| 12782 | unsigned char mac[16]) { |
| 12783 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 12784 | unsigned short c; |
| 12785 | unsigned short g[10]; |
| 12786 | unsigned short mask; |
| 12787 | unsigned long f; |
| 12788 | size_t i; |
| 12789 | |
| 12790 | /* process the remaining block */ |
| 12791 | if (st->leftover) { |
| 12792 | size_t i = st->leftover; |
| 12793 | st->buffer[i++] = 1; |
| 12794 | for (; i < poly1305_block_size; i++) st->buffer[i] = 0; |
| 12795 | st->final = 1; |
| 12796 | poly1305_blocks(st, st->buffer, poly1305_block_size); |
| 12797 | } |
| 12798 | |
| 12799 | /* fully carry h */ |
| 12800 | c = st->h[1] >> 13; |
| 12801 | st->h[1] &= 0x1fff; |
| 12802 | for (i = 2; i < 10; i++) { |
| 12803 | st->h[i] += c; |
| 12804 | c = st->h[i] >> 13; |
| 12805 | st->h[i] &= 0x1fff; |
| 12806 | } |
| 12807 | st->h[0] += (c * 5); |
| 12808 | c = st->h[0] >> 13; |
| 12809 | st->h[0] &= 0x1fff; |
| 12810 | st->h[1] += c; |
| 12811 | c = st->h[1] >> 13; |
| 12812 | st->h[1] &= 0x1fff; |
| 12813 | st->h[2] += c; |
| 12814 | |
| 12815 | /* compute h + -p */ |
| 12816 | g[0] = st->h[0] + 5; |
| 12817 | c = g[0] >> 13; |
| 12818 | g[0] &= 0x1fff; |
| 12819 | for (i = 1; i < 10; i++) { |
| 12820 | g[i] = st->h[i] + c; |
| 12821 | c = g[i] >> 13; |
| 12822 | g[i] &= 0x1fff; |
| 12823 | } |
| 12824 | |
| 12825 | /* select h if h < p, or h + -p if h >= p */ |
| 12826 | mask = (c ^ 1) - 1; |
| 12827 | for (i = 0; i < 10; i++) g[i] &= mask; |
| 12828 | mask = ~mask; |
| 12829 | for (i = 0; i < 10; i++) st->h[i] = (st->h[i] & mask) | g[i]; |
| 12830 | |
| 12831 | /* h = h % (2^128) */ |
| 12832 | st->h[0] = ((st->h[0]) | (st->h[1] << 13)) & 0xffff; |
| 12833 | st->h[1] = ((st->h[1] >> 3) | (st->h[2] << 10)) & 0xffff; |
| 12834 | st->h[2] = ((st->h[2] >> 6) | (st->h[3] << 7)) & 0xffff; |
| 12835 | st->h[3] = ((st->h[3] >> 9) | (st->h[4] << 4)) & 0xffff; |
| 12836 | st->h[4] = ((st->h[4] >> 12) | (st->h[5] << 1) | (st->h[6] << 14)) & 0xffff; |
| 12837 | st->h[5] = ((st->h[6] >> 2) | (st->h[7] << 11)) & 0xffff; |
| 12838 | st->h[6] = ((st->h[7] >> 5) | (st->h[8] << 8)) & 0xffff; |
| 12839 | st->h[7] = ((st->h[8] >> 8) | (st->h[9] << 5)) & 0xffff; |
| 12840 | |
| 12841 | /* mac = (h + pad) % (2^128) */ |
| 12842 | f = (unsigned long) st->h[0] + st->pad[0]; |
| 12843 | st->h[0] = (unsigned short) f; |
| 12844 | for (i = 1; i < 8; i++) { |
| 12845 | f = (unsigned long) st->h[i] + st->pad[i] + (f >> 16); |
| 12846 | st->h[i] = (unsigned short) f; |
| 12847 | } |
| 12848 | |
| 12849 | for (i = 0; i < 8; i++) U16TO8(mac + (i * 2), st->h[i]); |
| 12850 | |
| 12851 | /* zero out the state */ |
| 12852 | for (i = 0; i < 10; i++) st->h[i] = 0; |
| 12853 | for (i = 0; i < 10; i++) st->r[i] = 0; |
| 12854 | for (i = 0; i < 8; i++) st->pad[i] = 0; |
| 12855 | } |
| 12856 | #elif defined(POLY1305_32BIT) || \ |
| 12857 | (!defined(POLY1305_64BIT) && defined(__GUESS32)) |
| 12858 | /* |
| 12859 | poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication |
| 12860 | and 64 bit addition static */ |
| 12861 | |
| 12862 | #if defined(_MSC_VER) && _MSC_VER < 1700 |
| 12863 | #define POLY1305_NOINLINE |
| 12864 | #elif defined(_MSC_VER) |
| 12865 | #define POLY1305_NOINLINE __declspec(noinline) |
| 12866 | #elif defined(__GNUC__) |
| 12867 | #define POLY1305_NOINLINE __attribute__((noinline)) |
| 12868 | #else |
| 12869 | #define POLY1305_NOINLINE |
| 12870 | #endif |
| 12871 | |
| 12872 | #define poly1305_block_size 16 |
| 12873 | |
| 12874 | /* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ |
| 12875 | typedef struct poly1305_state_internal_t { |
| 12876 | unsigned long r[5]; |
| 12877 | unsigned long h[5]; |
| 12878 | unsigned long pad[4]; |
| 12879 | size_t leftover; |
| 12880 | unsigned char buffer[poly1305_block_size]; |
| 12881 | unsigned char final; |
| 12882 | } poly1305_state_internal_t; |
| 12883 | |
| 12884 | /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little |
| 12885 | * endian */ |
| 12886 | static unsigned long U8TO32(const unsigned char *p) { |
| 12887 | return (((unsigned long) (p[0] & 0xff)) | |
| 12888 | ((unsigned long) (p[1] & 0xff) << 8) | |
| 12889 | ((unsigned long) (p[2] & 0xff) << 16) | |
| 12890 | ((unsigned long) (p[3] & 0xff) << 24)); |
| 12891 | } |
| 12892 | |
| 12893 | /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little |
| 12894 | * endian */ |
| 12895 | static void U32TO8(unsigned char *p, unsigned long v) { |
| 12896 | p[0] = (unsigned char) ((v) &0xff); |
| 12897 | p[1] = (unsigned char) ((v >> 8) & 0xff); |
| 12898 | p[2] = (unsigned char) ((v >> 16) & 0xff); |
| 12899 | p[3] = (unsigned char) ((v >> 24) & 0xff); |
| 12900 | } |
| 12901 | |
| 12902 | static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { |
| 12903 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 12904 | |
| 12905 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ |
| 12906 | st->r[0] = (U8TO32(&key[0])) & 0x3ffffff; |
| 12907 | st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03; |
| 12908 | st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff; |
| 12909 | st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff; |
| 12910 | st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; |
| 12911 | |
| 12912 | /* h = 0 */ |
| 12913 | st->h[0] = 0; |
| 12914 | st->h[1] = 0; |
| 12915 | st->h[2] = 0; |
| 12916 | st->h[3] = 0; |
| 12917 | st->h[4] = 0; |
| 12918 | |
| 12919 | /* save pad for later */ |
| 12920 | st->pad[0] = U8TO32(&key[16]); |
| 12921 | st->pad[1] = U8TO32(&key[20]); |
| 12922 | st->pad[2] = U8TO32(&key[24]); |
| 12923 | st->pad[3] = U8TO32(&key[28]); |
| 12924 | |
| 12925 | st->leftover = 0; |
| 12926 | st->final = 0; |
| 12927 | } |
| 12928 | |
| 12929 | static void poly1305_blocks(poly1305_state_internal_t *st, |
| 12930 | const unsigned char *m, size_t bytes) { |
| 12931 | const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ |
| 12932 | unsigned long r0, r1, r2, r3, r4; |
| 12933 | unsigned long s1, s2, s3, s4; |
| 12934 | unsigned long h0, h1, h2, h3, h4; |
| 12935 | uint64_t d0, d1, d2, d3, d4; |
| 12936 | unsigned long c; |
| 12937 | |
| 12938 | r0 = st->r[0]; |
| 12939 | r1 = st->r[1]; |
| 12940 | r2 = st->r[2]; |
| 12941 | r3 = st->r[3]; |
| 12942 | r4 = st->r[4]; |
| 12943 | |
| 12944 | s1 = r1 * 5; |
| 12945 | s2 = r2 * 5; |
| 12946 | s3 = r3 * 5; |
| 12947 | s4 = r4 * 5; |
| 12948 | |
| 12949 | h0 = st->h[0]; |
| 12950 | h1 = st->h[1]; |
| 12951 | h2 = st->h[2]; |
| 12952 | h3 = st->h[3]; |
| 12953 | h4 = st->h[4]; |
| 12954 | |
| 12955 | while (bytes >= poly1305_block_size) { |
| 12956 | /* h += m[i] */ |
| 12957 | h0 += (U8TO32(m + 0)) & 0x3ffffff; |
| 12958 | h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff; |
| 12959 | h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff; |
| 12960 | h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff; |
| 12961 | h4 += (U8TO32(m + 12) >> 8) | hibit; |
| 12962 | |
| 12963 | /* h *= r */ |
| 12964 | d0 = ((uint64_t) h0 * r0) + ((uint64_t) h1 * s4) + ((uint64_t) h2 * s3) + |
| 12965 | ((uint64_t) h3 * s2) + ((uint64_t) h4 * s1); |
| 12966 | d1 = ((uint64_t) h0 * r1) + ((uint64_t) h1 * r0) + ((uint64_t) h2 * s4) + |
| 12967 | ((uint64_t) h3 * s3) + ((uint64_t) h4 * s2); |
| 12968 | d2 = ((uint64_t) h0 * r2) + ((uint64_t) h1 * r1) + ((uint64_t) h2 * r0) + |
| 12969 | ((uint64_t) h3 * s4) + ((uint64_t) h4 * s3); |
| 12970 | d3 = ((uint64_t) h0 * r3) + ((uint64_t) h1 * r2) + ((uint64_t) h2 * r1) + |
| 12971 | ((uint64_t) h3 * r0) + ((uint64_t) h4 * s4); |
| 12972 | d4 = ((uint64_t) h0 * r4) + ((uint64_t) h1 * r3) + ((uint64_t) h2 * r2) + |
| 12973 | ((uint64_t) h3 * r1) + ((uint64_t) h4 * r0); |
| 12974 | |
| 12975 | /* (partial) h %= p */ |
| 12976 | c = (unsigned long) (d0 >> 26); |
| 12977 | h0 = (unsigned long) d0 & 0x3ffffff; |
| 12978 | d1 += c; |
| 12979 | c = (unsigned long) (d1 >> 26); |
| 12980 | h1 = (unsigned long) d1 & 0x3ffffff; |
| 12981 | d2 += c; |
| 12982 | c = (unsigned long) (d2 >> 26); |
| 12983 | h2 = (unsigned long) d2 & 0x3ffffff; |
| 12984 | d3 += c; |
| 12985 | c = (unsigned long) (d3 >> 26); |
| 12986 | h3 = (unsigned long) d3 & 0x3ffffff; |
| 12987 | d4 += c; |
| 12988 | c = (unsigned long) (d4 >> 26); |
| 12989 | h4 = (unsigned long) d4 & 0x3ffffff; |
| 12990 | h0 += c * 5; |
| 12991 | c = (h0 >> 26); |
| 12992 | h0 = h0 & 0x3ffffff; |
| 12993 | h1 += c; |
| 12994 | |
| 12995 | m += poly1305_block_size; |
| 12996 | bytes -= poly1305_block_size; |
| 12997 | } |
| 12998 | |
| 12999 | st->h[0] = h0; |
| 13000 | st->h[1] = h1; |
| 13001 | st->h[2] = h2; |
| 13002 | st->h[3] = h3; |
| 13003 | st->h[4] = h4; |
| 13004 | } |
| 13005 | |
| 13006 | static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx, |
| 13007 | unsigned char mac[16]) { |
| 13008 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 13009 | unsigned long h0, h1, h2, h3, h4, c; |
| 13010 | unsigned long g0, g1, g2, g3, g4; |
| 13011 | uint64_t f; |
| 13012 | unsigned long mask; |
| 13013 | |
| 13014 | /* process the remaining block */ |
| 13015 | if (st->leftover) { |
| 13016 | size_t i = st->leftover; |
| 13017 | st->buffer[i++] = 1; |
| 13018 | for (; i < poly1305_block_size; i++) st->buffer[i] = 0; |
| 13019 | st->final = 1; |
| 13020 | poly1305_blocks(st, st->buffer, poly1305_block_size); |
| 13021 | } |
| 13022 | |
| 13023 | /* fully carry h */ |
| 13024 | h0 = st->h[0]; |
| 13025 | h1 = st->h[1]; |
| 13026 | h2 = st->h[2]; |
| 13027 | h3 = st->h[3]; |
| 13028 | h4 = st->h[4]; |
| 13029 | |
| 13030 | c = h1 >> 26; |
| 13031 | h1 = h1 & 0x3ffffff; |
| 13032 | h2 += c; |
| 13033 | c = h2 >> 26; |
| 13034 | h2 = h2 & 0x3ffffff; |
| 13035 | h3 += c; |
| 13036 | c = h3 >> 26; |
| 13037 | h3 = h3 & 0x3ffffff; |
| 13038 | h4 += c; |
| 13039 | c = h4 >> 26; |
| 13040 | h4 = h4 & 0x3ffffff; |
| 13041 | h0 += c * 5; |
| 13042 | c = h0 >> 26; |
| 13043 | h0 = h0 & 0x3ffffff; |
| 13044 | h1 += c; |
| 13045 | |
| 13046 | /* compute h + -p */ |
| 13047 | g0 = h0 + 5; |
| 13048 | c = g0 >> 26; |
| 13049 | g0 &= 0x3ffffff; |
| 13050 | g1 = h1 + c; |
| 13051 | c = g1 >> 26; |
| 13052 | g1 &= 0x3ffffff; |
| 13053 | g2 = h2 + c; |
| 13054 | c = g2 >> 26; |
| 13055 | g2 &= 0x3ffffff; |
| 13056 | g3 = h3 + c; |
| 13057 | c = g3 >> 26; |
| 13058 | g3 &= 0x3ffffff; |
| 13059 | g4 = h4 + c - (1UL << 26); |
| 13060 | |
| 13061 | /* select h if h < p, or h + -p if h >= p */ |
| 13062 | mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; |
| 13063 | g0 &= mask; |
| 13064 | g1 &= mask; |
| 13065 | g2 &= mask; |
| 13066 | g3 &= mask; |
| 13067 | g4 &= mask; |
| 13068 | mask = ~mask; |
| 13069 | h0 = (h0 & mask) | g0; |
| 13070 | h1 = (h1 & mask) | g1; |
| 13071 | h2 = (h2 & mask) | g2; |
| 13072 | h3 = (h3 & mask) | g3; |
| 13073 | h4 = (h4 & mask) | g4; |
| 13074 | |
| 13075 | /* h = h % (2^128) */ |
| 13076 | h0 = ((h0) | (h1 << 26)) & 0xffffffff; |
| 13077 | h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; |
| 13078 | h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; |
| 13079 | h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; |
| 13080 | |
| 13081 | /* mac = (h + pad) % (2^128) */ |
| 13082 | f = (uint64_t) h0 + st->pad[0]; |
| 13083 | h0 = (unsigned long) f; |
| 13084 | f = (uint64_t) h1 + st->pad[1] + (f >> 32); |
| 13085 | h1 = (unsigned long) f; |
| 13086 | f = (uint64_t) h2 + st->pad[2] + (f >> 32); |
| 13087 | h2 = (unsigned long) f; |
| 13088 | f = (uint64_t) h3 + st->pad[3] + (f >> 32); |
| 13089 | h3 = (unsigned long) f; |
| 13090 | |
| 13091 | U32TO8(mac + 0, h0); |
| 13092 | U32TO8(mac + 4, h1); |
| 13093 | U32TO8(mac + 8, h2); |
| 13094 | U32TO8(mac + 12, h3); |
| 13095 | |
| 13096 | /* zero out the state */ |
| 13097 | st->h[0] = 0; |
| 13098 | st->h[1] = 0; |
| 13099 | st->h[2] = 0; |
| 13100 | st->h[3] = 0; |
| 13101 | st->h[4] = 0; |
| 13102 | st->r[0] = 0; |
| 13103 | st->r[1] = 0; |
| 13104 | st->r[2] = 0; |
| 13105 | st->r[3] = 0; |
| 13106 | st->r[4] = 0; |
| 13107 | st->pad[0] = 0; |
| 13108 | st->pad[1] = 0; |
| 13109 | st->pad[2] = 0; |
| 13110 | st->pad[3] = 0; |
| 13111 | } |
| 13112 | |
| 13113 | #else |
| 13114 | /* |
| 13115 | poly1305 implementation using 64 bit * 64 bit = 128 bit multiplication |
| 13116 | and 128 bit addition static */ |
| 13117 | |
| 13118 | #if defined(_MSC_VER) |
| 13119 | |
| 13120 | typedef struct uint128_t { |
| 13121 | uint64_t lo; |
| 13122 | uint64_t hi; |
| 13123 | } uint128_t; |
| 13124 | |
| 13125 | #define MUL128(out, x, y) out.lo = _umul128((x), (y), &out.hi) |
| 13126 | #define ADD(out, in) \ |
| 13127 | { \ |
| 13128 | uint64_t t = out.lo; \ |
| 13129 | out.lo += in.lo; \ |
| 13130 | out.hi += (out.lo < t) + in.hi; \ |
| 13131 | } |
| 13132 | #define ADDLO(out, in) \ |
| 13133 | { \ |
| 13134 | uint64_t t = out.lo; \ |
| 13135 | out.lo += in; \ |
| 13136 | out.hi += (out.lo < t); \ |
| 13137 | } |
| 13138 | #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) |
| 13139 | #define LO(in) (in.lo) |
| 13140 | |
| 13141 | #if defined(_MSC_VER) && _MSC_VER < 1700 |
| 13142 | #define POLY1305_NOINLINE |
| 13143 | #else |
| 13144 | #define POLY1305_NOINLINE __declspec(noinline) |
| 13145 | #endif |
| 13146 | #elif defined(__GNUC__) |
| 13147 | #if defined(__SIZEOF_INT128__) |
| 13148 | // Get rid of GCC warning "ISO C does not support '__int128' types" |
| 13149 | #pragma GCC diagnostic push |
| 13150 | #pragma GCC diagnostic ignored "-Wpedantic" |
| 13151 | typedef unsigned __int128 uint128_t; |
| 13152 | #pragma GCC diagnostic pop |
| 13153 | #else |
| 13154 | typedef unsigned uint128_t __attribute__((mode(TI))); |
| 13155 | #endif |
| 13156 | |
| 13157 | #define MUL128(out, x, y) out = ((uint128_t) x * y) |
| 13158 | #define ADD(out, in) out += in |
| 13159 | #define ADDLO(out, in) out += in |
| 13160 | #define SHR(in, shift) (uint64_t)(in >> (shift)) |
| 13161 | #define LO(in) (uint64_t)(in) |
| 13162 | |
| 13163 | #define POLY1305_NOINLINE __attribute__((noinline)) |
| 13164 | #endif |
| 13165 | |
| 13166 | #define poly1305_block_size 16 |
| 13167 | |
| 13168 | /* 17 + sizeof(size_t) + 8*sizeof(uint64_t) */ |
| 13169 | typedef struct poly1305_state_internal_t { |
| 13170 | uint64_t r[3]; |
| 13171 | uint64_t h[3]; |
| 13172 | uint64_t pad[2]; |
| 13173 | size_t leftover; |
| 13174 | unsigned char buffer[poly1305_block_size]; |
| 13175 | unsigned char final; |
| 13176 | } poly1305_state_internal_t; |
| 13177 | |
| 13178 | /* interpret eight 8 bit unsigned integers as a 64 bit unsigned integer in |
| 13179 | * little endian */ |
| 13180 | static uint64_t U8TO64(const unsigned char *p) { |
| 13181 | return (((uint64_t) (p[0] & 0xff)) | ((uint64_t) (p[1] & 0xff) << 8) | |
| 13182 | ((uint64_t) (p[2] & 0xff) << 16) | ((uint64_t) (p[3] & 0xff) << 24) | |
| 13183 | ((uint64_t) (p[4] & 0xff) << 32) | ((uint64_t) (p[5] & 0xff) << 40) | |
| 13184 | ((uint64_t) (p[6] & 0xff) << 48) | ((uint64_t) (p[7] & 0xff) << 56)); |
| 13185 | } |
| 13186 | |
| 13187 | /* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little |
| 13188 | * endian */ |
| 13189 | static void U64TO8(unsigned char *p, uint64_t v) { |
| 13190 | p[0] = (unsigned char) ((v) &0xff); |
| 13191 | p[1] = (unsigned char) ((v >> 8) & 0xff); |
| 13192 | p[2] = (unsigned char) ((v >> 16) & 0xff); |
| 13193 | p[3] = (unsigned char) ((v >> 24) & 0xff); |
| 13194 | p[4] = (unsigned char) ((v >> 32) & 0xff); |
| 13195 | p[5] = (unsigned char) ((v >> 40) & 0xff); |
| 13196 | p[6] = (unsigned char) ((v >> 48) & 0xff); |
| 13197 | p[7] = (unsigned char) ((v >> 56) & 0xff); |
| 13198 | } |
| 13199 | |
| 13200 | static void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { |
| 13201 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 13202 | uint64_t t0, t1; |
| 13203 | |
| 13204 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ |
| 13205 | t0 = U8TO64(&key[0]); |
| 13206 | t1 = U8TO64(&key[8]); |
| 13207 | |
| 13208 | st->r[0] = (t0) &0xffc0fffffff; |
| 13209 | st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; |
| 13210 | st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f; |
| 13211 | |
| 13212 | /* h = 0 */ |
| 13213 | st->h[0] = 0; |
| 13214 | st->h[1] = 0; |
| 13215 | st->h[2] = 0; |
| 13216 | |
| 13217 | /* save pad for later */ |
| 13218 | st->pad[0] = U8TO64(&key[16]); |
| 13219 | st->pad[1] = U8TO64(&key[24]); |
| 13220 | |
| 13221 | st->leftover = 0; |
| 13222 | st->final = 0; |
| 13223 | } |
| 13224 | |
| 13225 | static void poly1305_blocks(poly1305_state_internal_t *st, |
| 13226 | const unsigned char *m, size_t bytes) { |
| 13227 | const uint64_t hibit = (st->final) ? 0 : ((uint64_t) 1 << 40); /* 1 << 128 */ |
| 13228 | uint64_t r0, r1, r2; |
| 13229 | uint64_t s1, s2; |
| 13230 | uint64_t h0, h1, h2; |
| 13231 | uint64_t c; |
| 13232 | uint128_t d0, d1, d2, d; |
| 13233 | |
| 13234 | r0 = st->r[0]; |
| 13235 | r1 = st->r[1]; |
| 13236 | r2 = st->r[2]; |
| 13237 | |
| 13238 | h0 = st->h[0]; |
| 13239 | h1 = st->h[1]; |
| 13240 | h2 = st->h[2]; |
| 13241 | |
| 13242 | s1 = r1 * (5 << 2); |
| 13243 | s2 = r2 * (5 << 2); |
| 13244 | |
| 13245 | while (bytes >= poly1305_block_size) { |
| 13246 | uint64_t t0, t1; |
| 13247 | |
| 13248 | /* h += m[i] */ |
| 13249 | t0 = U8TO64(&m[0]); |
| 13250 | t1 = U8TO64(&m[8]); |
| 13251 | |
| 13252 | h0 += ((t0) &0xfffffffffff); |
| 13253 | h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); |
| 13254 | h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit; |
| 13255 | |
| 13256 | /* h *= r */ |
| 13257 | MUL128(d0, h0, r0); |
| 13258 | MUL128(d, h1, s2); |
| 13259 | ADD(d0, d); |
| 13260 | MUL128(d, h2, s1); |
| 13261 | ADD(d0, d); |
| 13262 | MUL128(d1, h0, r1); |
| 13263 | MUL128(d, h1, r0); |
| 13264 | ADD(d1, d); |
| 13265 | MUL128(d, h2, s2); |
| 13266 | ADD(d1, d); |
| 13267 | MUL128(d2, h0, r2); |
| 13268 | MUL128(d, h1, r1); |
| 13269 | ADD(d2, d); |
| 13270 | MUL128(d, h2, r0); |
| 13271 | ADD(d2, d); |
| 13272 | |
| 13273 | /* (partial) h %= p */ |
| 13274 | c = SHR(d0, 44); |
| 13275 | h0 = LO(d0) & 0xfffffffffff; |
| 13276 | ADDLO(d1, c); |
| 13277 | c = SHR(d1, 44); |
| 13278 | h1 = LO(d1) & 0xfffffffffff; |
| 13279 | ADDLO(d2, c); |
| 13280 | c = SHR(d2, 42); |
| 13281 | h2 = LO(d2) & 0x3ffffffffff; |
| 13282 | h0 += c * 5; |
| 13283 | c = (h0 >> 44); |
| 13284 | h0 = h0 & 0xfffffffffff; |
| 13285 | h1 += c; |
| 13286 | |
| 13287 | m += poly1305_block_size; |
| 13288 | bytes -= poly1305_block_size; |
| 13289 | } |
| 13290 | |
| 13291 | st->h[0] = h0; |
| 13292 | st->h[1] = h1; |
| 13293 | st->h[2] = h2; |
| 13294 | } |
| 13295 | |
| 13296 | static POLY1305_NOINLINE void poly1305_finish(poly1305_context *ctx, |
| 13297 | unsigned char mac[16]) { |
| 13298 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 13299 | uint64_t h0, h1, h2, c; |
| 13300 | uint64_t g0, g1, g2; |
| 13301 | uint64_t t0, t1; |
| 13302 | |
| 13303 | /* process the remaining block */ |
| 13304 | if (st->leftover) { |
| 13305 | size_t i = st->leftover; |
| 13306 | st->buffer[i] = 1; |
| 13307 | for (i = i + 1; i < poly1305_block_size; i++) st->buffer[i] = 0; |
| 13308 | st->final = 1; |
| 13309 | poly1305_blocks(st, st->buffer, poly1305_block_size); |
| 13310 | } |
| 13311 | |
| 13312 | /* fully carry h */ |
| 13313 | h0 = st->h[0]; |
| 13314 | h1 = st->h[1]; |
| 13315 | h2 = st->h[2]; |
| 13316 | |
| 13317 | c = (h1 >> 44); |
| 13318 | h1 &= 0xfffffffffff; |
| 13319 | h2 += c; |
| 13320 | c = (h2 >> 42); |
| 13321 | h2 &= 0x3ffffffffff; |
| 13322 | h0 += c * 5; |
| 13323 | c = (h0 >> 44); |
| 13324 | h0 &= 0xfffffffffff; |
| 13325 | h1 += c; |
| 13326 | c = (h1 >> 44); |
| 13327 | h1 &= 0xfffffffffff; |
| 13328 | h2 += c; |
| 13329 | c = (h2 >> 42); |
| 13330 | h2 &= 0x3ffffffffff; |
| 13331 | h0 += c * 5; |
| 13332 | c = (h0 >> 44); |
| 13333 | h0 &= 0xfffffffffff; |
| 13334 | h1 += c; |
| 13335 | |
| 13336 | /* compute h + -p */ |
| 13337 | g0 = h0 + 5; |
| 13338 | c = (g0 >> 44); |
| 13339 | g0 &= 0xfffffffffff; |
| 13340 | g1 = h1 + c; |
| 13341 | c = (g1 >> 44); |
| 13342 | g1 &= 0xfffffffffff; |
| 13343 | g2 = h2 + c - ((uint64_t) 1 << 42); |
| 13344 | |
| 13345 | /* select h if h < p, or h + -p if h >= p */ |
| 13346 | c = (g2 >> ((sizeof(uint64_t) * 8) - 1)) - 1; |
| 13347 | g0 &= c; |
| 13348 | g1 &= c; |
| 13349 | g2 &= c; |
| 13350 | c = ~c; |
| 13351 | h0 = (h0 & c) | g0; |
| 13352 | h1 = (h1 & c) | g1; |
| 13353 | h2 = (h2 & c) | g2; |
| 13354 | |
| 13355 | /* h = (h + pad) */ |
| 13356 | t0 = st->pad[0]; |
| 13357 | t1 = st->pad[1]; |
| 13358 | |
| 13359 | h0 += ((t0) &0xfffffffffff); |
| 13360 | c = (h0 >> 44); |
| 13361 | h0 &= 0xfffffffffff; |
| 13362 | h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; |
| 13363 | c = (h1 >> 44); |
| 13364 | h1 &= 0xfffffffffff; |
| 13365 | h2 += (((t1 >> 24)) & 0x3ffffffffff) + c; |
| 13366 | h2 &= 0x3ffffffffff; |
| 13367 | |
| 13368 | /* mac = h % (2^128) */ |
| 13369 | h0 = ((h0) | (h1 << 44)); |
| 13370 | h1 = ((h1 >> 20) | (h2 << 24)); |
| 13371 | |
| 13372 | U64TO8(&mac[0], h0); |
| 13373 | U64TO8(&mac[8], h1); |
| 13374 | |
| 13375 | /* zero out the state */ |
| 13376 | st->h[0] = 0; |
| 13377 | st->h[1] = 0; |
| 13378 | st->h[2] = 0; |
| 13379 | st->r[0] = 0; |
| 13380 | st->r[1] = 0; |
| 13381 | st->r[2] = 0; |
| 13382 | st->pad[0] = 0; |
| 13383 | st->pad[1] = 0; |
| 13384 | } |
| 13385 | |
| 13386 | #endif |
| 13387 | |
| 13388 | static void poly1305_update(poly1305_context *ctx, const unsigned char *m, |
| 13389 | size_t bytes) { |
| 13390 | poly1305_state_internal_t *st = (poly1305_state_internal_t *) ctx; |
| 13391 | size_t i; |
| 13392 | |
| 13393 | /* handle leftover */ |
| 13394 | if (st->leftover) { |
| 13395 | size_t want = (poly1305_block_size - st->leftover); |
| 13396 | if (want > bytes) want = bytes; |
| 13397 | for (i = 0; i < want; i++) st->buffer[st->leftover + i] = m[i]; |
| 13398 | bytes -= want; |
| 13399 | m += want; |
| 13400 | st->leftover += want; |
| 13401 | if (st->leftover < poly1305_block_size) return; |
| 13402 | poly1305_blocks(st, st->buffer, poly1305_block_size); |
| 13403 | st->leftover = 0; |
| 13404 | } |
| 13405 | |
| 13406 | /* process full blocks */ |
| 13407 | if (bytes >= poly1305_block_size) { |
| 13408 | size_t want = (bytes & (size_t) ~(poly1305_block_size - 1)); |
| 13409 | poly1305_blocks(st, m, want); |
| 13410 | m += want; |
| 13411 | bytes -= want; |
| 13412 | } |
| 13413 | |
| 13414 | /* store leftover */ |
| 13415 | if (bytes) { |
| 13416 | for (i = 0; i < bytes; i++) st->buffer[st->leftover + i] = m[i]; |
| 13417 | st->leftover += bytes; |
| 13418 | } |
| 13419 | } |
| 13420 | |
| 13421 | // ******* END: poly1305-donna.c ******** |
| 13422 | // ******* BEGIN: portable8439.c ******** |
| 13423 | |
| 13424 | #define __CHACHA20_BLOCK_SIZE (64) |
| 13425 | #define __POLY1305_KEY_SIZE (32) |
| 13426 | |
| 13427 | static PORTABLE_8439_DECL uint8_t __ZEROES[16] = {0}; |
| 13428 | static PORTABLE_8439_DECL void pad_if_needed(poly1305_context *ctx, |
| 13429 | size_t size) { |
| 13430 | size_t padding = size % 16; |
| 13431 | if (padding != 0) { |
| 13432 | poly1305_update(ctx, __ZEROES, 16 - padding); |
| 13433 | } |
| 13434 | } |
| 13435 | |
| 13436 | #define __u8(v) ((uint8_t) ((v) &0xFF)) |
| 13437 | |
| 13438 | // TODO: make this depending on the unaligned/native read size possible |
| 13439 | static PORTABLE_8439_DECL void write_64bit_int(poly1305_context *ctx, |
| 13440 | uint64_t value) { |
| 13441 | uint8_t result[8]; |
| 13442 | result[0] = __u8(value); |
| 13443 | result[1] = __u8(value >> 8); |
| 13444 | result[2] = __u8(value >> 16); |
| 13445 | result[3] = __u8(value >> 24); |
| 13446 | result[4] = __u8(value >> 32); |
| 13447 | result[5] = __u8(value >> 40); |
| 13448 | result[6] = __u8(value >> 48); |
| 13449 | result[7] = __u8(value >> 56); |
| 13450 | poly1305_update(ctx, result, 8); |
| 13451 | } |
| 13452 | |
| 13453 | static PORTABLE_8439_DECL void poly1305_calculate_mac( |
| 13454 | uint8_t *mac, const uint8_t *cipher_text, size_t cipher_text_size, |
| 13455 | const uint8_t key[RFC_8439_KEY_SIZE], |
| 13456 | const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *ad, |
| 13457 | size_t ad_size) { |
| 13458 | // init poly key (section 2.6) |
| 13459 | uint8_t poly_key[__POLY1305_KEY_SIZE] = {0}; |
| 13460 | poly1305_context poly_ctx; |
| 13461 | rfc8439_keygen(poly_key, key, nonce); |
| 13462 | // start poly1305 mac |
| 13463 | poly1305_init(&poly_ctx, poly_key); |
| 13464 | |
| 13465 | if (ad != NULL && ad_size > 0) { |
| 13466 | // write AD if present |
| 13467 | poly1305_update(&poly_ctx, ad, ad_size); |
| 13468 | pad_if_needed(&poly_ctx, ad_size); |
| 13469 | } |
| 13470 | |
| 13471 | // now write the cipher text |
| 13472 | poly1305_update(&poly_ctx, cipher_text, cipher_text_size); |
| 13473 | pad_if_needed(&poly_ctx, cipher_text_size); |
| 13474 | |
| 13475 | // write sizes |
| 13476 | write_64bit_int(&poly_ctx, ad_size); |
| 13477 | write_64bit_int(&poly_ctx, cipher_text_size); |
| 13478 | |
| 13479 | // calculate MAC |
| 13480 | poly1305_finish(&poly_ctx, mac); |
| 13481 | } |
| 13482 | |
| 13483 | #define MG_PM(p) ((size_t) (p)) |
| 13484 | |
| 13485 | // pointers overlap if the smaller either ahead of the end, |
| 13486 | // or its end is before the start of the other |
| 13487 | // |
| 13488 | // s_size should be smaller or equal to b_size |
| 13489 | #define MG_OVERLAPPING(s, s_size, b, b_size) \ |
| 13490 | (MG_PM(s) < MG_PM((b) + (b_size))) && (MG_PM(b) < MG_PM((s) + (s_size))) |
| 13491 | |
| 13492 | PORTABLE_8439_DECL size_t mg_chacha20_poly1305_encrypt( |
| 13493 | uint8_t *restrict cipher_text, const uint8_t key[RFC_8439_KEY_SIZE], |
| 13494 | const uint8_t nonce[RFC_8439_NONCE_SIZE], const uint8_t *restrict ad, |
| 13495 | size_t ad_size, const uint8_t *restrict plain_text, |
| 13496 | size_t plain_text_size) { |
| 13497 | size_t new_size = plain_text_size + RFC_8439_TAG_SIZE; |
| 13498 | if (MG_OVERLAPPING(plain_text, plain_text_size, cipher_text, new_size)) { |
| 13499 | return (size_t) -1; |
| 13500 | } |
| 13501 | chacha20_xor_stream(cipher_text, plain_text, plain_text_size, key, nonce, 1); |
| 13502 | poly1305_calculate_mac(cipher_text + plain_text_size, cipher_text, |
| 13503 | plain_text_size, key, nonce, ad, ad_size); |
| 13504 | return new_size; |
| 13505 | } |
| 13506 | |
| 13507 | PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt( |
| 13508 | uint8_t *restrict plain_text, const uint8_t key[RFC_8439_KEY_SIZE], |
| 13509 | const uint8_t nonce[RFC_8439_NONCE_SIZE], |
| 13510 | const uint8_t *restrict cipher_text, size_t cipher_text_size) { |
| 13511 | // first we calculate the mac and see if it lines up, only then do we decrypt |
| 13512 | size_t actual_size = cipher_text_size - RFC_8439_TAG_SIZE; |
| 13513 | if (MG_OVERLAPPING(plain_text, actual_size, cipher_text, cipher_text_size)) { |
| 13514 | return (size_t) -1; |
| 13515 | } |
| 13516 | |
| 13517 | chacha20_xor_stream(plain_text, cipher_text, actual_size, key, nonce, 1); |
| 13518 | return actual_size; |
| 13519 | } |
| 13520 | // ******* END: portable8439.c ******** |
| 13521 | #endif // MG_TLS == MG_TLS_BUILTIN |
| 13522 | |
| 13523 | #ifdef MG_ENABLE_LINES |
| 13524 | #line 1 "src/tls_dummy.c" |
| 13525 | #endif |
| 13526 | |
| 13527 | |
| 13528 | #if MG_TLS == MG_TLS_NONE |
| 13529 | void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { |
| 13530 | (void) opts; |
| 13531 | mg_error(c, "TLS is not enabled"); |
| 13532 | } |
| 13533 | void mg_tls_handshake(struct mg_connection *c) { |
| 13534 | (void) c; |
| 13535 | } |
| 13536 | void mg_tls_free(struct mg_connection *c) { |
| 13537 | (void) c; |
| 13538 | } |
| 13539 | long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) { |
| 13540 | return c == NULL || buf == NULL || len == 0 ? 0 : -1; |
| 13541 | } |
| 13542 | long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { |
| 13543 | return c == NULL || buf == NULL || len == 0 ? 0 : -1; |
| 13544 | } |
| 13545 | size_t mg_tls_pending(struct mg_connection *c) { |
| 13546 | (void) c; |
| 13547 | return 0; |
| 13548 | } |
| 13549 | void mg_tls_ctx_init(struct mg_mgr *mgr) { |
| 13550 | (void) mgr; |
| 13551 | } |
| 13552 | void mg_tls_ctx_free(struct mg_mgr *mgr) { |
| 13553 | (void) mgr; |
| 13554 | } |
| 13555 | #endif |
| 13556 | |
| 13557 | #ifdef MG_ENABLE_LINES |
| 13558 | #line 1 "src/tls_mbed.c" |
| 13559 | #endif |
| 13560 | |
| 13561 | |
| 13562 | |
| 13563 | #if MG_TLS == MG_TLS_MBED |
| 13564 | |
| 13565 | #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 |
| 13566 | #define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL |
| 13567 | #else |
| 13568 | #define MG_MBEDTLS_RNG_GET |
| 13569 | #endif |
| 13570 | |
| 13571 | static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) { |
| 13572 | mg_random(buf, len); |
| 13573 | (void) ctx; |
| 13574 | return 0; |
| 13575 | } |
| 13576 | |
| 13577 | static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) { |
| 13578 | int rc; |
| 13579 | if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true; |
| 13580 | if (str.buf[0] == '-') str.len++; // PEM, include trailing NUL |
| 13581 | if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.buf, str.len)) != 0) { |
| 13582 | MG_ERROR(("cert err %#x", -rc)); |
| 13583 | return false; |
| 13584 | } |
| 13585 | return true; |
| 13586 | } |
| 13587 | |
| 13588 | static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) { |
| 13589 | int rc; |
| 13590 | if (str.buf == NULL || str.buf[0] == '\0' || str.buf[0] == '*') return true; |
| 13591 | if (str.buf[0] == '-') str.len++; // PEM, include trailing NUL |
| 13592 | if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.buf, str.len, NULL, |
| 13593 | 0 MG_MBEDTLS_RNG_GET)) != 0) { |
| 13594 | MG_ERROR(("key err %#x", -rc)); |
| 13595 | return false; |
| 13596 | } |
| 13597 | return true; |
| 13598 | } |
| 13599 | |
| 13600 | void mg_tls_free(struct mg_connection *c) { |
| 13601 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 13602 | if (tls != NULL) { |
| 13603 | mbedtls_ssl_free(&tls->ssl); |
| 13604 | mbedtls_pk_free(&tls->pk); |
| 13605 | mbedtls_x509_crt_free(&tls->ca); |
| 13606 | mbedtls_x509_crt_free(&tls->cert); |
| 13607 | mbedtls_ssl_config_free(&tls->conf); |
| 13608 | #ifdef MBEDTLS_SSL_SESSION_TICKETS |
| 13609 | mbedtls_ssl_ticket_free(&tls->ticket); |
| 13610 | #endif |
| 13611 | free(tls); |
| 13612 | c->tls = NULL; |
| 13613 | } |
| 13614 | } |
| 13615 | |
| 13616 | static int mg_net_send(void *ctx, const unsigned char *buf, size_t len) { |
| 13617 | long n = mg_io_send((struct mg_connection *) ctx, buf, len); |
| 13618 | MG_VERBOSE(("%lu n=%ld e=%d", ((struct mg_connection *) ctx)->id, n, errno)); |
| 13619 | if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE; |
| 13620 | if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET; |
| 13621 | if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_SEND_FAILED; |
| 13622 | return (int) n; |
| 13623 | } |
| 13624 | |
| 13625 | static int mg_net_recv(void *ctx, unsigned char *buf, size_t len) { |
| 13626 | long n = mg_io_recv((struct mg_connection *) ctx, buf, len); |
| 13627 | MG_VERBOSE(("%lu n=%ld", ((struct mg_connection *) ctx)->id, n)); |
| 13628 | if (n == MG_IO_WAIT) return MBEDTLS_ERR_SSL_WANT_WRITE; |
| 13629 | if (n == MG_IO_RESET) return MBEDTLS_ERR_NET_CONN_RESET; |
| 13630 | if (n == MG_IO_ERR) return MBEDTLS_ERR_NET_RECV_FAILED; |
| 13631 | return (int) n; |
| 13632 | } |
| 13633 | |
| 13634 | void mg_tls_handshake(struct mg_connection *c) { |
| 13635 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 13636 | int rc = mbedtls_ssl_handshake(&tls->ssl); |
| 13637 | if (rc == 0) { // Success |
| 13638 | MG_DEBUG(("%lu success", c->id)); |
| 13639 | c->is_tls_hs = 0; |
| 13640 | mg_call(c, MG_EV_TLS_HS, NULL); |
| 13641 | } else if (rc == MBEDTLS_ERR_SSL_WANT_READ || |
| 13642 | rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending |
| 13643 | MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting, |
| 13644 | c->is_tls_hs, rc, -rc)); |
| 13645 | } else { |
| 13646 | mg_error(c, "TLS handshake: -%#x", -rc); // Error |
| 13647 | } |
| 13648 | } |
| 13649 | |
| 13650 | static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) { |
| 13651 | n = (int) strlen(s2) - 1; |
| 13652 | MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2)); |
| 13653 | (void) s; |
| 13654 | } |
| 13655 | |
| 13656 | void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { |
| 13657 | struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); |
| 13658 | int rc = 0; |
| 13659 | c->tls = tls; |
| 13660 | if (c->tls == NULL) { |
| 13661 | mg_error(c, "TLS OOM"); |
| 13662 | goto fail; |
| 13663 | } |
| 13664 | if (c->is_listening) goto fail; |
| 13665 | MG_DEBUG(("%lu Setting TLS", c->id)); |
| 13666 | MG_PROF_ADD(c, "mbedtls_init_start"); |
| 13667 | #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 && \ |
| 13668 | defined(MBEDTLS_PSA_CRYPTO_C) |
| 13669 | psa_crypto_init(); // https://github.com/Mbed-TLS/mbedtls/issues/9072#issuecomment-2084845711 |
| 13670 | #endif |
| 13671 | mbedtls_ssl_init(&tls->ssl); |
| 13672 | mbedtls_ssl_config_init(&tls->conf); |
| 13673 | mbedtls_x509_crt_init(&tls->ca); |
| 13674 | mbedtls_x509_crt_init(&tls->cert); |
| 13675 | mbedtls_pk_init(&tls->pk); |
| 13676 | mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c); |
| 13677 | #if defined(MG_MBEDTLS_DEBUG_LEVEL) |
| 13678 | mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL); |
| 13679 | #endif |
| 13680 | if ((rc = mbedtls_ssl_config_defaults( |
| 13681 | &tls->conf, |
| 13682 | c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, |
| 13683 | MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { |
| 13684 | mg_error(c, "tls defaults %#x", -rc); |
| 13685 | goto fail; |
| 13686 | } |
| 13687 | mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c); |
| 13688 | |
| 13689 | if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) { |
| 13690 | // NOTE: MBEDTLS_SSL_VERIFY_NONE is not supported for TLS1.3 on client side |
| 13691 | // See https://github.com/Mbed-TLS/mbedtls/issues/7075 |
| 13692 | mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); |
| 13693 | } else { |
| 13694 | if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail; |
| 13695 | mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL); |
| 13696 | if (c->is_client && opts->name.buf != NULL && opts->name.buf[0] != '\0') { |
| 13697 | char *host = mg_mprintf("%.*s", opts->name.len, opts->name.buf); |
| 13698 | mbedtls_ssl_set_hostname(&tls->ssl, host); |
| 13699 | MG_DEBUG(("%lu hostname verification: %s", c->id, host)); |
| 13700 | free(host); |
| 13701 | } |
| 13702 | mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); |
| 13703 | } |
| 13704 | if (!mg_load_cert(opts->cert, &tls->cert)) goto fail; |
| 13705 | if (!mg_load_key(opts->key, &tls->pk)) goto fail; |
| 13706 | if (tls->cert.version && |
| 13707 | (rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk)) != 0) { |
| 13708 | mg_error(c, "own cert %#x", -rc); |
| 13709 | goto fail; |
| 13710 | } |
| 13711 | |
| 13712 | #ifdef MBEDTLS_SSL_SESSION_TICKETS |
| 13713 | mbedtls_ssl_conf_session_tickets_cb( |
| 13714 | &tls->conf, mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse, |
| 13715 | &((struct mg_tls_ctx *) c->mgr->tls_ctx)->tickets); |
| 13716 | #endif |
| 13717 | |
| 13718 | if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { |
| 13719 | mg_error(c, "setup err %#x", -rc); |
| 13720 | goto fail; |
| 13721 | } |
| 13722 | c->is_tls = 1; |
| 13723 | c->is_tls_hs = 1; |
| 13724 | mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0); |
| 13725 | MG_PROF_ADD(c, "mbedtls_init_end"); |
| 13726 | return; |
| 13727 | fail: |
| 13728 | mg_tls_free(c); |
| 13729 | } |
| 13730 | |
| 13731 | size_t mg_tls_pending(struct mg_connection *c) { |
| 13732 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 13733 | return tls == NULL ? 0 : mbedtls_ssl_get_bytes_avail(&tls->ssl); |
| 13734 | } |
| 13735 | |
| 13736 | long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) { |
| 13737 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 13738 | long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len); |
| 13739 | if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP |
| 13740 | if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) |
| 13741 | return MG_IO_WAIT; |
| 13742 | #if defined(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) |
| 13743 | if (n == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) { |
| 13744 | return MG_IO_WAIT; |
| 13745 | } |
| 13746 | #endif |
| 13747 | if (n <= 0) return MG_IO_ERR; |
| 13748 | return n; |
| 13749 | } |
| 13750 | |
| 13751 | long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { |
| 13752 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 13753 | long n; |
| 13754 | bool was_throttled = c->is_tls_throttled; // see #3074 |
| 13755 | n = was_throttled ? mbedtls_ssl_write(&tls->ssl, tls->throttled_buf, |
| 13756 | tls->throttled_len) /* flush old data */ |
| 13757 | : mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, |
| 13758 | len); // encrypt current data |
| 13759 | c->is_tls_throttled = |
| 13760 | (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE); |
| 13761 | if (was_throttled) return MG_IO_WAIT; // flushed throttled data instead |
| 13762 | if (c->is_tls_throttled) { |
| 13763 | tls->throttled_buf = (unsigned char *)buf; // MbedTLS code actually ignores |
| 13764 | tls->throttled_len = len; // these, but let's play API rules |
| 13765 | return (long) len; // already encripted that when throttled |
| 13766 | } |
| 13767 | if (n <= 0) return MG_IO_ERR; |
| 13768 | return n; |
| 13769 | } |
| 13770 | |
| 13771 | void mg_tls_ctx_init(struct mg_mgr *mgr) { |
| 13772 | struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx)); |
| 13773 | if (ctx == NULL) { |
| 13774 | MG_ERROR(("TLS context init OOM")); |
| 13775 | } else { |
| 13776 | #ifdef MBEDTLS_SSL_SESSION_TICKETS |
| 13777 | int rc; |
| 13778 | mbedtls_ssl_ticket_init(&ctx->tickets); |
| 13779 | if ((rc = mbedtls_ssl_ticket_setup(&ctx->tickets, mg_mbed_rng, NULL, |
| 13780 | MBEDTLS_CIPHER_AES_128_GCM, 86400)) != |
| 13781 | 0) { |
| 13782 | MG_ERROR((" mbedtls_ssl_ticket_setup %#x", -rc)); |
| 13783 | } |
| 13784 | #endif |
| 13785 | mgr->tls_ctx = ctx; |
| 13786 | } |
| 13787 | } |
| 13788 | |
| 13789 | void mg_tls_ctx_free(struct mg_mgr *mgr) { |
| 13790 | struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx; |
| 13791 | if (ctx != NULL) { |
| 13792 | #ifdef MBEDTLS_SSL_SESSION_TICKETS |
| 13793 | mbedtls_ssl_ticket_free(&ctx->tickets); |
| 13794 | #endif |
| 13795 | free(ctx); |
| 13796 | mgr->tls_ctx = NULL; |
| 13797 | } |
| 13798 | } |
| 13799 | #endif |
| 13800 | |
| 13801 | #ifdef MG_ENABLE_LINES |
| 13802 | #line 1 "src/tls_openssl.c" |
| 13803 | #endif |
| 13804 | |
| 13805 | |
| 13806 | |
| 13807 | #if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL |
| 13808 | |
| 13809 | static int tls_err_cb(const char *s, size_t len, void *c) { |
| 13810 | int n = (int) len - 1; |
| 13811 | MG_ERROR(("%lu %.*s", ((struct mg_connection *) c)->id, n, s)); |
| 13812 | return 0; // undocumented |
| 13813 | } |
| 13814 | |
| 13815 | static int mg_tls_err(struct mg_connection *c, struct mg_tls *tls, int res) { |
| 13816 | int err = SSL_get_error(tls->ssl, res); |
| 13817 | // We've just fetched the last error from the queue. |
| 13818 | // Now we need to clear the error queue. If we do not, then the following |
| 13819 | // can happen (actually reported): |
| 13820 | // - A new connection is accept()-ed with cert error (e.g. self-signed cert) |
| 13821 | // - Since all accept()-ed connections share listener's context, |
| 13822 | // - *ALL* SSL accepted connection report read error on the next poll cycle. |
| 13823 | // Thus a single errored connection can close all the rest, unrelated ones. |
| 13824 | // Clearing the error keeps the shared SSL_CTX in an OK state. |
| 13825 | |
| 13826 | if (err != 0) ERR_print_errors_cb(tls_err_cb, c); |
| 13827 | ERR_clear_error(); |
| 13828 | if (err == SSL_ERROR_WANT_READ) return 0; |
| 13829 | if (err == SSL_ERROR_WANT_WRITE) return 0; |
| 13830 | return err; |
| 13831 | } |
| 13832 | |
| 13833 | static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) { |
| 13834 | BIO *bio = BIO_new_mem_buf(ca.buf, (int) ca.len); |
| 13835 | STACK_OF(X509_INFO) *certs = |
| 13836 | bio ? PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL) : NULL; |
| 13837 | if (bio) BIO_free(bio); |
| 13838 | return certs; |
| 13839 | } |
| 13840 | |
| 13841 | static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) { |
| 13842 | int i; |
| 13843 | X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx); |
| 13844 | for (i = 0; i < sk_X509_INFO_num(certs); i++) { |
| 13845 | X509_INFO *cert_info = sk_X509_INFO_value(certs, i); |
| 13846 | if (cert_info->x509 && !X509_STORE_add_cert(cert_store, cert_info->x509)) |
| 13847 | return false; |
| 13848 | } |
| 13849 | return true; |
| 13850 | } |
| 13851 | |
| 13852 | static EVP_PKEY *load_key(struct mg_str s) { |
| 13853 | BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len); |
| 13854 | EVP_PKEY *key = bio ? PEM_read_bio_PrivateKey(bio, NULL, 0, NULL) : NULL; |
| 13855 | if (bio) BIO_free(bio); |
| 13856 | return key; |
| 13857 | } |
| 13858 | |
| 13859 | static X509 *load_cert(struct mg_str s) { |
| 13860 | BIO *bio = BIO_new_mem_buf(s.buf, (int) (long) s.len); |
| 13861 | X509 *cert = bio == NULL ? NULL |
| 13862 | : s.buf[0] == '-' |
| 13863 | ? PEM_read_bio_X509(bio, NULL, NULL, NULL) // PEM |
| 13864 | : d2i_X509_bio(bio, NULL); // DER |
| 13865 | if (bio) BIO_free(bio); |
| 13866 | return cert; |
| 13867 | } |
| 13868 | |
| 13869 | static long mg_bio_ctrl(BIO *b, int cmd, long larg, void *pargs) { |
| 13870 | long ret = 0; |
| 13871 | if (cmd == BIO_CTRL_PUSH) ret = 1; |
| 13872 | if (cmd == BIO_CTRL_POP) ret = 1; |
| 13873 | if (cmd == BIO_CTRL_FLUSH) ret = 1; |
| 13874 | #if MG_TLS == MG_TLS_OPENSSL |
| 13875 | if (cmd == BIO_C_SET_NBIO) ret = 1; |
| 13876 | #endif |
| 13877 | // MG_DEBUG(("%d -> %ld", cmd, ret)); |
| 13878 | (void) b, (void) cmd, (void) larg, (void) pargs; |
| 13879 | return ret; |
| 13880 | } |
| 13881 | |
| 13882 | static int mg_bio_read(BIO *bio, char *buf, int len) { |
| 13883 | struct mg_connection *c = (struct mg_connection *) BIO_get_data(bio); |
| 13884 | long res = mg_io_recv(c, buf, (size_t) len); |
| 13885 | // MG_DEBUG(("%p %d %ld", buf, len, res)); |
| 13886 | len = res > 0 ? (int) res : -1; |
| 13887 | if (res == MG_IO_WAIT) BIO_set_retry_read(bio); |
| 13888 | return len; |
| 13889 | } |
| 13890 | |
| 13891 | static int mg_bio_write(BIO *bio, const char *buf, int len) { |
| 13892 | struct mg_connection *c = (struct mg_connection *) BIO_get_data(bio); |
| 13893 | long res = mg_io_send(c, buf, (size_t) len); |
| 13894 | // MG_DEBUG(("%p %d %ld", buf, len, res)); |
| 13895 | len = res > 0 ? (int) res : -1; |
| 13896 | if (res == MG_IO_WAIT) BIO_set_retry_write(bio); |
| 13897 | return len; |
| 13898 | } |
| 13899 | |
| 13900 | #ifdef MG_TLS_SSLKEYLOGFILE |
| 13901 | static void ssl_keylog_cb(const SSL *ssl, const char *line) { |
| 13902 | char *keylogfile = getenv("SSLKEYLOGFILE"); |
| 13903 | if (keylogfile == NULL) { |
| 13904 | return; |
| 13905 | } |
| 13906 | FILE *f = fopen(keylogfile, "a"); |
| 13907 | fprintf(f, "%s\n", line); |
| 13908 | fflush(f); |
| 13909 | fclose(f); |
| 13910 | } |
| 13911 | #endif |
| 13912 | |
| 13913 | void mg_tls_free(struct mg_connection *c) { |
| 13914 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 13915 | if (tls == NULL) return; |
| 13916 | SSL_free(tls->ssl); |
| 13917 | SSL_CTX_free(tls->ctx); |
| 13918 | BIO_meth_free(tls->bm); |
| 13919 | free(tls); |
| 13920 | c->tls = NULL; |
| 13921 | } |
| 13922 | |
| 13923 | void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { |
| 13924 | struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); |
| 13925 | const char *id = "mongoose"; |
| 13926 | static unsigned char s_initialised = 0; |
| 13927 | BIO *bio = NULL; |
| 13928 | int rc; |
| 13929 | c->tls = tls; |
| 13930 | if (tls == NULL) { |
| 13931 | mg_error(c, "TLS OOM"); |
| 13932 | goto fail; |
| 13933 | } |
| 13934 | |
| 13935 | if (!s_initialised) { |
| 13936 | SSL_library_init(); |
| 13937 | s_initialised++; |
| 13938 | } |
| 13939 | MG_DEBUG(("%lu Setting TLS", c->id)); |
| 13940 | tls->ctx = c->is_client ? SSL_CTX_new(TLS_client_method()) |
| 13941 | : SSL_CTX_new(TLS_server_method()); |
| 13942 | if (tls->ctx == NULL) { |
| 13943 | mg_error(c, "SSL_CTX_new"); |
| 13944 | goto fail; |
| 13945 | } |
| 13946 | #ifdef MG_TLS_SSLKEYLOGFILE |
| 13947 | SSL_CTX_set_keylog_callback(tls->ctx, ssl_keylog_cb); |
| 13948 | #endif |
| 13949 | if ((tls->ssl = SSL_new(tls->ctx)) == NULL) { |
| 13950 | mg_error(c, "SSL_new"); |
| 13951 | goto fail; |
| 13952 | } |
| 13953 | SSL_set_session_id_context(tls->ssl, (const uint8_t *) id, |
| 13954 | (unsigned) strlen(id)); |
| 13955 | // Disable deprecated protocols |
| 13956 | SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2); |
| 13957 | SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3); |
| 13958 | SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1); |
| 13959 | SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1); |
| 13960 | #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION |
| 13961 | SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION); |
| 13962 | #endif |
| 13963 | #ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE |
| 13964 | SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE); |
| 13965 | #endif |
| 13966 | |
| 13967 | #if MG_TLS == MG_TLS_WOLFSSL && !defined(OPENSSL_COMPATIBLE_DEFAULTS) |
| 13968 | if (opts->ca.len == 0 || mg_strcmp(opts->ca, mg_str("*")) == 0) { |
| 13969 | // Older versions require that either the CA is loaded or SSL_VERIFY_NONE |
| 13970 | // explicitly set |
| 13971 | SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL); |
| 13972 | } |
| 13973 | #endif |
| 13974 | if (opts->ca.buf != NULL && opts->ca.buf[0] != '\0') { |
| 13975 | SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, |
| 13976 | NULL); |
| 13977 | STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca); |
| 13978 | rc = add_ca_certs(tls->ctx, certs); |
| 13979 | sk_X509_INFO_pop_free(certs, X509_INFO_free); |
| 13980 | if (!rc) { |
| 13981 | mg_error(c, "CA err"); |
| 13982 | goto fail; |
| 13983 | } |
| 13984 | } |
| 13985 | if (opts->cert.buf != NULL && opts->cert.buf[0] != '\0') { |
| 13986 | X509 *cert = load_cert(opts->cert); |
| 13987 | rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert); |
| 13988 | X509_free(cert); |
| 13989 | if (cert == NULL || rc != 1) { |
| 13990 | mg_error(c, "CERT err %d", mg_tls_err(c, tls, rc)); |
| 13991 | goto fail; |
| 13992 | } |
| 13993 | } |
| 13994 | if (opts->key.buf != NULL && opts->key.buf[0] != '\0') { |
| 13995 | EVP_PKEY *key = load_key(opts->key); |
| 13996 | rc = key == NULL ? 0 : SSL_use_PrivateKey(tls->ssl, key); |
| 13997 | EVP_PKEY_free(key); |
| 13998 | if (key == NULL || rc != 1) { |
| 13999 | mg_error(c, "KEY err %d", mg_tls_err(c, tls, rc)); |
| 14000 | goto fail; |
| 14001 | } |
| 14002 | } |
| 14003 | |
| 14004 | SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); |
| 14005 | #if MG_TLS == MG_TLS_OPENSSL && OPENSSL_VERSION_NUMBER > 0x10002000L |
| 14006 | (void) SSL_set_ecdh_auto(tls->ssl, 1); |
| 14007 | #endif |
| 14008 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L |
| 14009 | if (opts->name.len > 0) { |
| 14010 | char *s = mg_mprintf("%.*s", (int) opts->name.len, opts->name.buf); |
| 14011 | #if MG_TLS != MG_TLS_WOLFSSL || LIBWOLFSSL_VERSION_HEX >= 0x05005002 |
| 14012 | SSL_set1_host(tls->ssl, s); |
| 14013 | #else |
| 14014 | X509_VERIFY_PARAM_set1_host(SSL_get0_param(tls->ssl), s, 0); |
| 14015 | #endif |
| 14016 | SSL_set_tlsext_host_name(tls->ssl, s); |
| 14017 | free(s); |
| 14018 | } |
| 14019 | #endif |
| 14020 | #if MG_TLS == MG_TLS_WOLFSSL |
| 14021 | tls->bm = BIO_meth_new(0, "bio_mg"); |
| 14022 | #else |
| 14023 | tls->bm = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "bio_mg"); |
| 14024 | #endif |
| 14025 | BIO_meth_set_write(tls->bm, mg_bio_write); |
| 14026 | BIO_meth_set_read(tls->bm, mg_bio_read); |
| 14027 | BIO_meth_set_ctrl(tls->bm, mg_bio_ctrl); |
| 14028 | |
| 14029 | bio = BIO_new(tls->bm); |
| 14030 | BIO_set_data(bio, c); |
| 14031 | SSL_set_bio(tls->ssl, bio, bio); |
| 14032 | |
| 14033 | c->is_tls = 1; |
| 14034 | c->is_tls_hs = 1; |
| 14035 | MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client")); |
| 14036 | return; |
| 14037 | fail: |
| 14038 | mg_tls_free(c); |
| 14039 | } |
| 14040 | |
| 14041 | void mg_tls_handshake(struct mg_connection *c) { |
| 14042 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 14043 | int rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl); |
| 14044 | if (rc == 1) { |
| 14045 | MG_DEBUG(("%lu success", c->id)); |
| 14046 | c->is_tls_hs = 0; |
| 14047 | mg_call(c, MG_EV_TLS_HS, NULL); |
| 14048 | } else { |
| 14049 | int code = mg_tls_err(c, tls, rc); |
| 14050 | if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code); |
| 14051 | } |
| 14052 | } |
| 14053 | |
| 14054 | size_t mg_tls_pending(struct mg_connection *c) { |
| 14055 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 14056 | return tls == NULL ? 0 : (size_t) SSL_pending(tls->ssl); |
| 14057 | } |
| 14058 | |
| 14059 | long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) { |
| 14060 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 14061 | int n = SSL_read(tls->ssl, buf, (int) len); |
| 14062 | if (!c->is_tls_hs && buf == NULL && n == 0) return 0; // TODO(): MIP |
| 14063 | if (n < 0 && mg_tls_err(c, tls, n) == 0) return MG_IO_WAIT; |
| 14064 | if (n <= 0) return MG_IO_ERR; |
| 14065 | return n; |
| 14066 | } |
| 14067 | |
| 14068 | long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) { |
| 14069 | struct mg_tls *tls = (struct mg_tls *) c->tls; |
| 14070 | int n = SSL_write(tls->ssl, buf, (int) len); |
| 14071 | if (n < 0 && mg_tls_err(c, tls, n) == 0) return MG_IO_WAIT; |
| 14072 | if (n <= 0) return MG_IO_ERR; |
| 14073 | return n; |
| 14074 | } |
| 14075 | |
| 14076 | void mg_tls_ctx_init(struct mg_mgr *mgr) { |
| 14077 | (void) mgr; |
| 14078 | } |
| 14079 | |
| 14080 | void mg_tls_ctx_free(struct mg_mgr *mgr) { |
| 14081 | (void) mgr; |
| 14082 | } |
| 14083 | #endif |
| 14084 | |
| 14085 | #ifdef MG_ENABLE_LINES |
| 14086 | #line 1 "src/tls_rsa.c" |
| 14087 | #endif |
| 14088 | |
| 14089 | |
| 14090 | |
| 14091 | #if MG_TLS == MG_TLS_BUILTIN |
| 14092 | |
| 14093 | #define NS_INTERNAL static |
| 14094 | typedef struct _bigint bigint; /**< An alias for _bigint */ |
| 14095 | |
| 14096 | /* |
| 14097 | * Copyright (c) 2007, Cameron Rich |
| 14098 | * |
| 14099 | * All rights reserved. |
| 14100 | * |
| 14101 | * Redistribution and use in source and binary forms, with or without |
| 14102 | * modification, are permitted provided that the following conditions are met: |
| 14103 | * |
| 14104 | * * Redistributions of source code must retain the above copyright notice, |
| 14105 | * this list of conditions and the following disclaimer. |
| 14106 | * * Redistributions in binary form must reproduce the above copyright notice, |
| 14107 | * this list of conditions and the following disclaimer in the documentation |
| 14108 | * and/or other materials provided with the distribution. |
| 14109 | * * Neither the name of the axTLS project nor the names of its contributors |
| 14110 | * may be used to endorse or promote products derived from this software |
| 14111 | * without specific prior written permission. |
| 14112 | * |
| 14113 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 14114 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 14115 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 14116 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 14117 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 14118 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 14119 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 14120 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 14121 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 14122 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 14123 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 14124 | */ |
| 14125 | |
| 14126 | /* Maintain a number of precomputed variables when doing reduction */ |
| 14127 | #define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */ |
| 14128 | #define BIGINT_P_OFFSET 1 /**< p modulo offset. */ |
| 14129 | #define BIGINT_Q_OFFSET 2 /**< q module offset. */ |
| 14130 | #define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */ |
| 14131 | |
| 14132 | /* Architecture specific functions for big ints */ |
| 14133 | #if defined(CONFIG_INTEGER_8BIT) |
| 14134 | #define COMP_RADIX 256U /**< Max component + 1 */ |
| 14135 | #define COMP_MAX 0xFFFFU /**< (Max dbl comp -1) */ |
| 14136 | #define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ |
| 14137 | #define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ |
| 14138 | #define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ |
| 14139 | typedef uint8_t comp; /**< A single precision component. */ |
| 14140 | typedef uint16_t long_comp; /**< A double precision component. */ |
| 14141 | typedef int16_t slong_comp; /**< A signed double precision component. */ |
| 14142 | #elif defined(CONFIG_INTEGER_16BIT) |
| 14143 | #define COMP_RADIX 65536U /**< Max component + 1 */ |
| 14144 | #define COMP_MAX 0xFFFFFFFFU /**< (Max dbl comp -1) */ |
| 14145 | #define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ |
| 14146 | #define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ |
| 14147 | #define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ |
| 14148 | typedef uint16_t comp; /**< A single precision component. */ |
| 14149 | typedef uint32_t long_comp; /**< A double precision component. */ |
| 14150 | typedef int32_t slong_comp; /**< A signed double precision component. */ |
| 14151 | #else /* regular 32 bit */ |
| 14152 | #ifdef WIN32 |
| 14153 | #define COMP_RADIX 4294967296i64 |
| 14154 | #define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 |
| 14155 | #else |
| 14156 | #define COMP_RADIX 4294967296 /**< Max component + 1 */ |
| 14157 | #define COMP_MAX 0xFFFFFFFFFFFFFFFF /**< (Max dbl comp -1) */ |
| 14158 | #endif |
| 14159 | #define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ |
| 14160 | #define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ |
| 14161 | #define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ |
| 14162 | typedef uint32_t comp; /**< A single precision component. */ |
| 14163 | typedef uint64_t long_comp; /**< A double precision component. */ |
| 14164 | typedef int64_t slong_comp; /**< A signed double precision component. */ |
| 14165 | #endif |
| 14166 | |
| 14167 | /** |
| 14168 | * @struct _bigint |
| 14169 | * @brief A big integer basic object |
| 14170 | */ |
| 14171 | struct _bigint { |
| 14172 | struct _bigint *next; /**< The next bigint in the cache. */ |
| 14173 | short size; /**< The number of components in this bigint. */ |
| 14174 | short max_comps; /**< The heapsize allocated for this bigint */ |
| 14175 | int refs; /**< An internal reference count. */ |
| 14176 | comp *comps; /**< A ptr to the actual component data */ |
| 14177 | }; |
| 14178 | |
| 14179 | /** |
| 14180 | * Maintains the state of the cache, and a number of variables used in |
| 14181 | * reduction. |
| 14182 | */ |
| 14183 | struct _BI_CTX /**< A big integer "session" context. */ |
| 14184 | { |
| 14185 | bigint *active_list; /**< Bigints currently used. */ |
| 14186 | bigint *free_list; /**< Bigints not used. */ |
| 14187 | bigint *bi_radix; /**< The radix used. */ |
| 14188 | bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ |
| 14189 | |
| 14190 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 14191 | bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */ |
| 14192 | bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */ |
| 14193 | comp N0_dash[BIGINT_NUM_MODS]; |
| 14194 | #elif defined(CONFIG_BIGINT_BARRETT) |
| 14195 | bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */ |
| 14196 | #endif |
| 14197 | bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ |
| 14198 | bigint **g; /**< Used by sliding-window. */ |
| 14199 | int window; /**< The size of the sliding window */ |
| 14200 | int active_count; /**< Number of active bigints. */ |
| 14201 | int free_count; /**< Number of free bigints. */ |
| 14202 | |
| 14203 | #ifdef CONFIG_BIGINT_MONTGOMERY |
| 14204 | uint8_t use_classical; /**< Use classical reduction. */ |
| 14205 | #endif |
| 14206 | uint8_t mod_offset; /**< The mod offset we are using */ |
| 14207 | }; |
| 14208 | typedef struct _BI_CTX BI_CTX; |
| 14209 | |
| 14210 | #if !defined(MAX) |
| 14211 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
| 14212 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| 14213 | #endif |
| 14214 | |
| 14215 | #define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ |
| 14216 | |
| 14217 | /* |
| 14218 | * Copyright (c) 2007, Cameron Rich |
| 14219 | * |
| 14220 | * All rights reserved. |
| 14221 | * |
| 14222 | * Redistribution and use in source and binary forms, with or without |
| 14223 | * modification, are permitted provided that the following conditions are met: |
| 14224 | * |
| 14225 | * * Redistributions of source code must retain the above copyright notice, |
| 14226 | * this list of conditions and the following disclaimer. |
| 14227 | * * Redistributions in binary form must reproduce the above copyright notice, |
| 14228 | * this list of conditions and the following disclaimer in the documentation |
| 14229 | * and/or other materials provided with the distribution. |
| 14230 | * * Neither the name of the axTLS project nor the names of its contributors |
| 14231 | * may be used to endorse or promote products derived from this software |
| 14232 | * without specific prior written permission. |
| 14233 | * |
| 14234 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 14235 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 14236 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 14237 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 14238 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 14239 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 14240 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 14241 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 14242 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 14243 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 14244 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 14245 | */ |
| 14246 | |
| 14247 | NS_INTERNAL BI_CTX *bi_initialize(void); |
| 14248 | //NS_INTERNAL void bi_terminate(BI_CTX *ctx); |
| 14249 | NS_INTERNAL void bi_permanent(bigint *bi); |
| 14250 | NS_INTERNAL void bi_depermanent(bigint *bi); |
| 14251 | //NS_INTERNAL void bi_clear_cache(BI_CTX *ctx); |
| 14252 | NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi); |
| 14253 | NS_INTERNAL bigint *bi_copy(bigint *bi); |
| 14254 | NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi); |
| 14255 | NS_INTERNAL void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size); |
| 14256 | NS_INTERNAL bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len); |
| 14257 | NS_INTERNAL bigint *int_to_bi(BI_CTX *ctx, comp i); |
| 14258 | |
| 14259 | /* the functions that actually do something interesting */ |
| 14260 | NS_INTERNAL bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib); |
| 14261 | NS_INTERNAL bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, |
| 14262 | int *is_negative); |
| 14263 | NS_INTERNAL bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, |
| 14264 | int is_mod); |
| 14265 | NS_INTERNAL bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib); |
| 14266 | NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp); |
| 14267 | #if 0 |
| 14268 | NS_INTERNAL bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, |
| 14269 | bigint *bim, bigint *biexp); |
| 14270 | #endif |
| 14271 | NS_INTERNAL int bi_compare(bigint *bia, bigint *bib); |
| 14272 | NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); |
| 14273 | //NS_INTERNAL void bi_free_mod(BI_CTX *ctx, int mod_offset); |
| 14274 | |
| 14275 | #ifdef CONFIG_SSL_FULL_MODE |
| 14276 | NS_INTERNAL void bi_print(const char *label, bigint *bi); |
| 14277 | NS_INTERNAL bigint *bi_str_import(BI_CTX *ctx, const char *data); |
| 14278 | #endif |
| 14279 | |
| 14280 | /** |
| 14281 | * @def bi_mod |
| 14282 | * Find the residue of B. bi_set_mod() must be called before hand. |
| 14283 | */ |
| 14284 | #define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1) |
| 14285 | |
| 14286 | /** |
| 14287 | * bi_residue() is technically the same as bi_mod(), but it uses the |
| 14288 | * appropriate reduction technique (which is bi_mod() when doing classical |
| 14289 | * reduction). |
| 14290 | */ |
| 14291 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 14292 | #define bi_residue(A, B) bi_mont(A, B) |
| 14293 | NS_INTERNAL bigint *bi_mont(BI_CTX *ctx, bigint *bixy); |
| 14294 | #elif defined(CONFIG_BIGINT_BARRETT) |
| 14295 | #define bi_residue(A, B) bi_barrett(A, B) |
| 14296 | NS_INTERNAL bigint *bi_barrett(BI_CTX *ctx, bigint *bi); |
| 14297 | #else /* if defined(CONFIG_BIGINT_CLASSICAL) */ |
| 14298 | #define bi_residue(A, B) bi_mod(A, B) |
| 14299 | #endif |
| 14300 | |
| 14301 | #ifdef CONFIG_BIGINT_SQUARE |
| 14302 | NS_INTERNAL bigint *bi_square(BI_CTX *ctx, bigint *bi); |
| 14303 | #else |
| 14304 | #define bi_square(A, B) bi_multiply(A, bi_copy(B), B) |
| 14305 | #endif |
| 14306 | |
| 14307 | //NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, |
| 14308 | // bigint *p, bigint *q, bigint *qInv); |
| 14309 | |
| 14310 | /* |
| 14311 | * Copyright (c) 2007, Cameron Rich |
| 14312 | * |
| 14313 | * All rights reserved. |
| 14314 | * |
| 14315 | * Redistribution and use in source and binary forms, with or without |
| 14316 | * modification, are permitted provided that the following conditions are met: |
| 14317 | * |
| 14318 | * * Redistributions of source code must retain the above copyright notice, |
| 14319 | * this list of conditions and the following disclaimer. |
| 14320 | * * Redistributions in binary form must reproduce the above copyright notice, |
| 14321 | * this list of conditions and the following disclaimer in the documentation |
| 14322 | * and/or other materials provided with the distribution. |
| 14323 | * * Neither the name of the axTLS project nor the names of its contributors |
| 14324 | * may be used to endorse or promote products derived from this software |
| 14325 | * without specific prior written permission. |
| 14326 | * |
| 14327 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 14328 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 14329 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 14330 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 14331 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 14332 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 14333 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 14334 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 14335 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 14336 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 14337 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 14338 | */ |
| 14339 | |
| 14340 | /** |
| 14341 | * @defgroup bigint_api Big Integer API |
| 14342 | * @brief The bigint implementation as used by the axTLS project. |
| 14343 | * |
| 14344 | * The bigint library is for RSA encryption/decryption as well as signing. |
| 14345 | * This code tries to minimise use of malloc/free by maintaining a small |
| 14346 | * cache. A bigint context may maintain state by being made "permanent". |
| 14347 | * It be be later released with a bi_depermanent() and bi_free() call. |
| 14348 | * |
| 14349 | * It supports the following reduction techniques: |
| 14350 | * - Classical |
| 14351 | * - Barrett |
| 14352 | * - Montgomery |
| 14353 | * |
| 14354 | * It also implements the following: |
| 14355 | * - Karatsuba multiplication |
| 14356 | * - Squaring |
| 14357 | * - Sliding window exponentiation |
| 14358 | * - Chinese Remainder Theorem (implemented in rsa.c). |
| 14359 | * |
| 14360 | * All the algorithms used are pretty standard, and designed for different |
| 14361 | * data bus sizes. Negative numbers are not dealt with at all, so a subtraction |
| 14362 | * may need to be tested for negativity. |
| 14363 | * |
| 14364 | * This library steals some ideas from Jef Poskanzer |
| 14365 | * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint> |
| 14366 | * and GMP <http://www.swox.com/gmp>. It gets most of its implementation |
| 14367 | * detail from "The Handbook of Applied Cryptography" |
| 14368 | * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf> |
| 14369 | * @{ |
| 14370 | */ |
| 14371 | |
| 14372 | #define V1 v->comps[v->size - 1] /**< v1 for division */ |
| 14373 | #define V2 v->comps[v->size - 2] /**< v2 for division */ |
| 14374 | #define U(j) tmp_u->comps[tmp_u->size - j - 1] /**< uj for division */ |
| 14375 | #define Q(j) quotient->comps[quotient->size - j - 1] /**< qj for division */ |
| 14376 | |
| 14377 | static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); |
| 14378 | static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); |
| 14379 | static bigint *alloc(BI_CTX *ctx, int size); |
| 14380 | static bigint *trim(bigint *bi); |
| 14381 | static void more_comps(bigint *bi, int n); |
| 14382 | #if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ |
| 14383 | defined(CONFIG_BIGINT_MONTGOMERY) |
| 14384 | static bigint *comp_right_shift(bigint *biR, int num_shifts); |
| 14385 | static bigint *comp_left_shift(bigint *biR, int num_shifts); |
| 14386 | #endif |
| 14387 | |
| 14388 | #ifdef CONFIG_BIGINT_CHECK_ON |
| 14389 | static void check(const bigint *bi); |
| 14390 | #else |
| 14391 | #define check(A) /**< disappears in normal production mode */ |
| 14392 | #endif |
| 14393 | |
| 14394 | /** |
| 14395 | * @brief Start a new bigint context. |
| 14396 | * @return A bigint context. |
| 14397 | */ |
| 14398 | NS_INTERNAL BI_CTX *bi_initialize(void) { |
| 14399 | /* calloc() sets everything to zero */ |
| 14400 | BI_CTX *ctx = (BI_CTX *) calloc(1, sizeof(BI_CTX)); |
| 14401 | |
| 14402 | /* the radix */ |
| 14403 | ctx->bi_radix = alloc(ctx, 2); |
| 14404 | ctx->bi_radix->comps[0] = 0; |
| 14405 | ctx->bi_radix->comps[1] = 1; |
| 14406 | bi_permanent(ctx->bi_radix); |
| 14407 | return ctx; |
| 14408 | } |
| 14409 | |
| 14410 | #if 0 |
| 14411 | /** |
| 14412 | * @brief Close the bigint context and free any resources. |
| 14413 | * |
| 14414 | * Free up any used memory - a check is done if all objects were not |
| 14415 | * properly freed. |
| 14416 | * @param ctx [in] The bigint session context. |
| 14417 | */ |
| 14418 | NS_INTERNAL void bi_terminate(BI_CTX *ctx) { |
| 14419 | bi_depermanent(ctx->bi_radix); |
| 14420 | bi_free(ctx, ctx->bi_radix); |
| 14421 | |
| 14422 | if (ctx->active_count != 0) { |
| 14423 | #ifdef CONFIG_SSL_FULL_MODE |
| 14424 | printf("bi_terminate: there were %d un-freed bigints\n", ctx->active_count); |
| 14425 | #endif |
| 14426 | abort(); |
| 14427 | } |
| 14428 | |
| 14429 | bi_clear_cache(ctx); |
| 14430 | free(ctx); |
| 14431 | } |
| 14432 | |
| 14433 | /** |
| 14434 | *@brief Clear the memory cache. |
| 14435 | */ |
| 14436 | NS_INTERNAL void bi_clear_cache(BI_CTX *ctx) { |
| 14437 | bigint *p, *pn; |
| 14438 | |
| 14439 | if (ctx->free_list == NULL) return; |
| 14440 | |
| 14441 | for (p = ctx->free_list; p != NULL; p = pn) { |
| 14442 | pn = p->next; |
| 14443 | free(p->comps); |
| 14444 | free(p); |
| 14445 | } |
| 14446 | |
| 14447 | ctx->free_count = 0; |
| 14448 | ctx->free_list = NULL; |
| 14449 | } |
| 14450 | #endif |
| 14451 | |
| 14452 | /** |
| 14453 | * @brief Increment the number of references to this object. |
| 14454 | * It does not do a full copy. |
| 14455 | * @param bi [in] The bigint to copy. |
| 14456 | * @return A reference to the same bigint. |
| 14457 | */ |
| 14458 | NS_INTERNAL bigint *bi_copy(bigint *bi) { |
| 14459 | check(bi); |
| 14460 | if (bi->refs != PERMANENT) bi->refs++; |
| 14461 | return bi; |
| 14462 | } |
| 14463 | |
| 14464 | /** |
| 14465 | * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. |
| 14466 | * |
| 14467 | * For this object to be freed, bi_depermanent() must be called. |
| 14468 | * @param bi [in] The bigint to be made permanent. |
| 14469 | */ |
| 14470 | NS_INTERNAL void bi_permanent(bigint *bi) { |
| 14471 | check(bi); |
| 14472 | if (bi->refs != 1) { |
| 14473 | #ifdef CONFIG_SSL_FULL_MODE |
| 14474 | printf("bi_permanent: refs was not 1\n"); |
| 14475 | #endif |
| 14476 | abort(); |
| 14477 | } |
| 14478 | |
| 14479 | bi->refs = PERMANENT; |
| 14480 | } |
| 14481 | |
| 14482 | /** |
| 14483 | * @brief Take a permanent object and make it eligible for freedom. |
| 14484 | * @param bi [in] The bigint to be made back to temporary. |
| 14485 | */ |
| 14486 | NS_INTERNAL void bi_depermanent(bigint *bi) { |
| 14487 | check(bi); |
| 14488 | if (bi->refs != PERMANENT) { |
| 14489 | #ifdef CONFIG_SSL_FULL_MODE |
| 14490 | printf("bi_depermanent: bigint was not permanent\n"); |
| 14491 | #endif |
| 14492 | abort(); |
| 14493 | } |
| 14494 | |
| 14495 | bi->refs = 1; |
| 14496 | } |
| 14497 | |
| 14498 | /** |
| 14499 | * @brief Free a bigint object so it can be used again. |
| 14500 | * |
| 14501 | * The memory itself it not actually freed, just tagged as being available |
| 14502 | * @param ctx [in] The bigint session context. |
| 14503 | * @param bi [in] The bigint to be freed. |
| 14504 | */ |
| 14505 | NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi) { |
| 14506 | check(bi); |
| 14507 | if (bi->refs == PERMANENT) { |
| 14508 | return; |
| 14509 | } |
| 14510 | |
| 14511 | if (--bi->refs > 0) { |
| 14512 | return; |
| 14513 | } |
| 14514 | |
| 14515 | bi->next = ctx->free_list; |
| 14516 | ctx->free_list = bi; |
| 14517 | ctx->free_count++; |
| 14518 | |
| 14519 | if (--ctx->active_count < 0) { |
| 14520 | #ifdef CONFIG_SSL_FULL_MODE |
| 14521 | printf( |
| 14522 | "bi_free: active_count went negative " |
| 14523 | "- double-freed bigint?\n"); |
| 14524 | #endif |
| 14525 | abort(); |
| 14526 | } |
| 14527 | } |
| 14528 | |
| 14529 | /** |
| 14530 | * @brief Convert an (unsigned) integer into a bigint. |
| 14531 | * @param ctx [in] The bigint session context. |
| 14532 | * @param i [in] The (unsigned) integer to be converted. |
| 14533 | * |
| 14534 | */ |
| 14535 | NS_INTERNAL bigint *int_to_bi(BI_CTX *ctx, comp i) { |
| 14536 | bigint *biR = alloc(ctx, 1); |
| 14537 | biR->comps[0] = i; |
| 14538 | return biR; |
| 14539 | } |
| 14540 | |
| 14541 | /** |
| 14542 | * @brief Do a full copy of the bigint object. |
| 14543 | * @param ctx [in] The bigint session context. |
| 14544 | * @param bi [in] The bigint object to be copied. |
| 14545 | */ |
| 14546 | NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi) { |
| 14547 | bigint *biR = alloc(ctx, bi->size); |
| 14548 | check(bi); |
| 14549 | memcpy(biR->comps, bi->comps, (size_t) bi->size * COMP_BYTE_SIZE); |
| 14550 | return biR; |
| 14551 | } |
| 14552 | |
| 14553 | /** |
| 14554 | * @brief Perform an addition operation between two bigints. |
| 14555 | * @param ctx [in] The bigint session context. |
| 14556 | * @param bia [in] A bigint. |
| 14557 | * @param bib [in] Another bigint. |
| 14558 | * @return The result of the addition. |
| 14559 | */ |
| 14560 | NS_INTERNAL bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) { |
| 14561 | int n; |
| 14562 | comp carry = 0; |
| 14563 | comp *pa, *pb; |
| 14564 | |
| 14565 | check(bia); |
| 14566 | check(bib); |
| 14567 | |
| 14568 | n = MAX(bia->size, bib->size); |
| 14569 | more_comps(bia, n + 1); |
| 14570 | more_comps(bib, n); |
| 14571 | pa = bia->comps; |
| 14572 | pb = bib->comps; |
| 14573 | |
| 14574 | do { |
| 14575 | comp sl, rl, cy1; |
| 14576 | sl = *pa + *pb++; |
| 14577 | rl = sl + carry; |
| 14578 | cy1 = sl < *pa; |
| 14579 | carry = cy1 | (rl < sl); |
| 14580 | *pa++ = rl; |
| 14581 | } while (--n != 0); |
| 14582 | |
| 14583 | *pa = carry; /* do overflow */ |
| 14584 | bi_free(ctx, bib); |
| 14585 | return trim(bia); |
| 14586 | } |
| 14587 | |
| 14588 | /** |
| 14589 | * @brief Perform a subtraction operation between two bigints. |
| 14590 | * @param ctx [in] The bigint session context. |
| 14591 | * @param bia [in] A bigint. |
| 14592 | * @param bib [in] Another bigint. |
| 14593 | * @param is_negative [out] If defined, indicates that the result was negative. |
| 14594 | * is_negative may be null. |
| 14595 | * @return The result of the subtraction. The result is always positive. |
| 14596 | */ |
| 14597 | NS_INTERNAL bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, |
| 14598 | int *is_negative) { |
| 14599 | int n = bia->size; |
| 14600 | comp *pa, *pb, carry = 0; |
| 14601 | |
| 14602 | check(bia); |
| 14603 | check(bib); |
| 14604 | |
| 14605 | more_comps(bib, n); |
| 14606 | pa = bia->comps; |
| 14607 | pb = bib->comps; |
| 14608 | |
| 14609 | do { |
| 14610 | comp sl, rl, cy1; |
| 14611 | sl = *pa - *pb++; |
| 14612 | rl = sl - carry; |
| 14613 | cy1 = sl > *pa; |
| 14614 | carry = cy1 | (rl > sl); |
| 14615 | *pa++ = rl; |
| 14616 | } while (--n != 0); |
| 14617 | |
| 14618 | if (is_negative) /* indicate a negative result */ |
| 14619 | { |
| 14620 | *is_negative = (int) carry; |
| 14621 | } |
| 14622 | |
| 14623 | bi_free(ctx, trim(bib)); /* put bib back to the way it was */ |
| 14624 | return trim(bia); |
| 14625 | } |
| 14626 | |
| 14627 | /** |
| 14628 | * Perform a multiply between a bigint an an (unsigned) integer |
| 14629 | */ |
| 14630 | static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) { |
| 14631 | int j = 0, n = bia->size; |
| 14632 | bigint *biR = alloc(ctx, n + 1); |
| 14633 | comp carry = 0; |
| 14634 | comp *r = biR->comps; |
| 14635 | comp *a = bia->comps; |
| 14636 | |
| 14637 | check(bia); |
| 14638 | |
| 14639 | /* clear things to start with */ |
| 14640 | memset(r, 0, (size_t) ((n + 1) * COMP_BYTE_SIZE)); |
| 14641 | |
| 14642 | do { |
| 14643 | long_comp tmp = *r + (long_comp) a[j] * b + carry; |
| 14644 | *r++ = (comp) tmp; /* downsize */ |
| 14645 | carry = (comp)(tmp >> COMP_BIT_SIZE); |
| 14646 | } while (++j < n); |
| 14647 | |
| 14648 | *r = carry; |
| 14649 | bi_free(ctx, bia); |
| 14650 | return trim(biR); |
| 14651 | } |
| 14652 | |
| 14653 | /** |
| 14654 | * @brief Does both division and modulo calculations. |
| 14655 | * |
| 14656 | * Used extensively when doing classical reduction. |
| 14657 | * @param ctx [in] The bigint session context. |
| 14658 | * @param u [in] A bigint which is the numerator. |
| 14659 | * @param v [in] Either the denominator or the modulus depending on the mode. |
| 14660 | * @param is_mod [n] Determines if this is a normal division (0) or a reduction |
| 14661 | * (1). |
| 14662 | * @return The result of the division/reduction. |
| 14663 | */ |
| 14664 | NS_INTERNAL bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) { |
| 14665 | int n = v->size, m = u->size - n; |
| 14666 | int j = 0, orig_u_size = u->size; |
| 14667 | uint8_t mod_offset = ctx->mod_offset; |
| 14668 | comp d; |
| 14669 | bigint *quotient, *tmp_u; |
| 14670 | comp q_dash; |
| 14671 | |
| 14672 | check(u); |
| 14673 | check(v); |
| 14674 | |
| 14675 | /* if doing reduction and we are < mod, then return mod */ |
| 14676 | if (is_mod && bi_compare(v, u) > 0) { |
| 14677 | bi_free(ctx, v); |
| 14678 | return u; |
| 14679 | } |
| 14680 | |
| 14681 | quotient = alloc(ctx, m + 1); |
| 14682 | tmp_u = alloc(ctx, n + 1); |
| 14683 | v = trim(v); /* make sure we have no leading 0's */ |
| 14684 | d = (comp)((long_comp) COMP_RADIX / (V1 + 1)); |
| 14685 | |
| 14686 | /* clear things to start with */ |
| 14687 | memset(quotient->comps, 0, (size_t) ((quotient->size) * COMP_BYTE_SIZE)); |
| 14688 | |
| 14689 | /* normalise */ |
| 14690 | if (d > 1) { |
| 14691 | u = bi_int_multiply(ctx, u, d); |
| 14692 | |
| 14693 | if (is_mod) { |
| 14694 | v = ctx->bi_normalised_mod[mod_offset]; |
| 14695 | } else { |
| 14696 | v = bi_int_multiply(ctx, v, d); |
| 14697 | } |
| 14698 | } |
| 14699 | |
| 14700 | if (orig_u_size == u->size) /* new digit position u0 */ |
| 14701 | { |
| 14702 | more_comps(u, orig_u_size + 1); |
| 14703 | } |
| 14704 | |
| 14705 | do { |
| 14706 | /* get a temporary short version of u */ |
| 14707 | memcpy(tmp_u->comps, &u->comps[u->size - n - 1 - j], |
| 14708 | (size_t) (n + 1) * COMP_BYTE_SIZE); |
| 14709 | |
| 14710 | /* calculate q' */ |
| 14711 | if (U(0) == V1) { |
| 14712 | q_dash = COMP_RADIX - 1; |
| 14713 | } else { |
| 14714 | q_dash = (comp)(((long_comp) U(0) * COMP_RADIX + U(1)) / V1); |
| 14715 | |
| 14716 | if (v->size > 1 && V2) { |
| 14717 | /* we are implementing the following: |
| 14718 | if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - |
| 14719 | q_dash*V1)*COMP_RADIX) + U(2))) ... */ |
| 14720 | comp inner = (comp)((long_comp) COMP_RADIX * U(0) + U(1) - |
| 14721 | (long_comp) q_dash * V1); |
| 14722 | if ((long_comp) V2 * q_dash > (long_comp) inner * COMP_RADIX + U(2)) { |
| 14723 | q_dash--; |
| 14724 | } |
| 14725 | } |
| 14726 | } |
| 14727 | |
| 14728 | /* multiply and subtract */ |
| 14729 | if (q_dash) { |
| 14730 | int is_negative; |
| 14731 | tmp_u = bi_subtract(ctx, tmp_u, bi_int_multiply(ctx, bi_copy(v), q_dash), |
| 14732 | &is_negative); |
| 14733 | more_comps(tmp_u, n + 1); |
| 14734 | |
| 14735 | Q(j) = q_dash; |
| 14736 | |
| 14737 | /* add back */ |
| 14738 | if (is_negative) { |
| 14739 | Q(j)--; |
| 14740 | tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); |
| 14741 | |
| 14742 | /* lop off the carry */ |
| 14743 | tmp_u->size--; |
| 14744 | v->size--; |
| 14745 | } |
| 14746 | } else { |
| 14747 | Q(j) = 0; |
| 14748 | } |
| 14749 | |
| 14750 | /* copy back to u */ |
| 14751 | memcpy(&u->comps[u->size - n - 1 - j], tmp_u->comps, |
| 14752 | (size_t) (n + 1) * COMP_BYTE_SIZE); |
| 14753 | } while (++j <= m); |
| 14754 | |
| 14755 | bi_free(ctx, tmp_u); |
| 14756 | bi_free(ctx, v); |
| 14757 | |
| 14758 | if (is_mod) /* get the remainder */ |
| 14759 | { |
| 14760 | bi_free(ctx, quotient); |
| 14761 | return bi_int_divide(ctx, trim(u), d); |
| 14762 | } else /* get the quotient */ |
| 14763 | { |
| 14764 | bi_free(ctx, u); |
| 14765 | return trim(quotient); |
| 14766 | } |
| 14767 | } |
| 14768 | |
| 14769 | /* |
| 14770 | * Perform an integer divide on a bigint. |
| 14771 | */ |
| 14772 | static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom) { |
| 14773 | int i = biR->size - 1; |
| 14774 | long_comp r = 0; |
| 14775 | |
| 14776 | (void) ctx; |
| 14777 | check(biR); |
| 14778 | |
| 14779 | do { |
| 14780 | r = (r << COMP_BIT_SIZE) + biR->comps[i]; |
| 14781 | biR->comps[i] = (comp)(r / denom); |
| 14782 | r %= denom; |
| 14783 | } while (--i >= 0); |
| 14784 | |
| 14785 | return trim(biR); |
| 14786 | } |
| 14787 | |
| 14788 | #ifdef CONFIG_BIGINT_MONTGOMERY |
| 14789 | /** |
| 14790 | * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, |
| 14791 | * where B^-1(B-1) mod N=1. Actually, only the least significant part of |
| 14792 | * N' is needed, hence the definition N0'=N' mod b. We reproduce below the |
| 14793 | * simple algorithm from an article by Dusse and Kaliski to efficiently |
| 14794 | * find N0' from N0 and b */ |
| 14795 | static comp modular_inverse(bigint *bim) { |
| 14796 | int i; |
| 14797 | comp t = 1; |
| 14798 | comp two_2_i_minus_1 = 2; /* 2^(i-1) */ |
| 14799 | long_comp two_2_i = 4; /* 2^i */ |
| 14800 | comp N = bim->comps[0]; |
| 14801 | |
| 14802 | for (i = 2; i <= COMP_BIT_SIZE; i++) { |
| 14803 | if ((long_comp) N * t % two_2_i >= two_2_i_minus_1) { |
| 14804 | t += two_2_i_minus_1; |
| 14805 | } |
| 14806 | |
| 14807 | two_2_i_minus_1 <<= 1; |
| 14808 | two_2_i <<= 1; |
| 14809 | } |
| 14810 | |
| 14811 | return (comp)(COMP_RADIX - t); |
| 14812 | } |
| 14813 | #endif |
| 14814 | |
| 14815 | #if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ |
| 14816 | defined(CONFIG_BIGINT_MONTGOMERY) |
| 14817 | /** |
| 14818 | * Take each component and shift down (in terms of components) |
| 14819 | */ |
| 14820 | static bigint *comp_right_shift(bigint *biR, int num_shifts) { |
| 14821 | int i = biR->size - num_shifts; |
| 14822 | comp *x = biR->comps; |
| 14823 | comp *y = &biR->comps[num_shifts]; |
| 14824 | |
| 14825 | check(biR); |
| 14826 | |
| 14827 | if (i <= 0) /* have we completely right shifted? */ |
| 14828 | { |
| 14829 | biR->comps[0] = 0; /* return 0 */ |
| 14830 | biR->size = 1; |
| 14831 | return biR; |
| 14832 | } |
| 14833 | |
| 14834 | do { |
| 14835 | *x++ = *y++; |
| 14836 | } while (--i > 0); |
| 14837 | |
| 14838 | biR->size -= num_shifts; |
| 14839 | return biR; |
| 14840 | } |
| 14841 | |
| 14842 | /** |
| 14843 | * Take each component and shift it up (in terms of components) |
| 14844 | */ |
| 14845 | static bigint *comp_left_shift(bigint *biR, int num_shifts) { |
| 14846 | int i = biR->size - 1; |
| 14847 | comp *x, *y; |
| 14848 | |
| 14849 | check(biR); |
| 14850 | |
| 14851 | if (num_shifts <= 0) { |
| 14852 | return biR; |
| 14853 | } |
| 14854 | |
| 14855 | more_comps(biR, biR->size + num_shifts); |
| 14856 | |
| 14857 | x = &biR->comps[i + num_shifts]; |
| 14858 | y = &biR->comps[i]; |
| 14859 | |
| 14860 | do { |
| 14861 | *x-- = *y--; |
| 14862 | } while (i--); |
| 14863 | |
| 14864 | memset(biR->comps, 0, (size_t) (num_shifts * COMP_BYTE_SIZE)); /* zero LS comps */ |
| 14865 | return biR; |
| 14866 | } |
| 14867 | #endif |
| 14868 | |
| 14869 | /** |
| 14870 | * @brief Allow a binary sequence to be imported as a bigint. |
| 14871 | * @param ctx [in] The bigint session context. |
| 14872 | * @param data [in] The data to be converted. |
| 14873 | * @param size [in] The number of bytes of data. |
| 14874 | * @return A bigint representing this data. |
| 14875 | */ |
| 14876 | NS_INTERNAL bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) { |
| 14877 | bigint *biR = alloc(ctx, (size + COMP_BYTE_SIZE - 1) / COMP_BYTE_SIZE); |
| 14878 | int i, j = 0, offset = 0; |
| 14879 | |
| 14880 | memset(biR->comps, 0, (size_t) (biR->size * COMP_BYTE_SIZE)); |
| 14881 | |
| 14882 | for (i = size - 1; i >= 0; i--) { |
| 14883 | biR->comps[offset] += (comp) data[i] << (j * 8); |
| 14884 | |
| 14885 | if (++j == COMP_BYTE_SIZE) { |
| 14886 | j = 0; |
| 14887 | offset++; |
| 14888 | } |
| 14889 | } |
| 14890 | |
| 14891 | return trim(biR); |
| 14892 | } |
| 14893 | |
| 14894 | #ifdef CONFIG_SSL_FULL_MODE |
| 14895 | /** |
| 14896 | * @brief The testharness uses this code to import text hex-streams and |
| 14897 | * convert them into bigints. |
| 14898 | * @param ctx [in] The bigint session context. |
| 14899 | * @param data [in] A string consisting of hex characters. The characters must |
| 14900 | * be in upper case. |
| 14901 | * @return A bigint representing this data. |
| 14902 | */ |
| 14903 | NS_INTERNAL bigint *bi_str_import(BI_CTX *ctx, const char *data) { |
| 14904 | int size = strlen(data); |
| 14905 | bigint *biR = alloc(ctx, (size + COMP_NUM_NIBBLES - 1) / COMP_NUM_NIBBLES); |
| 14906 | int i, j = 0, offset = 0; |
| 14907 | memset(biR->comps, 0, (size_t) (biR->size * COMP_BYTE_SIZE)); |
| 14908 | |
| 14909 | for (i = size - 1; i >= 0; i--) { |
| 14910 | int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10); |
| 14911 | biR->comps[offset] += num << (j * 4); |
| 14912 | |
| 14913 | if (++j == COMP_NUM_NIBBLES) { |
| 14914 | j = 0; |
| 14915 | offset++; |
| 14916 | } |
| 14917 | } |
| 14918 | |
| 14919 | return biR; |
| 14920 | } |
| 14921 | |
| 14922 | NS_INTERNAL void bi_print(const char *label, bigint *x) { |
| 14923 | int i, j; |
| 14924 | |
| 14925 | if (x == NULL) { |
| 14926 | printf("%s: (null)\n", label); |
| 14927 | return; |
| 14928 | } |
| 14929 | |
| 14930 | printf("%s: (size %d)\n", label, x->size); |
| 14931 | for (i = x->size - 1; i >= 0; i--) { |
| 14932 | for (j = COMP_NUM_NIBBLES - 1; j >= 0; j--) { |
| 14933 | comp mask = 0x0f << (j * 4); |
| 14934 | comp num = (x->comps[i] & mask) >> (j * 4); |
| 14935 | putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); |
| 14936 | } |
| 14937 | } |
| 14938 | |
| 14939 | printf("\n"); |
| 14940 | } |
| 14941 | #endif |
| 14942 | |
| 14943 | /** |
| 14944 | * @brief Take a bigint and convert it into a byte sequence. |
| 14945 | * |
| 14946 | * This is useful after a decrypt operation. |
| 14947 | * @param ctx [in] The bigint session context. |
| 14948 | * @param x [in] The bigint to be converted. |
| 14949 | * @param data [out] The converted data as a byte stream. |
| 14950 | * @param size [in] The maximum size of the byte stream. Unused bytes will be |
| 14951 | * zeroed. |
| 14952 | */ |
| 14953 | NS_INTERNAL void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) { |
| 14954 | int i, j, k = size - 1; |
| 14955 | |
| 14956 | check(x); |
| 14957 | memset(data, 0, (size_t) size); /* ensure all leading 0's are cleared */ |
| 14958 | |
| 14959 | for (i = 0; i < x->size; i++) { |
| 14960 | for (j = 0; j < COMP_BYTE_SIZE; j++) { |
| 14961 | comp mask = (comp) 0xff << (j * 8); |
| 14962 | int num = (int) (x->comps[i] & mask) >> (j * 8); |
| 14963 | data[k--] = (uint8_t) num; |
| 14964 | |
| 14965 | if (k < 0) { |
| 14966 | goto buf_done; |
| 14967 | } |
| 14968 | } |
| 14969 | } |
| 14970 | buf_done: |
| 14971 | |
| 14972 | bi_free(ctx, x); |
| 14973 | } |
| 14974 | |
| 14975 | /** |
| 14976 | * @brief Pre-calculate some of the expensive steps in reduction. |
| 14977 | * |
| 14978 | * This function should only be called once (normally when a session starts). |
| 14979 | * When the session is over, bi_free_mod() should be called. bi_mod_power() |
| 14980 | * relies on this function being called. |
| 14981 | * @param ctx [in] The bigint session context. |
| 14982 | * @param bim [in] The bigint modulus that will be used. |
| 14983 | * @param mod_offset [in] There are three moduluii that can be stored - the |
| 14984 | * standard modulus, and its two primes p and q. This offset refers to which |
| 14985 | * modulus we are referring to. |
| 14986 | * @see bi_free_mod(), bi_mod_power(). |
| 14987 | */ |
| 14988 | NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) { |
| 14989 | int k = bim->size; |
| 14990 | comp d = (comp)((long_comp) COMP_RADIX / (bim->comps[k - 1] + 1)); |
| 14991 | #ifdef CONFIG_BIGINT_MONTGOMERY |
| 14992 | bigint *R, *R2; |
| 14993 | #endif |
| 14994 | |
| 14995 | ctx->bi_mod[mod_offset] = bim; |
| 14996 | bi_permanent(ctx->bi_mod[mod_offset]); |
| 14997 | ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); |
| 14998 | bi_permanent(ctx->bi_normalised_mod[mod_offset]); |
| 14999 | |
| 15000 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 15001 | /* set montgomery variables */ |
| 15002 | R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k - 1); /* R */ |
| 15003 | R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k * 2 - 1); /* R^2 */ |
| 15004 | ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */ |
| 15005 | ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */ |
| 15006 | |
| 15007 | bi_permanent(ctx->bi_RR_mod_m[mod_offset]); |
| 15008 | bi_permanent(ctx->bi_R_mod_m[mod_offset]); |
| 15009 | |
| 15010 | ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]); |
| 15011 | |
| 15012 | #elif defined(CONFIG_BIGINT_BARRETT) |
| 15013 | ctx->bi_mu[mod_offset] = |
| 15014 | bi_divide(ctx, comp_left_shift(bi_clone(ctx, ctx->bi_radix), k * 2 - 1), |
| 15015 | ctx->bi_mod[mod_offset], 0); |
| 15016 | bi_permanent(ctx->bi_mu[mod_offset]); |
| 15017 | #endif |
| 15018 | } |
| 15019 | |
| 15020 | #if 0 |
| 15021 | /** |
| 15022 | * @brief Used when cleaning various bigints at the end of a session. |
| 15023 | * @param ctx [in] The bigint session context. |
| 15024 | * @param mod_offset [in] The offset to use. |
| 15025 | * @see bi_set_mod(). |
| 15026 | */ |
| 15027 | void bi_free_mod(BI_CTX *ctx, int mod_offset) { |
| 15028 | bi_depermanent(ctx->bi_mod[mod_offset]); |
| 15029 | bi_free(ctx, ctx->bi_mod[mod_offset]); |
| 15030 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 15031 | bi_depermanent(ctx->bi_RR_mod_m[mod_offset]); |
| 15032 | bi_depermanent(ctx->bi_R_mod_m[mod_offset]); |
| 15033 | bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]); |
| 15034 | bi_free(ctx, ctx->bi_R_mod_m[mod_offset]); |
| 15035 | #elif defined(CONFIG_BIGINT_BARRETT) |
| 15036 | bi_depermanent(ctx->bi_mu[mod_offset]); |
| 15037 | bi_free(ctx, ctx->bi_mu[mod_offset]); |
| 15038 | #endif |
| 15039 | bi_depermanent(ctx->bi_normalised_mod[mod_offset]); |
| 15040 | bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); |
| 15041 | } |
| 15042 | #endif |
| 15043 | |
| 15044 | /** |
| 15045 | * Perform a standard multiplication between two bigints. |
| 15046 | * |
| 15047 | * Barrett reduction has no need for some parts of the product, so ignore bits |
| 15048 | * of the multiply. This routine gives Barrett its big performance |
| 15049 | * improvements over Classical/Montgomery reduction methods. |
| 15050 | */ |
| 15051 | static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, |
| 15052 | int inner_partial, int outer_partial) { |
| 15053 | int i = 0, j; |
| 15054 | int n = bia->size; |
| 15055 | int t = bib->size; |
| 15056 | bigint *biR = alloc(ctx, n + t); |
| 15057 | comp *sr = biR->comps; |
| 15058 | comp *sa = bia->comps; |
| 15059 | comp *sb = bib->comps; |
| 15060 | |
| 15061 | check(bia); |
| 15062 | check(bib); |
| 15063 | |
| 15064 | /* clear things to start with */ |
| 15065 | memset(biR->comps, 0, (size_t) ((n + t) * COMP_BYTE_SIZE)); |
| 15066 | |
| 15067 | do { |
| 15068 | long_comp tmp; |
| 15069 | comp carry = 0; |
| 15070 | int r_index = i; |
| 15071 | j = 0; |
| 15072 | |
| 15073 | if (outer_partial && outer_partial - i > 0 && outer_partial < n) { |
| 15074 | r_index = outer_partial - 1; |
| 15075 | j = outer_partial - i - 1; |
| 15076 | } |
| 15077 | |
| 15078 | do { |
| 15079 | if (inner_partial && r_index >= inner_partial) { |
| 15080 | break; |
| 15081 | } |
| 15082 | |
| 15083 | tmp = sr[r_index] + ((long_comp) sa[j]) * sb[i] + carry; |
| 15084 | sr[r_index++] = (comp) tmp; /* downsize */ |
| 15085 | carry = (comp) (tmp >> COMP_BIT_SIZE); |
| 15086 | } while (++j < n); |
| 15087 | |
| 15088 | sr[r_index] = carry; |
| 15089 | } while (++i < t); |
| 15090 | |
| 15091 | bi_free(ctx, bia); |
| 15092 | bi_free(ctx, bib); |
| 15093 | return trim(biR); |
| 15094 | } |
| 15095 | |
| 15096 | #ifdef CONFIG_BIGINT_KARATSUBA |
| 15097 | /* |
| 15098 | * Karatsuba improves on regular multiplication due to only 3 multiplications |
| 15099 | * being done instead of 4. The additional additions/subtractions are O(N) |
| 15100 | * rather than O(N^2) and so for big numbers it saves on a few operations |
| 15101 | */ |
| 15102 | static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) { |
| 15103 | bigint *x0, *x1; |
| 15104 | bigint *p0, *p1, *p2; |
| 15105 | int m; |
| 15106 | |
| 15107 | if (is_square) { |
| 15108 | m = (bia->size + 1) / 2; |
| 15109 | } else { |
| 15110 | m = (MAX(bia->size, bib->size) + 1) / 2; |
| 15111 | } |
| 15112 | |
| 15113 | x0 = bi_clone(ctx, bia); |
| 15114 | x0->size = m; |
| 15115 | x1 = bi_clone(ctx, bia); |
| 15116 | comp_right_shift(x1, m); |
| 15117 | bi_free(ctx, bia); |
| 15118 | |
| 15119 | /* work out the 3 partial products */ |
| 15120 | if (is_square) { |
| 15121 | p0 = bi_square(ctx, bi_copy(x0)); |
| 15122 | p2 = bi_square(ctx, bi_copy(x1)); |
| 15123 | p1 = bi_square(ctx, bi_add(ctx, x0, x1)); |
| 15124 | } else /* normal multiply */ |
| 15125 | { |
| 15126 | bigint *y0, *y1; |
| 15127 | y0 = bi_clone(ctx, bib); |
| 15128 | y0->size = m; |
| 15129 | y1 = bi_clone(ctx, bib); |
| 15130 | comp_right_shift(y1, m); |
| 15131 | bi_free(ctx, bib); |
| 15132 | |
| 15133 | p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); |
| 15134 | p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); |
| 15135 | p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); |
| 15136 | } |
| 15137 | |
| 15138 | p1 = bi_subtract(ctx, bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), |
| 15139 | NULL); |
| 15140 | |
| 15141 | comp_left_shift(p1, m); |
| 15142 | comp_left_shift(p2, 2 * m); |
| 15143 | return bi_add(ctx, p1, bi_add(ctx, p0, p2)); |
| 15144 | } |
| 15145 | #endif |
| 15146 | |
| 15147 | /** |
| 15148 | * @brief Perform a multiplication operation between two bigints. |
| 15149 | * @param ctx [in] The bigint session context. |
| 15150 | * @param bia [in] A bigint. |
| 15151 | * @param bib [in] Another bigint. |
| 15152 | * @return The result of the multiplication. |
| 15153 | */ |
| 15154 | NS_INTERNAL bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) { |
| 15155 | check(bia); |
| 15156 | check(bib); |
| 15157 | |
| 15158 | #ifdef CONFIG_BIGINT_KARATSUBA |
| 15159 | if (MIN(bia->size, bib->size) < MUL_KARATSUBA_THRESH) { |
| 15160 | return regular_multiply(ctx, bia, bib, 0, 0); |
| 15161 | } |
| 15162 | |
| 15163 | return karatsuba(ctx, bia, bib, 0); |
| 15164 | #else |
| 15165 | return regular_multiply(ctx, bia, bib, 0, 0); |
| 15166 | #endif |
| 15167 | } |
| 15168 | |
| 15169 | #ifdef CONFIG_BIGINT_SQUARE |
| 15170 | /* |
| 15171 | * Perform the actual square operion. It takes into account overflow. |
| 15172 | */ |
| 15173 | static bigint *regular_square(BI_CTX *ctx, bigint *bi) { |
| 15174 | int t = bi->size; |
| 15175 | int i = 0, j; |
| 15176 | bigint *biR = alloc(ctx, t * 2 + 1); |
| 15177 | comp *w = biR->comps; |
| 15178 | comp *x = bi->comps; |
| 15179 | long_comp carry; |
| 15180 | memset(w, 0, biR->size * COMP_BYTE_SIZE); |
| 15181 | |
| 15182 | do { |
| 15183 | long_comp tmp = w[2 * i] + (long_comp) x[i] * x[i]; |
| 15184 | w[2 * i] = (comp) tmp; |
| 15185 | carry = tmp >> COMP_BIT_SIZE; |
| 15186 | |
| 15187 | for (j = i + 1; j < t; j++) { |
| 15188 | uint8_t c = 0; |
| 15189 | long_comp xx = (long_comp) x[i] * x[j]; |
| 15190 | if ((COMP_MAX - xx) < xx) c = 1; |
| 15191 | |
| 15192 | tmp = (xx << 1); |
| 15193 | |
| 15194 | if ((COMP_MAX - tmp) < w[i + j]) c = 1; |
| 15195 | |
| 15196 | tmp += w[i + j]; |
| 15197 | |
| 15198 | if ((COMP_MAX - tmp) < carry) c = 1; |
| 15199 | |
| 15200 | tmp += carry; |
| 15201 | w[i + j] = (comp) tmp; |
| 15202 | carry = tmp >> COMP_BIT_SIZE; |
| 15203 | |
| 15204 | if (c) carry += COMP_RADIX; |
| 15205 | } |
| 15206 | |
| 15207 | tmp = w[i + t] + carry; |
| 15208 | w[i + t] = (comp) tmp; |
| 15209 | w[i + t + 1] = tmp >> COMP_BIT_SIZE; |
| 15210 | } while (++i < t); |
| 15211 | |
| 15212 | bi_free(ctx, bi); |
| 15213 | return trim(biR); |
| 15214 | } |
| 15215 | |
| 15216 | /** |
| 15217 | * @brief Perform a square operation on a bigint. |
| 15218 | * @param ctx [in] The bigint session context. |
| 15219 | * @param bia [in] A bigint. |
| 15220 | * @return The result of the multiplication. |
| 15221 | */ |
| 15222 | NS_INTERNAL bigint *bi_square(BI_CTX *ctx, bigint *bia) { |
| 15223 | check(bia); |
| 15224 | |
| 15225 | #ifdef CONFIG_BIGINT_KARATSUBA |
| 15226 | if (bia->size < SQU_KARATSUBA_THRESH) { |
| 15227 | return regular_square(ctx, bia); |
| 15228 | } |
| 15229 | |
| 15230 | return karatsuba(ctx, bia, NULL, 1); |
| 15231 | #else |
| 15232 | return regular_square(ctx, bia); |
| 15233 | #endif |
| 15234 | } |
| 15235 | #endif |
| 15236 | |
| 15237 | /** |
| 15238 | * @brief Compare two bigints. |
| 15239 | * @param bia [in] A bigint. |
| 15240 | * @param bib [in] Another bigint. |
| 15241 | * @return -1 if smaller, 1 if larger and 0 if equal. |
| 15242 | */ |
| 15243 | NS_INTERNAL int bi_compare(bigint *bia, bigint *bib) { |
| 15244 | int r, i; |
| 15245 | |
| 15246 | check(bia); |
| 15247 | check(bib); |
| 15248 | |
| 15249 | if (bia->size > bib->size) |
| 15250 | r = 1; |
| 15251 | else if (bia->size < bib->size) |
| 15252 | r = -1; |
| 15253 | else { |
| 15254 | comp *a = bia->comps; |
| 15255 | comp *b = bib->comps; |
| 15256 | |
| 15257 | /* Same number of components. Compare starting from the high end |
| 15258 | * and working down. */ |
| 15259 | r = 0; |
| 15260 | i = bia->size - 1; |
| 15261 | |
| 15262 | do { |
| 15263 | if (a[i] > b[i]) { |
| 15264 | r = 1; |
| 15265 | break; |
| 15266 | } else if (a[i] < b[i]) { |
| 15267 | r = -1; |
| 15268 | break; |
| 15269 | } |
| 15270 | } while (--i >= 0); |
| 15271 | } |
| 15272 | |
| 15273 | return r; |
| 15274 | } |
| 15275 | |
| 15276 | /* |
| 15277 | * Allocate and zero more components. Does not consume bi. |
| 15278 | */ |
| 15279 | static void more_comps(bigint *bi, int n) { |
| 15280 | if (n > bi->max_comps) { |
| 15281 | int max = MAX(bi->max_comps * 2, n); |
| 15282 | void *p = calloc(1, (size_t) max * COMP_BYTE_SIZE); |
| 15283 | if (p != NULL && bi->size > 0) memcpy(p, bi->comps, (size_t) bi->max_comps * COMP_BYTE_SIZE); |
| 15284 | free(bi->comps); |
| 15285 | bi->max_comps = (short) max; |
| 15286 | bi->comps = (comp *) p; |
| 15287 | } |
| 15288 | |
| 15289 | if (n > bi->size) { |
| 15290 | memset(&bi->comps[bi->size], 0, (size_t) (n - bi->size) * COMP_BYTE_SIZE); |
| 15291 | } |
| 15292 | |
| 15293 | bi->size = (short) n; |
| 15294 | } |
| 15295 | |
| 15296 | /* |
| 15297 | * Make a new empty bigint. It may just use an old one if one is available. |
| 15298 | * Otherwise get one off the heap. |
| 15299 | */ |
| 15300 | static bigint *alloc(BI_CTX *ctx, int size) { |
| 15301 | bigint *biR; |
| 15302 | |
| 15303 | /* Can we recycle an old bigint? */ |
| 15304 | if (ctx->free_list != NULL) { |
| 15305 | biR = ctx->free_list; |
| 15306 | ctx->free_list = biR->next; |
| 15307 | ctx->free_count--; |
| 15308 | |
| 15309 | if (biR->refs != 0) { |
| 15310 | #ifdef CONFIG_SSL_FULL_MODE |
| 15311 | printf("alloc: refs was not 0\n"); |
| 15312 | #endif |
| 15313 | abort(); /* create a stack trace from a core dump */ |
| 15314 | } |
| 15315 | |
| 15316 | more_comps(biR, size); |
| 15317 | } else { |
| 15318 | /* No free bigints available - create a new one. */ |
| 15319 | biR = (bigint *) calloc(1, sizeof(bigint)); |
| 15320 | biR->comps = (comp *) calloc(1, (size_t) size * COMP_BYTE_SIZE); |
| 15321 | biR->max_comps = (short) size; /* give some space to spare */ |
| 15322 | } |
| 15323 | |
| 15324 | biR->size = (short) size; |
| 15325 | biR->refs = 1; |
| 15326 | biR->next = NULL; |
| 15327 | ctx->active_count++; |
| 15328 | return biR; |
| 15329 | } |
| 15330 | |
| 15331 | /* |
| 15332 | * Work out the highest '1' bit in an exponent. Used when doing sliding-window |
| 15333 | * exponentiation. |
| 15334 | */ |
| 15335 | static int find_max_exp_index(bigint *biexp) { |
| 15336 | int i = COMP_BIT_SIZE - 1; |
| 15337 | comp shift = COMP_RADIX / 2; |
| 15338 | comp test = biexp->comps[biexp->size - 1]; /* assume no leading zeroes */ |
| 15339 | |
| 15340 | check(biexp); |
| 15341 | |
| 15342 | do { |
| 15343 | if (test & shift) { |
| 15344 | return i + (biexp->size - 1) * COMP_BIT_SIZE; |
| 15345 | } |
| 15346 | |
| 15347 | shift >>= 1; |
| 15348 | } while (i-- != 0); |
| 15349 | |
| 15350 | return -1; /* error - must have been a leading 0 */ |
| 15351 | } |
| 15352 | |
| 15353 | /* |
| 15354 | * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window |
| 15355 | * exponentiation. |
| 15356 | */ |
| 15357 | static int exp_bit_is_one(bigint *biexp, int offset) { |
| 15358 | comp test = biexp->comps[offset / COMP_BIT_SIZE]; |
| 15359 | int num_shifts = offset % COMP_BIT_SIZE; |
| 15360 | comp shift = 1; |
| 15361 | int i; |
| 15362 | |
| 15363 | check(biexp); |
| 15364 | |
| 15365 | for (i = 0; i < num_shifts; i++) { |
| 15366 | shift <<= 1; |
| 15367 | } |
| 15368 | |
| 15369 | return (test & shift) != 0; |
| 15370 | } |
| 15371 | |
| 15372 | #ifdef CONFIG_BIGINT_CHECK_ON |
| 15373 | /* |
| 15374 | * Perform a sanity check on bi. |
| 15375 | */ |
| 15376 | static void check(const bigint *bi) { |
| 15377 | if (bi->refs <= 0) { |
| 15378 | printf("check: zero or negative refs in bigint\n"); |
| 15379 | abort(); |
| 15380 | } |
| 15381 | |
| 15382 | if (bi->next != NULL) { |
| 15383 | printf( |
| 15384 | "check: attempt to use a bigint from " |
| 15385 | "the free list\n"); |
| 15386 | abort(); |
| 15387 | } |
| 15388 | } |
| 15389 | #endif |
| 15390 | |
| 15391 | /* |
| 15392 | * Delete any leading 0's (and allow for 0). |
| 15393 | */ |
| 15394 | static bigint *trim(bigint *bi) { |
| 15395 | check(bi); |
| 15396 | |
| 15397 | while (bi->comps[bi->size - 1] == 0 && bi->size > 1) { |
| 15398 | bi->size--; |
| 15399 | } |
| 15400 | |
| 15401 | return bi; |
| 15402 | } |
| 15403 | |
| 15404 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 15405 | /** |
| 15406 | * @brief Perform a single montgomery reduction. |
| 15407 | * @param ctx [in] The bigint session context. |
| 15408 | * @param bixy [in] A bigint. |
| 15409 | * @return The result of the montgomery reduction. |
| 15410 | */ |
| 15411 | NS_INTERNAL bigint *bi_mont(BI_CTX *ctx, bigint *bixy) { |
| 15412 | int i = 0, n; |
| 15413 | uint8_t mod_offset = ctx->mod_offset; |
| 15414 | bigint *bim = ctx->bi_mod[mod_offset]; |
| 15415 | comp mod_inv = ctx->N0_dash[mod_offset]; |
| 15416 | |
| 15417 | check(bixy); |
| 15418 | |
| 15419 | if (ctx->use_classical) /* just use classical instead */ |
| 15420 | { |
| 15421 | return bi_mod(ctx, bixy); |
| 15422 | } |
| 15423 | |
| 15424 | n = bim->size; |
| 15425 | |
| 15426 | do { |
| 15427 | bixy = bi_add(ctx, bixy, |
| 15428 | comp_left_shift( |
| 15429 | bi_int_multiply(ctx, bim, bixy->comps[i] * mod_inv), i)); |
| 15430 | } while (++i < n); |
| 15431 | |
| 15432 | comp_right_shift(bixy, n); |
| 15433 | |
| 15434 | if (bi_compare(bixy, bim) >= 0) { |
| 15435 | bixy = bi_subtract(ctx, bixy, bim, NULL); |
| 15436 | } |
| 15437 | |
| 15438 | return bixy; |
| 15439 | } |
| 15440 | |
| 15441 | #elif defined(CONFIG_BIGINT_BARRETT) |
| 15442 | /* |
| 15443 | * Stomp on the most significant components to give the illusion of a "mod base |
| 15444 | * radix" operation |
| 15445 | */ |
| 15446 | static bigint *comp_mod(bigint *bi, int mod) { |
| 15447 | check(bi); |
| 15448 | |
| 15449 | if (bi->size > mod) { |
| 15450 | bi->size = mod; |
| 15451 | } |
| 15452 | |
| 15453 | return bi; |
| 15454 | } |
| 15455 | |
| 15456 | /** |
| 15457 | * @brief Perform a single Barrett reduction. |
| 15458 | * @param ctx [in] The bigint session context. |
| 15459 | * @param bi [in] A bigint. |
| 15460 | * @return The result of the Barrett reduction. |
| 15461 | */ |
| 15462 | NS_INTERNAL bigint *bi_barrett(BI_CTX *ctx, bigint *bi) { |
| 15463 | bigint *q1, *q2, *q3, *r1, *r2, *r; |
| 15464 | uint8_t mod_offset = ctx->mod_offset; |
| 15465 | bigint *bim = ctx->bi_mod[mod_offset]; |
| 15466 | int k = bim->size; |
| 15467 | |
| 15468 | check(bi); |
| 15469 | check(bim); |
| 15470 | |
| 15471 | /* use Classical method instead - Barrett cannot help here */ |
| 15472 | if (bi->size > k * 2) { |
| 15473 | return bi_mod(ctx, bi); |
| 15474 | } |
| 15475 | |
| 15476 | q1 = comp_right_shift(bi_clone(ctx, bi), k - 1); |
| 15477 | |
| 15478 | /* do outer partial multiply */ |
| 15479 | q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k - 1); |
| 15480 | q3 = comp_right_shift(q2, k + 1); |
| 15481 | r1 = comp_mod(bi, k + 1); |
| 15482 | |
| 15483 | /* do inner partial multiply */ |
| 15484 | r2 = comp_mod(regular_multiply(ctx, q3, bim, k + 1, 0), k + 1); |
| 15485 | r = bi_subtract(ctx, r1, r2, NULL); |
| 15486 | |
| 15487 | /* if (r >= m) r = r - m; */ |
| 15488 | if (bi_compare(r, bim) >= 0) { |
| 15489 | r = bi_subtract(ctx, r, bim, NULL); |
| 15490 | } |
| 15491 | |
| 15492 | return r; |
| 15493 | } |
| 15494 | #endif /* CONFIG_BIGINT_BARRETT */ |
| 15495 | |
| 15496 | #ifdef CONFIG_BIGINT_SLIDING_WINDOW |
| 15497 | /* |
| 15498 | * Work out g1, g3, g5, g7... etc for the sliding-window algorithm |
| 15499 | */ |
| 15500 | static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) { |
| 15501 | int k = 1, i; |
| 15502 | bigint *g2; |
| 15503 | |
| 15504 | for (i = 0; i < window - 1; i++) /* compute 2^(window-1) */ |
| 15505 | { |
| 15506 | k <<= 1; |
| 15507 | } |
| 15508 | |
| 15509 | ctx->g = (bigint **) calloc(1, k * sizeof(bigint *)); |
| 15510 | ctx->g[0] = bi_clone(ctx, g1); |
| 15511 | bi_permanent(ctx->g[0]); |
| 15512 | g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ |
| 15513 | |
| 15514 | for (i = 1; i < k; i++) { |
| 15515 | ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i - 1], bi_copy(g2))); |
| 15516 | bi_permanent(ctx->g[i]); |
| 15517 | } |
| 15518 | |
| 15519 | bi_free(ctx, g2); |
| 15520 | ctx->window = k; |
| 15521 | } |
| 15522 | #endif |
| 15523 | |
| 15524 | /** |
| 15525 | * @brief Perform a modular exponentiation. |
| 15526 | * |
| 15527 | * This function requires bi_set_mod() to have been called previously. This is |
| 15528 | * one of the optimisations used for performance. |
| 15529 | * @param ctx [in] The bigint session context. |
| 15530 | * @param bi [in] The bigint on which to perform the mod power operation. |
| 15531 | * @param biexp [in] The bigint exponent. |
| 15532 | * @return The result of the mod exponentiation operation |
| 15533 | * @see bi_set_mod(). |
| 15534 | */ |
| 15535 | NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) { |
| 15536 | int i = find_max_exp_index(biexp), j, window_size = 1; |
| 15537 | bigint *biR = int_to_bi(ctx, 1); |
| 15538 | |
| 15539 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 15540 | uint8_t mod_offset = ctx->mod_offset; |
| 15541 | if (!ctx->use_classical) { |
| 15542 | /* preconvert */ |
| 15543 | bi = bi_mont(ctx, |
| 15544 | bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ |
| 15545 | bi_free(ctx, biR); |
| 15546 | biR = ctx->bi_R_mod_m[mod_offset]; /* A */ |
| 15547 | } |
| 15548 | #endif |
| 15549 | |
| 15550 | check(bi); |
| 15551 | check(biexp); |
| 15552 | |
| 15553 | #ifdef CONFIG_BIGINT_SLIDING_WINDOW |
| 15554 | for (j = i; j > 32; j /= 5) /* work out an optimum size */ |
| 15555 | window_size++; |
| 15556 | |
| 15557 | /* work out the slide constants */ |
| 15558 | precompute_slide_window(ctx, window_size, bi); |
| 15559 | #else /* just one constant */ |
| 15560 | ctx->g = (bigint **) calloc(1, sizeof(bigint *)); |
| 15561 | ctx->g[0] = bi_clone(ctx, bi); |
| 15562 | ctx->window = 1; |
| 15563 | bi_permanent(ctx->g[0]); |
| 15564 | #endif |
| 15565 | |
| 15566 | /* if sliding-window is off, then only one bit will be done at a time and |
| 15567 | * will reduce to standard left-to-right exponentiation */ |
| 15568 | do { |
| 15569 | if (exp_bit_is_one(biexp, i)) { |
| 15570 | int l = i - window_size + 1; |
| 15571 | int part_exp = 0; |
| 15572 | |
| 15573 | if (l < 0) /* LSB of exponent will always be 1 */ |
| 15574 | l = 0; |
| 15575 | else { |
| 15576 | while (exp_bit_is_one(biexp, l) == 0) l++; /* go back up */ |
| 15577 | } |
| 15578 | |
| 15579 | /* build up the section of the exponent */ |
| 15580 | for (j = i; j >= l; j--) { |
| 15581 | biR = bi_residue(ctx, bi_square(ctx, biR)); |
| 15582 | if (exp_bit_is_one(biexp, j)) part_exp++; |
| 15583 | |
| 15584 | if (j != l) part_exp <<= 1; |
| 15585 | } |
| 15586 | |
| 15587 | part_exp = (part_exp - 1) / 2; /* adjust for array */ |
| 15588 | biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); |
| 15589 | i = l - 1; |
| 15590 | } else /* square it */ |
| 15591 | { |
| 15592 | biR = bi_residue(ctx, bi_square(ctx, biR)); |
| 15593 | i--; |
| 15594 | } |
| 15595 | } while (i >= 0); |
| 15596 | |
| 15597 | /* cleanup */ |
| 15598 | for (i = 0; i < ctx->window; i++) { |
| 15599 | bi_depermanent(ctx->g[i]); |
| 15600 | bi_free(ctx, ctx->g[i]); |
| 15601 | } |
| 15602 | |
| 15603 | free(ctx->g); |
| 15604 | bi_free(ctx, bi); |
| 15605 | bi_free(ctx, biexp); |
| 15606 | #if defined CONFIG_BIGINT_MONTGOMERY |
| 15607 | return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ |
| 15608 | #else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ |
| 15609 | return biR; |
| 15610 | #endif |
| 15611 | } |
| 15612 | |
| 15613 | #if 0 |
| 15614 | /** |
| 15615 | * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. |
| 15616 | * |
| 15617 | * @param ctx [in] The bigint session context. |
| 15618 | * @param bi [in] The bigint to perform the exp/mod. |
| 15619 | * @param dP [in] CRT's dP bigint |
| 15620 | * @param dQ [in] CRT's dQ bigint |
| 15621 | * @param p [in] CRT's p bigint |
| 15622 | * @param q [in] CRT's q bigint |
| 15623 | * @param qInv [in] CRT's qInv bigint |
| 15624 | * @return The result of the CRT operation |
| 15625 | */ |
| 15626 | NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, |
| 15627 | bigint *p, bigint *q, bigint *qInv) { |
| 15628 | bigint *m1, *m2, *h; |
| 15629 | |
| 15630 | /* Montgomery has a condition the 0 < x, y < m and these products violate |
| 15631 | * that condition. So disable Montgomery when using CRT */ |
| 15632 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 15633 | ctx->use_classical = 1; |
| 15634 | #endif |
| 15635 | ctx->mod_offset = BIGINT_P_OFFSET; |
| 15636 | m1 = bi_mod_power(ctx, bi_copy(bi), dP); |
| 15637 | |
| 15638 | ctx->mod_offset = BIGINT_Q_OFFSET; |
| 15639 | m2 = bi_mod_power(ctx, bi, dQ); |
| 15640 | |
| 15641 | h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); |
| 15642 | h = bi_multiply(ctx, h, qInv); |
| 15643 | ctx->mod_offset = BIGINT_P_OFFSET; |
| 15644 | h = bi_residue(ctx, h); |
| 15645 | #if defined(CONFIG_BIGINT_MONTGOMERY) |
| 15646 | ctx->use_classical = 0; /* reset for any further operation */ |
| 15647 | #endif |
| 15648 | return bi_add(ctx, m2, bi_multiply(ctx, q, h)); |
| 15649 | } |
| 15650 | #endif |
| 15651 | |
| 15652 | int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz) { |
| 15653 | BI_CTX *bi_ctx = bi_initialize(); |
| 15654 | bigint *n = bi_import(bi_ctx, mod, (int) modsz); |
| 15655 | bigint *e = bi_import(bi_ctx, exp, (int) expsz); |
| 15656 | bigint *h = bi_import(bi_ctx, msg, (int) msgsz); |
| 15657 | bi_set_mod(bi_ctx, n, 0); |
| 15658 | bigint *m1 = bi_mod_power(bi_ctx, h, e); |
| 15659 | bi_export(bi_ctx, m1, out, (int) outsz); |
| 15660 | bi_free(bi_ctx, n); |
| 15661 | bi_free(bi_ctx, e); |
| 15662 | bi_free(bi_ctx, h); |
| 15663 | bi_free(bi_ctx, m1); |
| 15664 | return 0; |
| 15665 | } |
| 15666 | |
| 15667 | #endif /* MG_TLS == MG_TLS_BUILTIN */ |
| 15668 | |
| 15669 | #ifdef MG_ENABLE_LINES |
| 15670 | #line 1 "src/tls_uecc.c" |
| 15671 | #endif |
| 15672 | /* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ |
| 15673 | |
| 15674 | |
| 15675 | |
| 15676 | |
| 15677 | #if MG_TLS == MG_TLS_BUILTIN |
| 15678 | |
| 15679 | #ifndef MG_UECC_RNG_MAX_TRIES |
| 15680 | #define MG_UECC_RNG_MAX_TRIES 64 |
| 15681 | #endif |
| 15682 | |
| 15683 | #if MG_UECC_ENABLE_VLI_API |
| 15684 | #define MG_UECC_VLI_API |
| 15685 | #else |
| 15686 | #define MG_UECC_VLI_API static |
| 15687 | #endif |
| 15688 | |
| 15689 | #if (MG_UECC_PLATFORM == mg_uecc_avr) || (MG_UECC_PLATFORM == mg_uecc_arm) || \ |
| 15690 | (MG_UECC_PLATFORM == mg_uecc_arm_thumb) || \ |
| 15691 | (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) |
| 15692 | #define MG_UECC_CONCATX(a, ...) a##__VA_ARGS__ |
| 15693 | #define MG_UECC_CONCAT(a, ...) MG_UECC_CONCATX(a, __VA_ARGS__) |
| 15694 | |
| 15695 | #define STRX(a) #a |
| 15696 | #define STR(a) STRX(a) |
| 15697 | |
| 15698 | #define EVAL(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__)))) |
| 15699 | #define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__)))) |
| 15700 | #define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__)))) |
| 15701 | #define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__)))) |
| 15702 | #define EVAL4(...) __VA_ARGS__ |
| 15703 | |
| 15704 | #define DEC_1 0 |
| 15705 | #define DEC_2 1 |
| 15706 | #define DEC_3 2 |
| 15707 | #define DEC_4 3 |
| 15708 | #define DEC_5 4 |
| 15709 | #define DEC_6 5 |
| 15710 | #define DEC_7 6 |
| 15711 | #define DEC_8 7 |
| 15712 | #define DEC_9 8 |
| 15713 | #define DEC_10 9 |
| 15714 | #define DEC_11 10 |
| 15715 | #define DEC_12 11 |
| 15716 | #define DEC_13 12 |
| 15717 | #define DEC_14 13 |
| 15718 | #define DEC_15 14 |
| 15719 | #define DEC_16 15 |
| 15720 | #define DEC_17 16 |
| 15721 | #define DEC_18 17 |
| 15722 | #define DEC_19 18 |
| 15723 | #define DEC_20 19 |
| 15724 | #define DEC_21 20 |
| 15725 | #define DEC_22 21 |
| 15726 | #define DEC_23 22 |
| 15727 | #define DEC_24 23 |
| 15728 | #define DEC_25 24 |
| 15729 | #define DEC_26 25 |
| 15730 | #define DEC_27 26 |
| 15731 | #define DEC_28 27 |
| 15732 | #define DEC_29 28 |
| 15733 | #define DEC_30 29 |
| 15734 | #define DEC_31 30 |
| 15735 | #define DEC_32 31 |
| 15736 | |
| 15737 | #define DEC_(N) MG_UECC_CONCAT(DEC_, N) |
| 15738 | |
| 15739 | #define SECOND_ARG(_, val, ...) val |
| 15740 | #define SOME_CHECK_0 ~, 0 |
| 15741 | #define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME, ) |
| 15742 | #define SOME_OR_0(N) GET_SECOND_ARG(MG_UECC_CONCAT(SOME_CHECK_, N)) |
| 15743 | |
| 15744 | #define MG_UECC_EMPTY(...) |
| 15745 | #define DEFER(...) __VA_ARGS__ MG_UECC_EMPTY() |
| 15746 | |
| 15747 | #define REPEAT_NAME_0() REPEAT_0 |
| 15748 | #define REPEAT_NAME_SOME() REPEAT_SOME |
| 15749 | #define REPEAT_0(...) |
| 15750 | #define REPEAT_SOME(N, stuff) \ |
| 15751 | DEFER(MG_UECC_CONCAT(REPEAT_NAME_, SOME_OR_0(DEC_(N))))()(DEC_(N), stuff) stuff |
| 15752 | #define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff)) |
| 15753 | |
| 15754 | #define REPEATM_NAME_0() REPEATM_0 |
| 15755 | #define REPEATM_NAME_SOME() REPEATM_SOME |
| 15756 | #define REPEATM_0(...) |
| 15757 | #define REPEATM_SOME(N, macro) \ |
| 15758 | macro(N) DEFER(MG_UECC_CONCAT(REPEATM_NAME_, SOME_OR_0(DEC_(N))))()(DEC_(N), macro) |
| 15759 | #define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro)) |
| 15760 | #endif |
| 15761 | |
| 15762 | // |
| 15763 | |
| 15764 | #if (MG_UECC_WORD_SIZE == 1) |
| 15765 | #if MG_UECC_SUPPORTS_secp160r1 |
| 15766 | #define MG_UECC_MAX_WORDS 21 /* Due to the size of curve_n. */ |
| 15767 | #endif |
| 15768 | #if MG_UECC_SUPPORTS_secp192r1 |
| 15769 | #undef MG_UECC_MAX_WORDS |
| 15770 | #define MG_UECC_MAX_WORDS 24 |
| 15771 | #endif |
| 15772 | #if MG_UECC_SUPPORTS_secp224r1 |
| 15773 | #undef MG_UECC_MAX_WORDS |
| 15774 | #define MG_UECC_MAX_WORDS 28 |
| 15775 | #endif |
| 15776 | #if (MG_UECC_SUPPORTS_secp256r1 || MG_UECC_SUPPORTS_secp256k1) |
| 15777 | #undef MG_UECC_MAX_WORDS |
| 15778 | #define MG_UECC_MAX_WORDS 32 |
| 15779 | #endif |
| 15780 | #elif (MG_UECC_WORD_SIZE == 4) |
| 15781 | #if MG_UECC_SUPPORTS_secp160r1 |
| 15782 | #define MG_UECC_MAX_WORDS 6 /* Due to the size of curve_n. */ |
| 15783 | #endif |
| 15784 | #if MG_UECC_SUPPORTS_secp192r1 |
| 15785 | #undef MG_UECC_MAX_WORDS |
| 15786 | #define MG_UECC_MAX_WORDS 6 |
| 15787 | #endif |
| 15788 | #if MG_UECC_SUPPORTS_secp224r1 |
| 15789 | #undef MG_UECC_MAX_WORDS |
| 15790 | #define MG_UECC_MAX_WORDS 7 |
| 15791 | #endif |
| 15792 | #if (MG_UECC_SUPPORTS_secp256r1 || MG_UECC_SUPPORTS_secp256k1) |
| 15793 | #undef MG_UECC_MAX_WORDS |
| 15794 | #define MG_UECC_MAX_WORDS 8 |
| 15795 | #endif |
| 15796 | #elif (MG_UECC_WORD_SIZE == 8) |
| 15797 | #if MG_UECC_SUPPORTS_secp160r1 |
| 15798 | #define MG_UECC_MAX_WORDS 3 |
| 15799 | #endif |
| 15800 | #if MG_UECC_SUPPORTS_secp192r1 |
| 15801 | #undef MG_UECC_MAX_WORDS |
| 15802 | #define MG_UECC_MAX_WORDS 3 |
| 15803 | #endif |
| 15804 | #if MG_UECC_SUPPORTS_secp224r1 |
| 15805 | #undef MG_UECC_MAX_WORDS |
| 15806 | #define MG_UECC_MAX_WORDS 4 |
| 15807 | #endif |
| 15808 | #if (MG_UECC_SUPPORTS_secp256r1 || MG_UECC_SUPPORTS_secp256k1) |
| 15809 | #undef MG_UECC_MAX_WORDS |
| 15810 | #define MG_UECC_MAX_WORDS 4 |
| 15811 | #endif |
| 15812 | #endif /* MG_UECC_WORD_SIZE */ |
| 15813 | |
| 15814 | #define BITS_TO_WORDS(num_bits) \ |
| 15815 | ((wordcount_t) ((num_bits + ((MG_UECC_WORD_SIZE * 8) - 1)) / \ |
| 15816 | (MG_UECC_WORD_SIZE * 8))) |
| 15817 | #define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8) |
| 15818 | |
| 15819 | struct MG_UECC_Curve_t { |
| 15820 | wordcount_t num_words; |
| 15821 | wordcount_t num_bytes; |
| 15822 | bitcount_t num_n_bits; |
| 15823 | mg_uecc_word_t p[MG_UECC_MAX_WORDS]; |
| 15824 | mg_uecc_word_t n[MG_UECC_MAX_WORDS]; |
| 15825 | mg_uecc_word_t G[MG_UECC_MAX_WORDS * 2]; |
| 15826 | mg_uecc_word_t b[MG_UECC_MAX_WORDS]; |
| 15827 | void (*double_jacobian)(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 15828 | mg_uecc_word_t *Z1, MG_UECC_Curve curve); |
| 15829 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 15830 | void (*mod_sqrt)(mg_uecc_word_t *a, MG_UECC_Curve curve); |
| 15831 | #endif |
| 15832 | void (*x_side)(mg_uecc_word_t *result, const mg_uecc_word_t *x, |
| 15833 | MG_UECC_Curve curve); |
| 15834 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 15835 | void (*mmod_fast)(mg_uecc_word_t *result, mg_uecc_word_t *product); |
| 15836 | #endif |
| 15837 | }; |
| 15838 | |
| 15839 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 15840 | static void bcopy(uint8_t *dst, const uint8_t *src, unsigned num_bytes) { |
| 15841 | while (0 != num_bytes) { |
| 15842 | num_bytes--; |
| 15843 | dst[num_bytes] = src[num_bytes]; |
| 15844 | } |
| 15845 | } |
| 15846 | #endif |
| 15847 | |
| 15848 | static cmpresult_t mg_uecc_vli_cmp_unsafe(const mg_uecc_word_t *left, |
| 15849 | const mg_uecc_word_t *right, |
| 15850 | wordcount_t num_words); |
| 15851 | |
| 15852 | #if (MG_UECC_PLATFORM == mg_uecc_arm || \ |
| 15853 | MG_UECC_PLATFORM == mg_uecc_arm_thumb || \ |
| 15854 | MG_UECC_PLATFORM == mg_uecc_arm_thumb2) |
| 15855 | |
| 15856 | #endif |
| 15857 | |
| 15858 | #if (MG_UECC_PLATFORM == mg_uecc_avr) |
| 15859 | |
| 15860 | #endif |
| 15861 | |
| 15862 | #ifndef asm_clear |
| 15863 | #define asm_clear 0 |
| 15864 | #endif |
| 15865 | #ifndef asm_set |
| 15866 | #define asm_set 0 |
| 15867 | #endif |
| 15868 | #ifndef asm_add |
| 15869 | #define asm_add 0 |
| 15870 | #endif |
| 15871 | #ifndef asm_sub |
| 15872 | #define asm_sub 0 |
| 15873 | #endif |
| 15874 | #ifndef asm_mult |
| 15875 | #define asm_mult 0 |
| 15876 | #endif |
| 15877 | #ifndef asm_rshift1 |
| 15878 | #define asm_rshift1 0 |
| 15879 | #endif |
| 15880 | #ifndef asm_mmod_fast_secp256r1 |
| 15881 | #define asm_mmod_fast_secp256r1 0 |
| 15882 | #endif |
| 15883 | |
| 15884 | #if defined(default_RNG_defined) && default_RNG_defined |
| 15885 | static MG_UECC_RNG_Function g_rng_function = &default_RNG; |
| 15886 | #else |
| 15887 | static MG_UECC_RNG_Function g_rng_function = 0; |
| 15888 | #endif |
| 15889 | |
| 15890 | void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function) { |
| 15891 | g_rng_function = rng_function; |
| 15892 | } |
| 15893 | |
| 15894 | MG_UECC_RNG_Function mg_uecc_get_rng(void) { |
| 15895 | return g_rng_function; |
| 15896 | } |
| 15897 | |
| 15898 | int mg_uecc_curve_private_key_size(MG_UECC_Curve curve) { |
| 15899 | return BITS_TO_BYTES(curve->num_n_bits); |
| 15900 | } |
| 15901 | |
| 15902 | int mg_uecc_curve_public_key_size(MG_UECC_Curve curve) { |
| 15903 | return 2 * curve->num_bytes; |
| 15904 | } |
| 15905 | |
| 15906 | #if !asm_clear |
| 15907 | MG_UECC_VLI_API void mg_uecc_vli_clear(mg_uecc_word_t *vli, |
| 15908 | wordcount_t num_words) { |
| 15909 | wordcount_t i; |
| 15910 | for (i = 0; i < num_words; ++i) { |
| 15911 | vli[i] = 0; |
| 15912 | } |
| 15913 | } |
| 15914 | #endif /* !asm_clear */ |
| 15915 | |
| 15916 | /* Constant-time comparison to zero - secure way to compare long integers */ |
| 15917 | /* Returns 1 if vli == 0, 0 otherwise. */ |
| 15918 | MG_UECC_VLI_API mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli, |
| 15919 | wordcount_t num_words) { |
| 15920 | mg_uecc_word_t bits = 0; |
| 15921 | wordcount_t i; |
| 15922 | for (i = 0; i < num_words; ++i) { |
| 15923 | bits |= vli[i]; |
| 15924 | } |
| 15925 | return (bits == 0); |
| 15926 | } |
| 15927 | |
| 15928 | /* Returns nonzero if bit 'bit' of vli is set. */ |
| 15929 | MG_UECC_VLI_API mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, |
| 15930 | bitcount_t bit) { |
| 15931 | return (vli[bit >> MG_UECC_WORD_BITS_SHIFT] & |
| 15932 | ((mg_uecc_word_t) 1 << (bit & MG_UECC_WORD_BITS_MASK))); |
| 15933 | } |
| 15934 | |
| 15935 | /* Counts the number of words in vli. */ |
| 15936 | static wordcount_t vli_numDigits(const mg_uecc_word_t *vli, |
| 15937 | const wordcount_t max_words) { |
| 15938 | wordcount_t i; |
| 15939 | /* Search from the end until we find a non-zero digit. |
| 15940 | We do it in reverse because we expect that most digits will be nonzero. */ |
| 15941 | for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { |
| 15942 | } |
| 15943 | |
| 15944 | return (i + 1); |
| 15945 | } |
| 15946 | |
| 15947 | /* Counts the number of bits required to represent vli. */ |
| 15948 | MG_UECC_VLI_API bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli, |
| 15949 | const wordcount_t max_words) { |
| 15950 | mg_uecc_word_t i; |
| 15951 | mg_uecc_word_t digit; |
| 15952 | |
| 15953 | wordcount_t num_digits = vli_numDigits(vli, max_words); |
| 15954 | if (num_digits == 0) { |
| 15955 | return 0; |
| 15956 | } |
| 15957 | |
| 15958 | digit = vli[num_digits - 1]; |
| 15959 | for (i = 0; digit; ++i) { |
| 15960 | digit >>= 1; |
| 15961 | } |
| 15962 | |
| 15963 | return (((bitcount_t) ((num_digits - 1) << MG_UECC_WORD_BITS_SHIFT)) + |
| 15964 | (bitcount_t) i); |
| 15965 | } |
| 15966 | |
| 15967 | /* Sets dest = src. */ |
| 15968 | #if !asm_set |
| 15969 | MG_UECC_VLI_API void mg_uecc_vli_set(mg_uecc_word_t *dest, |
| 15970 | const mg_uecc_word_t *src, |
| 15971 | wordcount_t num_words) { |
| 15972 | wordcount_t i; |
| 15973 | for (i = 0; i < num_words; ++i) { |
| 15974 | dest[i] = src[i]; |
| 15975 | } |
| 15976 | } |
| 15977 | #endif /* !asm_set */ |
| 15978 | |
| 15979 | /* Returns sign of left - right. */ |
| 15980 | static cmpresult_t mg_uecc_vli_cmp_unsafe(const mg_uecc_word_t *left, |
| 15981 | const mg_uecc_word_t *right, |
| 15982 | wordcount_t num_words) { |
| 15983 | wordcount_t i; |
| 15984 | for (i = num_words - 1; i >= 0; --i) { |
| 15985 | if (left[i] > right[i]) { |
| 15986 | return 1; |
| 15987 | } else if (left[i] < right[i]) { |
| 15988 | return -1; |
| 15989 | } |
| 15990 | } |
| 15991 | return 0; |
| 15992 | } |
| 15993 | |
| 15994 | /* Constant-time comparison function - secure way to compare long integers */ |
| 15995 | /* Returns one if left == right, zero otherwise. */ |
| 15996 | MG_UECC_VLI_API mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left, |
| 15997 | const mg_uecc_word_t *right, |
| 15998 | wordcount_t num_words) { |
| 15999 | mg_uecc_word_t diff = 0; |
| 16000 | wordcount_t i; |
| 16001 | for (i = num_words - 1; i >= 0; --i) { |
| 16002 | diff |= (left[i] ^ right[i]); |
| 16003 | } |
| 16004 | return (diff == 0); |
| 16005 | } |
| 16006 | |
| 16007 | MG_UECC_VLI_API mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result, |
| 16008 | const mg_uecc_word_t *left, |
| 16009 | const mg_uecc_word_t *right, |
| 16010 | wordcount_t num_words); |
| 16011 | |
| 16012 | /* Returns sign of left - right, in constant time. */ |
| 16013 | MG_UECC_VLI_API cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left, |
| 16014 | const mg_uecc_word_t *right, |
| 16015 | wordcount_t num_words) { |
| 16016 | mg_uecc_word_t tmp[MG_UECC_MAX_WORDS]; |
| 16017 | mg_uecc_word_t neg = !!mg_uecc_vli_sub(tmp, left, right, num_words); |
| 16018 | mg_uecc_word_t equal = mg_uecc_vli_isZero(tmp, num_words); |
| 16019 | return (cmpresult_t) (!equal - 2 * neg); |
| 16020 | } |
| 16021 | |
| 16022 | /* Computes vli = vli >> 1. */ |
| 16023 | #if !asm_rshift1 |
| 16024 | MG_UECC_VLI_API void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, |
| 16025 | wordcount_t num_words) { |
| 16026 | mg_uecc_word_t *end = vli; |
| 16027 | mg_uecc_word_t carry = 0; |
| 16028 | |
| 16029 | vli += num_words; |
| 16030 | while (vli-- > end) { |
| 16031 | mg_uecc_word_t temp = *vli; |
| 16032 | *vli = (temp >> 1) | carry; |
| 16033 | carry = temp << (MG_UECC_WORD_BITS - 1); |
| 16034 | } |
| 16035 | } |
| 16036 | #endif /* !asm_rshift1 */ |
| 16037 | |
| 16038 | /* Computes result = left + right, returning carry. Can modify in place. */ |
| 16039 | #if !asm_add |
| 16040 | MG_UECC_VLI_API mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result, |
| 16041 | const mg_uecc_word_t *left, |
| 16042 | const mg_uecc_word_t *right, |
| 16043 | wordcount_t num_words) { |
| 16044 | mg_uecc_word_t carry = 0; |
| 16045 | wordcount_t i; |
| 16046 | for (i = 0; i < num_words; ++i) { |
| 16047 | mg_uecc_word_t sum = left[i] + right[i] + carry; |
| 16048 | if (sum != left[i]) { |
| 16049 | carry = (sum < left[i]); |
| 16050 | } |
| 16051 | result[i] = sum; |
| 16052 | } |
| 16053 | return carry; |
| 16054 | } |
| 16055 | #endif /* !asm_add */ |
| 16056 | |
| 16057 | /* Computes result = left - right, returning borrow. Can modify in place. */ |
| 16058 | #if !asm_sub |
| 16059 | MG_UECC_VLI_API mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result, |
| 16060 | const mg_uecc_word_t *left, |
| 16061 | const mg_uecc_word_t *right, |
| 16062 | wordcount_t num_words) { |
| 16063 | mg_uecc_word_t borrow = 0; |
| 16064 | wordcount_t i; |
| 16065 | for (i = 0; i < num_words; ++i) { |
| 16066 | mg_uecc_word_t diff = left[i] - right[i] - borrow; |
| 16067 | if (diff != left[i]) { |
| 16068 | borrow = (diff > left[i]); |
| 16069 | } |
| 16070 | result[i] = diff; |
| 16071 | } |
| 16072 | return borrow; |
| 16073 | } |
| 16074 | #endif /* !asm_sub */ |
| 16075 | |
| 16076 | #if !asm_mult || (MG_UECC_SQUARE_FUNC && !asm_square) || \ |
| 16077 | (MG_UECC_SUPPORTS_secp256k1 && (MG_UECC_OPTIMIZATION_LEVEL > 0) && \ |
| 16078 | ((MG_UECC_WORD_SIZE == 1) || (MG_UECC_WORD_SIZE == 8))) |
| 16079 | static void muladd(mg_uecc_word_t a, mg_uecc_word_t b, mg_uecc_word_t *r0, |
| 16080 | mg_uecc_word_t *r1, mg_uecc_word_t *r2) { |
| 16081 | #if MG_UECC_WORD_SIZE == 8 |
| 16082 | uint64_t a0 = a & 0xffffffff; |
| 16083 | uint64_t a1 = a >> 32; |
| 16084 | uint64_t b0 = b & 0xffffffff; |
| 16085 | uint64_t b1 = b >> 32; |
| 16086 | |
| 16087 | uint64_t i0 = a0 * b0; |
| 16088 | uint64_t i1 = a0 * b1; |
| 16089 | uint64_t i2 = a1 * b0; |
| 16090 | uint64_t i3 = a1 * b1; |
| 16091 | |
| 16092 | uint64_t p0, p1; |
| 16093 | |
| 16094 | i2 += (i0 >> 32); |
| 16095 | i2 += i1; |
| 16096 | if (i2 < i1) { /* overflow */ |
| 16097 | i3 += 0x100000000; |
| 16098 | } |
| 16099 | |
| 16100 | p0 = (i0 & 0xffffffff) | (i2 << 32); |
| 16101 | p1 = i3 + (i2 >> 32); |
| 16102 | |
| 16103 | *r0 += p0; |
| 16104 | *r1 += (p1 + (*r0 < p0)); |
| 16105 | *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); |
| 16106 | #else |
| 16107 | mg_uecc_dword_t p = (mg_uecc_dword_t) a * b; |
| 16108 | mg_uecc_dword_t r01 = ((mg_uecc_dword_t) (*r1) << MG_UECC_WORD_BITS) | *r0; |
| 16109 | r01 += p; |
| 16110 | *r2 += (r01 < p); |
| 16111 | *r1 = (mg_uecc_word_t) (r01 >> MG_UECC_WORD_BITS); |
| 16112 | *r0 = (mg_uecc_word_t) r01; |
| 16113 | #endif |
| 16114 | } |
| 16115 | #endif /* muladd needed */ |
| 16116 | |
| 16117 | #if !asm_mult |
| 16118 | MG_UECC_VLI_API void mg_uecc_vli_mult(mg_uecc_word_t *result, |
| 16119 | const mg_uecc_word_t *left, |
| 16120 | const mg_uecc_word_t *right, |
| 16121 | wordcount_t num_words) { |
| 16122 | mg_uecc_word_t r0 = 0; |
| 16123 | mg_uecc_word_t r1 = 0; |
| 16124 | mg_uecc_word_t r2 = 0; |
| 16125 | wordcount_t i, k; |
| 16126 | |
| 16127 | /* Compute each digit of result in sequence, maintaining the carries. */ |
| 16128 | for (k = 0; k < num_words; ++k) { |
| 16129 | for (i = 0; i <= k; ++i) { |
| 16130 | muladd(left[i], right[k - i], &r0, &r1, &r2); |
| 16131 | } |
| 16132 | result[k] = r0; |
| 16133 | r0 = r1; |
| 16134 | r1 = r2; |
| 16135 | r2 = 0; |
| 16136 | } |
| 16137 | for (k = num_words; k < num_words * 2 - 1; ++k) { |
| 16138 | for (i = (wordcount_t) ((k + 1) - num_words); i < num_words; ++i) { |
| 16139 | muladd(left[i], right[k - i], &r0, &r1, &r2); |
| 16140 | } |
| 16141 | result[k] = r0; |
| 16142 | r0 = r1; |
| 16143 | r1 = r2; |
| 16144 | r2 = 0; |
| 16145 | } |
| 16146 | result[num_words * 2 - 1] = r0; |
| 16147 | } |
| 16148 | #endif /* !asm_mult */ |
| 16149 | |
| 16150 | #if MG_UECC_SQUARE_FUNC |
| 16151 | |
| 16152 | #if !asm_square |
| 16153 | static void mul2add(mg_uecc_word_t a, mg_uecc_word_t b, mg_uecc_word_t *r0, |
| 16154 | mg_uecc_word_t *r1, mg_uecc_word_t *r2) { |
| 16155 | #if MG_UECC_WORD_SIZE == 8 |
| 16156 | uint64_t a0 = a & 0xffffffffull; |
| 16157 | uint64_t a1 = a >> 32; |
| 16158 | uint64_t b0 = b & 0xffffffffull; |
| 16159 | uint64_t b1 = b >> 32; |
| 16160 | |
| 16161 | uint64_t i0 = a0 * b0; |
| 16162 | uint64_t i1 = a0 * b1; |
| 16163 | uint64_t i2 = a1 * b0; |
| 16164 | uint64_t i3 = a1 * b1; |
| 16165 | |
| 16166 | uint64_t p0, p1; |
| 16167 | |
| 16168 | i2 += (i0 >> 32); |
| 16169 | i2 += i1; |
| 16170 | if (i2 < i1) { /* overflow */ |
| 16171 | i3 += 0x100000000ull; |
| 16172 | } |
| 16173 | |
| 16174 | p0 = (i0 & 0xffffffffull) | (i2 << 32); |
| 16175 | p1 = i3 + (i2 >> 32); |
| 16176 | |
| 16177 | *r2 += (p1 >> 63); |
| 16178 | p1 = (p1 << 1) | (p0 >> 63); |
| 16179 | p0 <<= 1; |
| 16180 | |
| 16181 | *r0 += p0; |
| 16182 | *r1 += (p1 + (*r0 < p0)); |
| 16183 | *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); |
| 16184 | #else |
| 16185 | mg_uecc_dword_t p = (mg_uecc_dword_t) a * b; |
| 16186 | mg_uecc_dword_t r01 = ((mg_uecc_dword_t) (*r1) << MG_UECC_WORD_BITS) | *r0; |
| 16187 | *r2 += (p >> (MG_UECC_WORD_BITS * 2 - 1)); |
| 16188 | p *= 2; |
| 16189 | r01 += p; |
| 16190 | *r2 += (r01 < p); |
| 16191 | *r1 = r01 >> MG_UECC_WORD_BITS; |
| 16192 | *r0 = (mg_uecc_word_t) r01; |
| 16193 | #endif |
| 16194 | } |
| 16195 | |
| 16196 | MG_UECC_VLI_API void mg_uecc_vli_square(mg_uecc_word_t *result, |
| 16197 | const mg_uecc_word_t *left, |
| 16198 | wordcount_t num_words) { |
| 16199 | mg_uecc_word_t r0 = 0; |
| 16200 | mg_uecc_word_t r1 = 0; |
| 16201 | mg_uecc_word_t r2 = 0; |
| 16202 | |
| 16203 | wordcount_t i, k; |
| 16204 | |
| 16205 | for (k = 0; k < num_words * 2 - 1; ++k) { |
| 16206 | mg_uecc_word_t min = (k < num_words ? 0 : (k + 1) - num_words); |
| 16207 | for (i = min; i <= k && i <= k - i; ++i) { |
| 16208 | if (i < k - i) { |
| 16209 | mul2add(left[i], left[k - i], &r0, &r1, &r2); |
| 16210 | } else { |
| 16211 | muladd(left[i], left[k - i], &r0, &r1, &r2); |
| 16212 | } |
| 16213 | } |
| 16214 | result[k] = r0; |
| 16215 | r0 = r1; |
| 16216 | r1 = r2; |
| 16217 | r2 = 0; |
| 16218 | } |
| 16219 | |
| 16220 | result[num_words * 2 - 1] = r0; |
| 16221 | } |
| 16222 | #endif /* !asm_square */ |
| 16223 | |
| 16224 | #else /* MG_UECC_SQUARE_FUNC */ |
| 16225 | |
| 16226 | #if MG_UECC_ENABLE_VLI_API |
| 16227 | MG_UECC_VLI_API void mg_uecc_vli_square(mg_uecc_word_t *result, |
| 16228 | const mg_uecc_word_t *left, |
| 16229 | wordcount_t num_words) { |
| 16230 | mg_uecc_vli_mult(result, left, left, num_words); |
| 16231 | } |
| 16232 | #endif /* MG_UECC_ENABLE_VLI_API */ |
| 16233 | |
| 16234 | #endif /* MG_UECC_SQUARE_FUNC */ |
| 16235 | |
| 16236 | /* Computes result = (left + right) % mod. |
| 16237 | Assumes that left < mod and right < mod, and that result does not overlap |
| 16238 | mod. */ |
| 16239 | MG_UECC_VLI_API void mg_uecc_vli_modAdd(mg_uecc_word_t *result, |
| 16240 | const mg_uecc_word_t *left, |
| 16241 | const mg_uecc_word_t *right, |
| 16242 | const mg_uecc_word_t *mod, |
| 16243 | wordcount_t num_words) { |
| 16244 | mg_uecc_word_t carry = mg_uecc_vli_add(result, left, right, num_words); |
| 16245 | if (carry || mg_uecc_vli_cmp_unsafe(mod, result, num_words) != 1) { |
| 16246 | /* result > mod (result = mod + remainder), so subtract mod to get |
| 16247 | * remainder. */ |
| 16248 | mg_uecc_vli_sub(result, result, mod, num_words); |
| 16249 | } |
| 16250 | } |
| 16251 | |
| 16252 | /* Computes result = (left - right) % mod. |
| 16253 | Assumes that left < mod and right < mod, and that result does not overlap |
| 16254 | mod. */ |
| 16255 | MG_UECC_VLI_API void mg_uecc_vli_modSub(mg_uecc_word_t *result, |
| 16256 | const mg_uecc_word_t *left, |
| 16257 | const mg_uecc_word_t *right, |
| 16258 | const mg_uecc_word_t *mod, |
| 16259 | wordcount_t num_words) { |
| 16260 | mg_uecc_word_t l_borrow = mg_uecc_vli_sub(result, left, right, num_words); |
| 16261 | if (l_borrow) { |
| 16262 | /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, |
| 16263 | we can get the correct result from result + mod (with overflow). */ |
| 16264 | mg_uecc_vli_add(result, result, mod, num_words); |
| 16265 | } |
| 16266 | } |
| 16267 | |
| 16268 | /* Computes result = product % mod, where product is 2N words long. */ |
| 16269 | /* Currently only designed to work for curve_p or curve_n. */ |
| 16270 | MG_UECC_VLI_API void mg_uecc_vli_mmod(mg_uecc_word_t *result, |
| 16271 | mg_uecc_word_t *product, |
| 16272 | const mg_uecc_word_t *mod, |
| 16273 | wordcount_t num_words) { |
| 16274 | mg_uecc_word_t mod_multiple[2 * MG_UECC_MAX_WORDS]; |
| 16275 | mg_uecc_word_t tmp[2 * MG_UECC_MAX_WORDS]; |
| 16276 | mg_uecc_word_t *v[2] = {tmp, product}; |
| 16277 | mg_uecc_word_t index; |
| 16278 | |
| 16279 | /* Shift mod so its highest set bit is at the maximum position. */ |
| 16280 | bitcount_t shift = (bitcount_t) ((num_words * 2 * MG_UECC_WORD_BITS) - |
| 16281 | mg_uecc_vli_numBits(mod, num_words)); |
| 16282 | wordcount_t word_shift = (wordcount_t) (shift / MG_UECC_WORD_BITS); |
| 16283 | wordcount_t bit_shift = (wordcount_t) (shift % MG_UECC_WORD_BITS); |
| 16284 | mg_uecc_word_t carry = 0; |
| 16285 | mg_uecc_vli_clear(mod_multiple, word_shift); |
| 16286 | if (bit_shift > 0) { |
| 16287 | for (index = 0; index < (mg_uecc_word_t) num_words; ++index) { |
| 16288 | mod_multiple[(mg_uecc_word_t) word_shift + index] = |
| 16289 | (mg_uecc_word_t) (mod[index] << bit_shift) | carry; |
| 16290 | carry = mod[index] >> (MG_UECC_WORD_BITS - bit_shift); |
| 16291 | } |
| 16292 | } else { |
| 16293 | mg_uecc_vli_set(mod_multiple + word_shift, mod, num_words); |
| 16294 | } |
| 16295 | |
| 16296 | for (index = 1; shift >= 0; --shift) { |
| 16297 | mg_uecc_word_t borrow = 0; |
| 16298 | wordcount_t i; |
| 16299 | for (i = 0; i < num_words * 2; ++i) { |
| 16300 | mg_uecc_word_t diff = v[index][i] - mod_multiple[i] - borrow; |
| 16301 | if (diff != v[index][i]) { |
| 16302 | borrow = (diff > v[index][i]); |
| 16303 | } |
| 16304 | v[1 - index][i] = diff; |
| 16305 | } |
| 16306 | index = !(index ^ borrow); /* Swap the index if there was no borrow */ |
| 16307 | mg_uecc_vli_rshift1(mod_multiple, num_words); |
| 16308 | mod_multiple[num_words - 1] |= mod_multiple[num_words] |
| 16309 | << (MG_UECC_WORD_BITS - 1); |
| 16310 | mg_uecc_vli_rshift1(mod_multiple + num_words, num_words); |
| 16311 | } |
| 16312 | mg_uecc_vli_set(result, v[index], num_words); |
| 16313 | } |
| 16314 | |
| 16315 | /* Computes result = (left * right) % mod. */ |
| 16316 | MG_UECC_VLI_API void mg_uecc_vli_modMult(mg_uecc_word_t *result, |
| 16317 | const mg_uecc_word_t *left, |
| 16318 | const mg_uecc_word_t *right, |
| 16319 | const mg_uecc_word_t *mod, |
| 16320 | wordcount_t num_words) { |
| 16321 | mg_uecc_word_t product[2 * MG_UECC_MAX_WORDS]; |
| 16322 | mg_uecc_vli_mult(product, left, right, num_words); |
| 16323 | mg_uecc_vli_mmod(result, product, mod, num_words); |
| 16324 | } |
| 16325 | |
| 16326 | MG_UECC_VLI_API void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result, |
| 16327 | const mg_uecc_word_t *left, |
| 16328 | const mg_uecc_word_t *right, |
| 16329 | MG_UECC_Curve curve) { |
| 16330 | mg_uecc_word_t product[2 * MG_UECC_MAX_WORDS]; |
| 16331 | mg_uecc_vli_mult(product, left, right, curve->num_words); |
| 16332 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16333 | curve->mmod_fast(result, product); |
| 16334 | #else |
| 16335 | mg_uecc_vli_mmod(result, product, curve->p, curve->num_words); |
| 16336 | #endif |
| 16337 | } |
| 16338 | |
| 16339 | #if MG_UECC_SQUARE_FUNC |
| 16340 | |
| 16341 | #if MG_UECC_ENABLE_VLI_API |
| 16342 | /* Computes result = left^2 % mod. */ |
| 16343 | MG_UECC_VLI_API void mg_uecc_vli_modSquare(mg_uecc_word_t *result, |
| 16344 | const mg_uecc_word_t *left, |
| 16345 | const mg_uecc_word_t *mod, |
| 16346 | wordcount_t num_words) { |
| 16347 | mg_uecc_word_t product[2 * MG_UECC_MAX_WORDS]; |
| 16348 | mg_uecc_vli_square(product, left, num_words); |
| 16349 | mg_uecc_vli_mmod(result, product, mod, num_words); |
| 16350 | } |
| 16351 | #endif /* MG_UECC_ENABLE_VLI_API */ |
| 16352 | |
| 16353 | MG_UECC_VLI_API void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result, |
| 16354 | const mg_uecc_word_t *left, |
| 16355 | MG_UECC_Curve curve) { |
| 16356 | mg_uecc_word_t product[2 * MG_UECC_MAX_WORDS]; |
| 16357 | mg_uecc_vli_square(product, left, curve->num_words); |
| 16358 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16359 | curve->mmod_fast(result, product); |
| 16360 | #else |
| 16361 | mg_uecc_vli_mmod(result, product, curve->p, curve->num_words); |
| 16362 | #endif |
| 16363 | } |
| 16364 | |
| 16365 | #else /* MG_UECC_SQUARE_FUNC */ |
| 16366 | |
| 16367 | #if MG_UECC_ENABLE_VLI_API |
| 16368 | MG_UECC_VLI_API void mg_uecc_vli_modSquare(mg_uecc_word_t *result, |
| 16369 | const mg_uecc_word_t *left, |
| 16370 | const mg_uecc_word_t *mod, |
| 16371 | wordcount_t num_words) { |
| 16372 | mg_uecc_vli_modMult(result, left, left, mod, num_words); |
| 16373 | } |
| 16374 | #endif /* MG_UECC_ENABLE_VLI_API */ |
| 16375 | |
| 16376 | MG_UECC_VLI_API void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result, |
| 16377 | const mg_uecc_word_t *left, |
| 16378 | MG_UECC_Curve curve) { |
| 16379 | mg_uecc_vli_modMult_fast(result, left, left, curve); |
| 16380 | } |
| 16381 | |
| 16382 | #endif /* MG_UECC_SQUARE_FUNC */ |
| 16383 | |
| 16384 | #define EVEN(vli) (!(vli[0] & 1)) |
| 16385 | static void vli_modInv_update(mg_uecc_word_t *uv, const mg_uecc_word_t *mod, |
| 16386 | wordcount_t num_words) { |
| 16387 | mg_uecc_word_t carry = 0; |
| 16388 | if (!EVEN(uv)) { |
| 16389 | carry = mg_uecc_vli_add(uv, uv, mod, num_words); |
| 16390 | } |
| 16391 | mg_uecc_vli_rshift1(uv, num_words); |
| 16392 | if (carry) { |
| 16393 | uv[num_words - 1] |= HIGH_BIT_SET; |
| 16394 | } |
| 16395 | } |
| 16396 | |
| 16397 | /* Computes result = (1 / input) % mod. All VLIs are the same size. |
| 16398 | See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */ |
| 16399 | MG_UECC_VLI_API void mg_uecc_vli_modInv(mg_uecc_word_t *result, |
| 16400 | const mg_uecc_word_t *input, |
| 16401 | const mg_uecc_word_t *mod, |
| 16402 | wordcount_t num_words) { |
| 16403 | mg_uecc_word_t a[MG_UECC_MAX_WORDS], b[MG_UECC_MAX_WORDS], |
| 16404 | u[MG_UECC_MAX_WORDS], v[MG_UECC_MAX_WORDS]; |
| 16405 | cmpresult_t cmpResult; |
| 16406 | |
| 16407 | if (mg_uecc_vli_isZero(input, num_words)) { |
| 16408 | mg_uecc_vli_clear(result, num_words); |
| 16409 | return; |
| 16410 | } |
| 16411 | |
| 16412 | mg_uecc_vli_set(a, input, num_words); |
| 16413 | mg_uecc_vli_set(b, mod, num_words); |
| 16414 | mg_uecc_vli_clear(u, num_words); |
| 16415 | u[0] = 1; |
| 16416 | mg_uecc_vli_clear(v, num_words); |
| 16417 | while ((cmpResult = mg_uecc_vli_cmp_unsafe(a, b, num_words)) != 0) { |
| 16418 | if (EVEN(a)) { |
| 16419 | mg_uecc_vli_rshift1(a, num_words); |
| 16420 | vli_modInv_update(u, mod, num_words); |
| 16421 | } else if (EVEN(b)) { |
| 16422 | mg_uecc_vli_rshift1(b, num_words); |
| 16423 | vli_modInv_update(v, mod, num_words); |
| 16424 | } else if (cmpResult > 0) { |
| 16425 | mg_uecc_vli_sub(a, a, b, num_words); |
| 16426 | mg_uecc_vli_rshift1(a, num_words); |
| 16427 | if (mg_uecc_vli_cmp_unsafe(u, v, num_words) < 0) { |
| 16428 | mg_uecc_vli_add(u, u, mod, num_words); |
| 16429 | } |
| 16430 | mg_uecc_vli_sub(u, u, v, num_words); |
| 16431 | vli_modInv_update(u, mod, num_words); |
| 16432 | } else { |
| 16433 | mg_uecc_vli_sub(b, b, a, num_words); |
| 16434 | mg_uecc_vli_rshift1(b, num_words); |
| 16435 | if (mg_uecc_vli_cmp_unsafe(v, u, num_words) < 0) { |
| 16436 | mg_uecc_vli_add(v, v, mod, num_words); |
| 16437 | } |
| 16438 | mg_uecc_vli_sub(v, v, u, num_words); |
| 16439 | vli_modInv_update(v, mod, num_words); |
| 16440 | } |
| 16441 | } |
| 16442 | mg_uecc_vli_set(result, u, num_words); |
| 16443 | } |
| 16444 | |
| 16445 | /* ------ Point operations ------ */ |
| 16446 | |
| 16447 | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ |
| 16448 | |
| 16449 | #ifndef _UECC_CURVE_SPECIFIC_H_ |
| 16450 | #define _UECC_CURVE_SPECIFIC_H_ |
| 16451 | |
| 16452 | #define num_bytes_secp160r1 20 |
| 16453 | #define num_bytes_secp192r1 24 |
| 16454 | #define num_bytes_secp224r1 28 |
| 16455 | #define num_bytes_secp256r1 32 |
| 16456 | #define num_bytes_secp256k1 32 |
| 16457 | |
| 16458 | #if (MG_UECC_WORD_SIZE == 1) |
| 16459 | |
| 16460 | #define num_words_secp160r1 20 |
| 16461 | #define num_words_secp192r1 24 |
| 16462 | #define num_words_secp224r1 28 |
| 16463 | #define num_words_secp256r1 32 |
| 16464 | #define num_words_secp256k1 32 |
| 16465 | |
| 16466 | #define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) \ |
| 16467 | 0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h |
| 16468 | #define BYTES_TO_WORDS_4(a, b, c, d) 0x##a, 0x##b, 0x##c, 0x##d |
| 16469 | |
| 16470 | #elif (MG_UECC_WORD_SIZE == 4) |
| 16471 | |
| 16472 | #define num_words_secp160r1 5 |
| 16473 | #define num_words_secp192r1 6 |
| 16474 | #define num_words_secp224r1 7 |
| 16475 | #define num_words_secp256r1 8 |
| 16476 | #define num_words_secp256k1 8 |
| 16477 | |
| 16478 | #define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e |
| 16479 | #define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a |
| 16480 | |
| 16481 | #elif (MG_UECC_WORD_SIZE == 8) |
| 16482 | |
| 16483 | #define num_words_secp160r1 3 |
| 16484 | #define num_words_secp192r1 3 |
| 16485 | #define num_words_secp224r1 4 |
| 16486 | #define num_words_secp256r1 4 |
| 16487 | #define num_words_secp256k1 4 |
| 16488 | |
| 16489 | #define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##h##g##f##e##d##c##b##a##U |
| 16490 | #define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a##U |
| 16491 | |
| 16492 | #endif /* MG_UECC_WORD_SIZE */ |
| 16493 | |
| 16494 | #if MG_UECC_SUPPORTS_secp160r1 || MG_UECC_SUPPORTS_secp192r1 || \ |
| 16495 | MG_UECC_SUPPORTS_secp224r1 || MG_UECC_SUPPORTS_secp256r1 |
| 16496 | static void double_jacobian_default(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 16497 | mg_uecc_word_t *Z1, MG_UECC_Curve curve) { |
| 16498 | /* t1 = X, t2 = Y, t3 = Z */ |
| 16499 | mg_uecc_word_t t4[MG_UECC_MAX_WORDS]; |
| 16500 | mg_uecc_word_t t5[MG_UECC_MAX_WORDS]; |
| 16501 | wordcount_t num_words = curve->num_words; |
| 16502 | |
| 16503 | if (mg_uecc_vli_isZero(Z1, num_words)) { |
| 16504 | return; |
| 16505 | } |
| 16506 | |
| 16507 | mg_uecc_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ |
| 16508 | mg_uecc_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ |
| 16509 | mg_uecc_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ |
| 16510 | mg_uecc_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ |
| 16511 | mg_uecc_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ |
| 16512 | |
| 16513 | mg_uecc_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ |
| 16514 | mg_uecc_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ |
| 16515 | mg_uecc_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ |
| 16516 | mg_uecc_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ |
| 16517 | |
| 16518 | mg_uecc_vli_modAdd(Z1, X1, X1, curve->p, |
| 16519 | num_words); /* t3 = 2*(x1^2 - z1^4) */ |
| 16520 | mg_uecc_vli_modAdd(X1, X1, Z1, curve->p, |
| 16521 | num_words); /* t1 = 3*(x1^2 - z1^4) */ |
| 16522 | if (mg_uecc_vli_testBit(X1, 0)) { |
| 16523 | mg_uecc_word_t l_carry = mg_uecc_vli_add(X1, X1, curve->p, num_words); |
| 16524 | mg_uecc_vli_rshift1(X1, num_words); |
| 16525 | X1[num_words - 1] |= l_carry << (MG_UECC_WORD_BITS - 1); |
| 16526 | } else { |
| 16527 | mg_uecc_vli_rshift1(X1, num_words); |
| 16528 | } |
| 16529 | /* t1 = 3/2*(x1^2 - z1^4) = B */ |
| 16530 | |
| 16531 | mg_uecc_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ |
| 16532 | mg_uecc_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ |
| 16533 | mg_uecc_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ |
| 16534 | mg_uecc_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ |
| 16535 | mg_uecc_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ |
| 16536 | mg_uecc_vli_modSub(t4, X1, t4, curve->p, |
| 16537 | num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ |
| 16538 | |
| 16539 | mg_uecc_vli_set(X1, Z1, num_words); |
| 16540 | mg_uecc_vli_set(Z1, Y1, num_words); |
| 16541 | mg_uecc_vli_set(Y1, t4, num_words); |
| 16542 | } |
| 16543 | |
| 16544 | /* Computes result = x^3 + ax + b. result must not overlap x. */ |
| 16545 | static void x_side_default(mg_uecc_word_t *result, const mg_uecc_word_t *x, |
| 16546 | MG_UECC_Curve curve) { |
| 16547 | mg_uecc_word_t _3[MG_UECC_MAX_WORDS] = {3}; /* -a = 3 */ |
| 16548 | wordcount_t num_words = curve->num_words; |
| 16549 | |
| 16550 | mg_uecc_vli_modSquare_fast(result, x, curve); /* r = x^2 */ |
| 16551 | mg_uecc_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ |
| 16552 | mg_uecc_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ |
| 16553 | mg_uecc_vli_modAdd(result, result, curve->b, curve->p, |
| 16554 | num_words); /* r = x^3 - 3x + b */ |
| 16555 | } |
| 16556 | #endif /* MG_UECC_SUPPORTS_secp... */ |
| 16557 | |
| 16558 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 16559 | #if MG_UECC_SUPPORTS_secp160r1 || MG_UECC_SUPPORTS_secp192r1 || \ |
| 16560 | MG_UECC_SUPPORTS_secp256r1 || MG_UECC_SUPPORTS_secp256k1 |
| 16561 | /* Compute a = sqrt(a) (mod curve_p). */ |
| 16562 | static void mod_sqrt_default(mg_uecc_word_t *a, MG_UECC_Curve curve) { |
| 16563 | bitcount_t i; |
| 16564 | mg_uecc_word_t p1[MG_UECC_MAX_WORDS] = {1}; |
| 16565 | mg_uecc_word_t l_result[MG_UECC_MAX_WORDS] = {1}; |
| 16566 | wordcount_t num_words = curve->num_words; |
| 16567 | |
| 16568 | /* When curve->p == 3 (mod 4), we can compute |
| 16569 | sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */ |
| 16570 | mg_uecc_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ |
| 16571 | for (i = mg_uecc_vli_numBits(p1, num_words) - 1; i > 1; --i) { |
| 16572 | mg_uecc_vli_modSquare_fast(l_result, l_result, curve); |
| 16573 | if (mg_uecc_vli_testBit(p1, i)) { |
| 16574 | mg_uecc_vli_modMult_fast(l_result, l_result, a, curve); |
| 16575 | } |
| 16576 | } |
| 16577 | mg_uecc_vli_set(a, l_result, num_words); |
| 16578 | } |
| 16579 | #endif /* MG_UECC_SUPPORTS_secp... */ |
| 16580 | #endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */ |
| 16581 | |
| 16582 | #if MG_UECC_SUPPORTS_secp160r1 |
| 16583 | |
| 16584 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16585 | static void vli_mmod_fast_secp160r1(mg_uecc_word_t *result, |
| 16586 | mg_uecc_word_t *product); |
| 16587 | #endif |
| 16588 | |
| 16589 | static const struct MG_UECC_Curve_t curve_secp160r1 = { |
| 16590 | num_words_secp160r1, |
| 16591 | num_bytes_secp160r1, |
| 16592 | 161, /* num_n_bits */ |
| 16593 | {BYTES_TO_WORDS_8(FF, FF, FF, 7F, FF, FF, FF, FF), |
| 16594 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 16595 | BYTES_TO_WORDS_4(FF, FF, FF, FF)}, |
| 16596 | {BYTES_TO_WORDS_8(57, 22, 75, CA, D3, AE, 27, F9), |
| 16597 | BYTES_TO_WORDS_8(C8, F4, 01, 00, 00, 00, 00, 00), |
| 16598 | BYTES_TO_WORDS_8(00, 00, 00, 00, 01, 00, 00, 00)}, |
| 16599 | {BYTES_TO_WORDS_8(82, FC, CB, 13, B9, 8B, C3, 68), |
| 16600 | BYTES_TO_WORDS_8(89, 69, 64, 46, 28, 73, F5, 8E), |
| 16601 | BYTES_TO_WORDS_4(68, B5, 96, 4A), |
| 16602 | |
| 16603 | BYTES_TO_WORDS_8(32, FB, C5, 7A, 37, 51, 23, 04), |
| 16604 | BYTES_TO_WORDS_8(12, C9, DC, 59, 7D, 94, 68, 31), |
| 16605 | BYTES_TO_WORDS_4(55, 28, A6, 23)}, |
| 16606 | {BYTES_TO_WORDS_8(45, FA, 65, C5, AD, D4, D4, 81), |
| 16607 | BYTES_TO_WORDS_8(9F, F8, AC, 65, 8B, 7A, BD, 54), |
| 16608 | BYTES_TO_WORDS_4(FC, BE, 97, 1C)}, |
| 16609 | &double_jacobian_default, |
| 16610 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 16611 | &mod_sqrt_default, |
| 16612 | #endif |
| 16613 | &x_side_default, |
| 16614 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16615 | &vli_mmod_fast_secp160r1 |
| 16616 | #endif |
| 16617 | }; |
| 16618 | |
| 16619 | MG_UECC_Curve mg_uecc_secp160r1(void) { |
| 16620 | return &curve_secp160r1; |
| 16621 | } |
| 16622 | |
| 16623 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) |
| 16624 | /* Computes result = product % curve_p |
| 16625 | see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354 |
| 16626 | |
| 16627 | Note that this only works if log2(omega) < log2(p) / 2 */ |
| 16628 | static void omega_mult_secp160r1(mg_uecc_word_t *result, |
| 16629 | const mg_uecc_word_t *right); |
| 16630 | #if MG_UECC_WORD_SIZE == 8 |
| 16631 | static void vli_mmod_fast_secp160r1(mg_uecc_word_t *result, |
| 16632 | mg_uecc_word_t *product) { |
| 16633 | mg_uecc_word_t tmp[2 * num_words_secp160r1]; |
| 16634 | mg_uecc_word_t copy; |
| 16635 | |
| 16636 | mg_uecc_vli_clear(tmp, num_words_secp160r1); |
| 16637 | mg_uecc_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); |
| 16638 | |
| 16639 | omega_mult_secp160r1(tmp, |
| 16640 | product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */ |
| 16641 | |
| 16642 | product[num_words_secp160r1 - 1] &= 0xffffffff; |
| 16643 | copy = tmp[num_words_secp160r1 - 1]; |
| 16644 | tmp[num_words_secp160r1 - 1] &= 0xffffffff; |
| 16645 | mg_uecc_vli_add(result, product, tmp, |
| 16646 | num_words_secp160r1); /* (C, r) = r + q */ |
| 16647 | mg_uecc_vli_clear(product, num_words_secp160r1); |
| 16648 | tmp[num_words_secp160r1 - 1] = copy; |
| 16649 | omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */ |
| 16650 | mg_uecc_vli_add(result, result, product, |
| 16651 | num_words_secp160r1); /* (C1, r) = r + Rq*c */ |
| 16652 | |
| 16653 | while (mg_uecc_vli_cmp_unsafe(result, curve_secp160r1.p, |
| 16654 | num_words_secp160r1) > 0) { |
| 16655 | mg_uecc_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); |
| 16656 | } |
| 16657 | } |
| 16658 | |
| 16659 | static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) { |
| 16660 | uint32_t carry; |
| 16661 | unsigned i; |
| 16662 | |
| 16663 | /* Multiply by (2^31 + 1). */ |
| 16664 | carry = 0; |
| 16665 | for (i = 0; i < num_words_secp160r1; ++i) { |
| 16666 | uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32); |
| 16667 | result[i] = (tmp << 31) + tmp + carry; |
| 16668 | carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp)); |
| 16669 | } |
| 16670 | result[i] = carry; |
| 16671 | } |
| 16672 | #else |
| 16673 | static void vli_mmod_fast_secp160r1(mg_uecc_word_t *result, |
| 16674 | mg_uecc_word_t *product) { |
| 16675 | mg_uecc_word_t tmp[2 * num_words_secp160r1]; |
| 16676 | mg_uecc_word_t carry; |
| 16677 | |
| 16678 | mg_uecc_vli_clear(tmp, num_words_secp160r1); |
| 16679 | mg_uecc_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); |
| 16680 | |
| 16681 | omega_mult_secp160r1(tmp, |
| 16682 | product + num_words_secp160r1); /* (Rq, q) = q * c */ |
| 16683 | |
| 16684 | carry = mg_uecc_vli_add(result, product, tmp, |
| 16685 | num_words_secp160r1); /* (C, r) = r + q */ |
| 16686 | mg_uecc_vli_clear(product, num_words_secp160r1); |
| 16687 | omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */ |
| 16688 | carry += mg_uecc_vli_add(result, result, product, |
| 16689 | num_words_secp160r1); /* (C1, r) = r + Rq*c */ |
| 16690 | |
| 16691 | while (carry > 0) { |
| 16692 | --carry; |
| 16693 | mg_uecc_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); |
| 16694 | } |
| 16695 | if (mg_uecc_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > |
| 16696 | 0) { |
| 16697 | mg_uecc_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); |
| 16698 | } |
| 16699 | } |
| 16700 | #endif |
| 16701 | |
| 16702 | #if MG_UECC_WORD_SIZE == 1 |
| 16703 | static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) { |
| 16704 | uint8_t carry; |
| 16705 | uint8_t i; |
| 16706 | |
| 16707 | /* Multiply by (2^31 + 1). */ |
| 16708 | mg_uecc_vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */ |
| 16709 | mg_uecc_vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */ |
| 16710 | result[3] = right[0] << 7; /* get last bit from shift */ |
| 16711 | |
| 16712 | carry = mg_uecc_vli_add(result, result, right, |
| 16713 | num_words_secp160r1); /* 2^31 + 1 */ |
| 16714 | for (i = num_words_secp160r1; carry; ++i) { |
| 16715 | uint16_t sum = (uint16_t) result[i] + carry; |
| 16716 | result[i] = (uint8_t) sum; |
| 16717 | carry = sum >> 8; |
| 16718 | } |
| 16719 | } |
| 16720 | #elif MG_UECC_WORD_SIZE == 4 |
| 16721 | static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) { |
| 16722 | uint32_t carry; |
| 16723 | unsigned i; |
| 16724 | |
| 16725 | /* Multiply by (2^31 + 1). */ |
| 16726 | mg_uecc_vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */ |
| 16727 | mg_uecc_vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */ |
| 16728 | result[0] = right[0] << 31; /* get last bit from shift */ |
| 16729 | |
| 16730 | carry = mg_uecc_vli_add(result, result, right, |
| 16731 | num_words_secp160r1); /* 2^31 + 1 */ |
| 16732 | for (i = num_words_secp160r1; carry; ++i) { |
| 16733 | uint64_t sum = (uint64_t) result[i] + carry; |
| 16734 | result[i] = (uint32_t) sum; |
| 16735 | carry = sum >> 32; |
| 16736 | } |
| 16737 | } |
| 16738 | #endif /* MG_UECC_WORD_SIZE */ |
| 16739 | #endif /* (MG_UECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) */ |
| 16740 | |
| 16741 | #endif /* MG_UECC_SUPPORTS_secp160r1 */ |
| 16742 | |
| 16743 | #if MG_UECC_SUPPORTS_secp192r1 |
| 16744 | |
| 16745 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16746 | static void vli_mmod_fast_secp192r1(mg_uecc_word_t *result, |
| 16747 | mg_uecc_word_t *product); |
| 16748 | #endif |
| 16749 | |
| 16750 | static const struct MG_UECC_Curve_t curve_secp192r1 = { |
| 16751 | num_words_secp192r1, |
| 16752 | num_bytes_secp192r1, |
| 16753 | 192, /* num_n_bits */ |
| 16754 | {BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 16755 | BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), |
| 16756 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF)}, |
| 16757 | {BYTES_TO_WORDS_8(31, 28, D2, B4, B1, C9, 6B, 14), |
| 16758 | BYTES_TO_WORDS_8(36, F8, DE, 99, FF, FF, FF, FF), |
| 16759 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF)}, |
| 16760 | {BYTES_TO_WORDS_8(12, 10, FF, 82, FD, 0A, FF, F4), |
| 16761 | BYTES_TO_WORDS_8(00, 88, A1, 43, EB, 20, BF, 7C), |
| 16762 | BYTES_TO_WORDS_8(F6, 90, 30, B0, 0E, A8, 8D, 18), |
| 16763 | |
| 16764 | BYTES_TO_WORDS_8(11, 48, 79, 1E, A1, 77, F9, 73), |
| 16765 | BYTES_TO_WORDS_8(D5, CD, 24, 6B, ED, 11, 10, 63), |
| 16766 | BYTES_TO_WORDS_8(78, DA, C8, FF, 95, 2B, 19, 07)}, |
| 16767 | {BYTES_TO_WORDS_8(B1, B9, 46, C1, EC, DE, B8, FE), |
| 16768 | BYTES_TO_WORDS_8(49, 30, 24, 72, AB, E9, A7, 0F), |
| 16769 | BYTES_TO_WORDS_8(E7, 80, 9C, E5, 19, 05, 21, 64)}, |
| 16770 | &double_jacobian_default, |
| 16771 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 16772 | &mod_sqrt_default, |
| 16773 | #endif |
| 16774 | &x_side_default, |
| 16775 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16776 | &vli_mmod_fast_secp192r1 |
| 16777 | #endif |
| 16778 | }; |
| 16779 | |
| 16780 | MG_UECC_Curve mg_uecc_secp192r1(void) { |
| 16781 | return &curve_secp192r1; |
| 16782 | } |
| 16783 | |
| 16784 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16785 | /* Computes result = product % curve_p. |
| 16786 | See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf |
| 16787 | */ |
| 16788 | #if MG_UECC_WORD_SIZE == 1 |
| 16789 | static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) { |
| 16790 | uint8_t tmp[num_words_secp192r1]; |
| 16791 | uint8_t carry; |
| 16792 | |
| 16793 | mg_uecc_vli_set(result, product, num_words_secp192r1); |
| 16794 | |
| 16795 | mg_uecc_vli_set(tmp, &product[24], num_words_secp192r1); |
| 16796 | carry = mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16797 | |
| 16798 | tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; |
| 16799 | tmp[8] = product[24]; |
| 16800 | tmp[9] = product[25]; |
| 16801 | tmp[10] = product[26]; |
| 16802 | tmp[11] = product[27]; |
| 16803 | tmp[12] = product[28]; |
| 16804 | tmp[13] = product[29]; |
| 16805 | tmp[14] = product[30]; |
| 16806 | tmp[15] = product[31]; |
| 16807 | tmp[16] = product[32]; |
| 16808 | tmp[17] = product[33]; |
| 16809 | tmp[18] = product[34]; |
| 16810 | tmp[19] = product[35]; |
| 16811 | tmp[20] = product[36]; |
| 16812 | tmp[21] = product[37]; |
| 16813 | tmp[22] = product[38]; |
| 16814 | tmp[23] = product[39]; |
| 16815 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16816 | |
| 16817 | tmp[0] = tmp[8] = product[40]; |
| 16818 | tmp[1] = tmp[9] = product[41]; |
| 16819 | tmp[2] = tmp[10] = product[42]; |
| 16820 | tmp[3] = tmp[11] = product[43]; |
| 16821 | tmp[4] = tmp[12] = product[44]; |
| 16822 | tmp[5] = tmp[13] = product[45]; |
| 16823 | tmp[6] = tmp[14] = product[46]; |
| 16824 | tmp[7] = tmp[15] = product[47]; |
| 16825 | tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = |
| 16826 | tmp[23] = 0; |
| 16827 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16828 | |
| 16829 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp192r1.p, result, |
| 16830 | num_words_secp192r1) != 1) { |
| 16831 | carry -= |
| 16832 | mg_uecc_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); |
| 16833 | } |
| 16834 | } |
| 16835 | #elif MG_UECC_WORD_SIZE == 4 |
| 16836 | static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) { |
| 16837 | uint32_t tmp[num_words_secp192r1]; |
| 16838 | int carry; |
| 16839 | |
| 16840 | mg_uecc_vli_set(result, product, num_words_secp192r1); |
| 16841 | |
| 16842 | mg_uecc_vli_set(tmp, &product[6], num_words_secp192r1); |
| 16843 | carry = mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16844 | |
| 16845 | tmp[0] = tmp[1] = 0; |
| 16846 | tmp[2] = product[6]; |
| 16847 | tmp[3] = product[7]; |
| 16848 | tmp[4] = product[8]; |
| 16849 | tmp[5] = product[9]; |
| 16850 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16851 | |
| 16852 | tmp[0] = tmp[2] = product[10]; |
| 16853 | tmp[1] = tmp[3] = product[11]; |
| 16854 | tmp[4] = tmp[5] = 0; |
| 16855 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16856 | |
| 16857 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp192r1.p, result, |
| 16858 | num_words_secp192r1) != 1) { |
| 16859 | carry -= |
| 16860 | mg_uecc_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); |
| 16861 | } |
| 16862 | } |
| 16863 | #else |
| 16864 | static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) { |
| 16865 | uint64_t tmp[num_words_secp192r1]; |
| 16866 | int carry; |
| 16867 | |
| 16868 | mg_uecc_vli_set(result, product, num_words_secp192r1); |
| 16869 | |
| 16870 | mg_uecc_vli_set(tmp, &product[3], num_words_secp192r1); |
| 16871 | carry = (int) mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16872 | |
| 16873 | tmp[0] = 0; |
| 16874 | tmp[1] = product[3]; |
| 16875 | tmp[2] = product[4]; |
| 16876 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16877 | |
| 16878 | tmp[0] = tmp[1] = product[5]; |
| 16879 | tmp[2] = 0; |
| 16880 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp192r1); |
| 16881 | |
| 16882 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp192r1.p, result, |
| 16883 | num_words_secp192r1) != 1) { |
| 16884 | carry -= |
| 16885 | mg_uecc_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); |
| 16886 | } |
| 16887 | } |
| 16888 | #endif /* MG_UECC_WORD_SIZE */ |
| 16889 | #endif /* (MG_UECC_OPTIMIZATION_LEVEL > 0) */ |
| 16890 | |
| 16891 | #endif /* MG_UECC_SUPPORTS_secp192r1 */ |
| 16892 | |
| 16893 | #if MG_UECC_SUPPORTS_secp224r1 |
| 16894 | |
| 16895 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 16896 | static void mod_sqrt_secp224r1(mg_uecc_word_t *a, MG_UECC_Curve curve); |
| 16897 | #endif |
| 16898 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16899 | static void vli_mmod_fast_secp224r1(mg_uecc_word_t *result, |
| 16900 | mg_uecc_word_t *product); |
| 16901 | #endif |
| 16902 | |
| 16903 | static const struct MG_UECC_Curve_t curve_secp224r1 = { |
| 16904 | num_words_secp224r1, |
| 16905 | num_bytes_secp224r1, |
| 16906 | 224, /* num_n_bits */ |
| 16907 | {BYTES_TO_WORDS_8(01, 00, 00, 00, 00, 00, 00, 00), |
| 16908 | BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF), |
| 16909 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 16910 | BYTES_TO_WORDS_4(FF, FF, FF, FF)}, |
| 16911 | {BYTES_TO_WORDS_8(3D, 2A, 5C, 5C, 45, 29, DD, 13), |
| 16912 | BYTES_TO_WORDS_8(3E, F0, B8, E0, A2, 16, FF, FF), |
| 16913 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 16914 | BYTES_TO_WORDS_4(FF, FF, FF, FF)}, |
| 16915 | {BYTES_TO_WORDS_8(21, 1D, 5C, 11, D6, 80, 32, 34), |
| 16916 | BYTES_TO_WORDS_8(22, 11, C2, 56, D3, C1, 03, 4A), |
| 16917 | BYTES_TO_WORDS_8(B9, 90, 13, 32, 7F, BF, B4, 6B), |
| 16918 | BYTES_TO_WORDS_4(BD, 0C, 0E, B7), |
| 16919 | |
| 16920 | BYTES_TO_WORDS_8(34, 7E, 00, 85, 99, 81, D5, 44), |
| 16921 | BYTES_TO_WORDS_8(64, 47, 07, 5A, A0, 75, 43, CD), |
| 16922 | BYTES_TO_WORDS_8(E6, DF, 22, 4C, FB, 23, F7, B5), |
| 16923 | BYTES_TO_WORDS_4(88, 63, 37, BD)}, |
| 16924 | {BYTES_TO_WORDS_8(B4, FF, 55, 23, 43, 39, 0B, 27), |
| 16925 | BYTES_TO_WORDS_8(BA, D8, BF, D7, B7, B0, 44, 50), |
| 16926 | BYTES_TO_WORDS_8(56, 32, 41, F5, AB, B3, 04, 0C), |
| 16927 | BYTES_TO_WORDS_4(85, 0A, 05, B4)}, |
| 16928 | &double_jacobian_default, |
| 16929 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 16930 | &mod_sqrt_secp224r1, |
| 16931 | #endif |
| 16932 | &x_side_default, |
| 16933 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 16934 | &vli_mmod_fast_secp224r1 |
| 16935 | #endif |
| 16936 | }; |
| 16937 | |
| 16938 | MG_UECC_Curve mg_uecc_secp224r1(void) { |
| 16939 | return &curve_secp224r1; |
| 16940 | } |
| 16941 | |
| 16942 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 16943 | /* Routine 3.2.4 RS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 16944 | static void mod_sqrt_secp224r1_rs(mg_uecc_word_t *d1, mg_uecc_word_t *e1, |
| 16945 | mg_uecc_word_t *f1, const mg_uecc_word_t *d0, |
| 16946 | const mg_uecc_word_t *e0, |
| 16947 | const mg_uecc_word_t *f0) { |
| 16948 | mg_uecc_word_t t[num_words_secp224r1]; |
| 16949 | |
| 16950 | mg_uecc_vli_modSquare_fast(t, d0, &curve_secp224r1); /* t <-- d0 ^ 2 */ |
| 16951 | mg_uecc_vli_modMult_fast(e1, d0, e0, &curve_secp224r1); /* e1 <-- d0 * e0 */ |
| 16952 | mg_uecc_vli_modAdd(d1, t, f0, curve_secp224r1.p, |
| 16953 | num_words_secp224r1); /* d1 <-- t + f0 */ |
| 16954 | mg_uecc_vli_modAdd(e1, e1, e1, curve_secp224r1.p, |
| 16955 | num_words_secp224r1); /* e1 <-- e1 + e1 */ |
| 16956 | mg_uecc_vli_modMult_fast(f1, t, f0, &curve_secp224r1); /* f1 <-- t * f0 */ |
| 16957 | mg_uecc_vli_modAdd(f1, f1, f1, curve_secp224r1.p, |
| 16958 | num_words_secp224r1); /* f1 <-- f1 + f1 */ |
| 16959 | mg_uecc_vli_modAdd(f1, f1, f1, curve_secp224r1.p, |
| 16960 | num_words_secp224r1); /* f1 <-- f1 + f1 */ |
| 16961 | } |
| 16962 | |
| 16963 | /* Routine 3.2.5 RSS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 16964 | static void mod_sqrt_secp224r1_rss(mg_uecc_word_t *d1, mg_uecc_word_t *e1, |
| 16965 | mg_uecc_word_t *f1, const mg_uecc_word_t *d0, |
| 16966 | const mg_uecc_word_t *e0, |
| 16967 | const mg_uecc_word_t *f0, |
| 16968 | const bitcount_t j) { |
| 16969 | bitcount_t i; |
| 16970 | |
| 16971 | mg_uecc_vli_set(d1, d0, num_words_secp224r1); /* d1 <-- d0 */ |
| 16972 | mg_uecc_vli_set(e1, e0, num_words_secp224r1); /* e1 <-- e0 */ |
| 16973 | mg_uecc_vli_set(f1, f0, num_words_secp224r1); /* f1 <-- f0 */ |
| 16974 | for (i = 1; i <= j; i++) { |
| 16975 | mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */ |
| 16976 | } |
| 16977 | } |
| 16978 | |
| 16979 | /* Routine 3.2.6 RM; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 16980 | static void mod_sqrt_secp224r1_rm(mg_uecc_word_t *d2, mg_uecc_word_t *e2, |
| 16981 | mg_uecc_word_t *f2, const mg_uecc_word_t *c, |
| 16982 | const mg_uecc_word_t *d0, |
| 16983 | const mg_uecc_word_t *e0, |
| 16984 | const mg_uecc_word_t *d1, |
| 16985 | const mg_uecc_word_t *e1) { |
| 16986 | mg_uecc_word_t t1[num_words_secp224r1]; |
| 16987 | mg_uecc_word_t t2[num_words_secp224r1]; |
| 16988 | |
| 16989 | mg_uecc_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */ |
| 16990 | mg_uecc_vli_modMult_fast(t1, t1, c, &curve_secp224r1); /* t1 <-- t1 * c */ |
| 16991 | /* t1 <-- p - t1 */ |
| 16992 | mg_uecc_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, |
| 16993 | num_words_secp224r1); |
| 16994 | mg_uecc_vli_modMult_fast(t2, d0, d1, &curve_secp224r1); /* t2 <-- d0 * d1 */ |
| 16995 | mg_uecc_vli_modAdd(t2, t2, t1, curve_secp224r1.p, |
| 16996 | num_words_secp224r1); /* t2 <-- t2 + t1 */ |
| 16997 | mg_uecc_vli_modMult_fast(t1, d0, e1, &curve_secp224r1); /* t1 <-- d0 * e1 */ |
| 16998 | mg_uecc_vli_modMult_fast(e2, d1, e0, &curve_secp224r1); /* e2 <-- d1 * e0 */ |
| 16999 | mg_uecc_vli_modAdd(e2, e2, t1, curve_secp224r1.p, |
| 17000 | num_words_secp224r1); /* e2 <-- e2 + t1 */ |
| 17001 | mg_uecc_vli_modSquare_fast(f2, e2, &curve_secp224r1); /* f2 <-- e2^2 */ |
| 17002 | mg_uecc_vli_modMult_fast(f2, f2, c, &curve_secp224r1); /* f2 <-- f2 * c */ |
| 17003 | /* f2 <-- p - f2 */ |
| 17004 | mg_uecc_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, |
| 17005 | num_words_secp224r1); |
| 17006 | mg_uecc_vli_set(d2, t2, num_words_secp224r1); /* d2 <-- t2 */ |
| 17007 | } |
| 17008 | |
| 17009 | /* Routine 3.2.7 RP; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 17010 | static void mod_sqrt_secp224r1_rp(mg_uecc_word_t *d1, mg_uecc_word_t *e1, |
| 17011 | mg_uecc_word_t *f1, const mg_uecc_word_t *c, |
| 17012 | const mg_uecc_word_t *r) { |
| 17013 | wordcount_t i; |
| 17014 | wordcount_t pow2i = 1; |
| 17015 | mg_uecc_word_t d0[num_words_secp224r1]; |
| 17016 | mg_uecc_word_t e0[num_words_secp224r1] = {1}; /* e0 <-- 1 */ |
| 17017 | mg_uecc_word_t f0[num_words_secp224r1]; |
| 17018 | |
| 17019 | mg_uecc_vli_set(d0, r, num_words_secp224r1); /* d0 <-- r */ |
| 17020 | /* f0 <-- p - c */ |
| 17021 | mg_uecc_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, |
| 17022 | num_words_secp224r1); |
| 17023 | for (i = 0; i <= 6; i++) { |
| 17024 | mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, |
| 17025 | pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */ |
| 17026 | mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, |
| 17027 | e0); /* RM (d1,e1,f1,c,d1,e1,d0,e0) */ |
| 17028 | mg_uecc_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ |
| 17029 | mg_uecc_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ |
| 17030 | mg_uecc_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ |
| 17031 | pow2i *= 2; |
| 17032 | } |
| 17033 | } |
| 17034 | |
| 17035 | /* Compute a = sqrt(a) (mod curve_p). */ |
| 17036 | /* Routine 3.2.8 mp_mod_sqrt_224; from |
| 17037 | * http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 17038 | static void mod_sqrt_secp224r1(mg_uecc_word_t *a, MG_UECC_Curve curve) { |
| 17039 | (void) curve; |
| 17040 | bitcount_t i; |
| 17041 | mg_uecc_word_t e1[num_words_secp224r1]; |
| 17042 | mg_uecc_word_t f1[num_words_secp224r1]; |
| 17043 | mg_uecc_word_t d0[num_words_secp224r1]; |
| 17044 | mg_uecc_word_t e0[num_words_secp224r1]; |
| 17045 | mg_uecc_word_t f0[num_words_secp224r1]; |
| 17046 | mg_uecc_word_t d1[num_words_secp224r1]; |
| 17047 | |
| 17048 | /* s = a; using constant instead of random value */ |
| 17049 | mod_sqrt_secp224r1_rp(d0, e0, f0, a, a); /* RP (d0, e0, f0, c, s) */ |
| 17050 | mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, |
| 17051 | f0); /* RS (d1, e1, f1, d0, e0, f0) */ |
| 17052 | for (i = 1; i <= 95; i++) { |
| 17053 | mg_uecc_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ |
| 17054 | mg_uecc_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ |
| 17055 | mg_uecc_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ |
| 17056 | mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, |
| 17057 | f0); /* RS (d1, e1, f1, d0, e0, f0) */ |
| 17058 | if (mg_uecc_vli_isZero(d1, num_words_secp224r1)) { /* if d1 == 0 */ |
| 17059 | break; |
| 17060 | } |
| 17061 | } |
| 17062 | mg_uecc_vli_modInv(f1, e0, curve_secp224r1.p, |
| 17063 | num_words_secp224r1); /* f1 <-- 1 / e0 */ |
| 17064 | mg_uecc_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */ |
| 17065 | } |
| 17066 | #endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */ |
| 17067 | |
| 17068 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 17069 | /* Computes result = product % curve_p |
| 17070 | from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 17071 | #if MG_UECC_WORD_SIZE == 1 |
| 17072 | static void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) { |
| 17073 | uint8_t tmp[num_words_secp224r1]; |
| 17074 | int8_t carry; |
| 17075 | |
| 17076 | /* t */ |
| 17077 | mg_uecc_vli_set(result, product, num_words_secp224r1); |
| 17078 | |
| 17079 | /* s1 */ |
| 17080 | tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; |
| 17081 | tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; |
| 17082 | tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; |
| 17083 | tmp[12] = product[28]; |
| 17084 | tmp[13] = product[29]; |
| 17085 | tmp[14] = product[30]; |
| 17086 | tmp[15] = product[31]; |
| 17087 | tmp[16] = product[32]; |
| 17088 | tmp[17] = product[33]; |
| 17089 | tmp[18] = product[34]; |
| 17090 | tmp[19] = product[35]; |
| 17091 | tmp[20] = product[36]; |
| 17092 | tmp[21] = product[37]; |
| 17093 | tmp[22] = product[38]; |
| 17094 | tmp[23] = product[39]; |
| 17095 | tmp[24] = product[40]; |
| 17096 | tmp[25] = product[41]; |
| 17097 | tmp[26] = product[42]; |
| 17098 | tmp[27] = product[43]; |
| 17099 | carry = mg_uecc_vli_add(result, result, tmp, num_words_secp224r1); |
| 17100 | |
| 17101 | /* s2 */ |
| 17102 | tmp[12] = product[44]; |
| 17103 | tmp[13] = product[45]; |
| 17104 | tmp[14] = product[46]; |
| 17105 | tmp[15] = product[47]; |
| 17106 | tmp[16] = product[48]; |
| 17107 | tmp[17] = product[49]; |
| 17108 | tmp[18] = product[50]; |
| 17109 | tmp[19] = product[51]; |
| 17110 | tmp[20] = product[52]; |
| 17111 | tmp[21] = product[53]; |
| 17112 | tmp[22] = product[54]; |
| 17113 | tmp[23] = product[55]; |
| 17114 | tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; |
| 17115 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp224r1); |
| 17116 | |
| 17117 | /* d1 */ |
| 17118 | tmp[0] = product[28]; |
| 17119 | tmp[1] = product[29]; |
| 17120 | tmp[2] = product[30]; |
| 17121 | tmp[3] = product[31]; |
| 17122 | tmp[4] = product[32]; |
| 17123 | tmp[5] = product[33]; |
| 17124 | tmp[6] = product[34]; |
| 17125 | tmp[7] = product[35]; |
| 17126 | tmp[8] = product[36]; |
| 17127 | tmp[9] = product[37]; |
| 17128 | tmp[10] = product[38]; |
| 17129 | tmp[11] = product[39]; |
| 17130 | tmp[12] = product[40]; |
| 17131 | tmp[13] = product[41]; |
| 17132 | tmp[14] = product[42]; |
| 17133 | tmp[15] = product[43]; |
| 17134 | tmp[16] = product[44]; |
| 17135 | tmp[17] = product[45]; |
| 17136 | tmp[18] = product[46]; |
| 17137 | tmp[19] = product[47]; |
| 17138 | tmp[20] = product[48]; |
| 17139 | tmp[21] = product[49]; |
| 17140 | tmp[22] = product[50]; |
| 17141 | tmp[23] = product[51]; |
| 17142 | tmp[24] = product[52]; |
| 17143 | tmp[25] = product[53]; |
| 17144 | tmp[26] = product[54]; |
| 17145 | tmp[27] = product[55]; |
| 17146 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp224r1); |
| 17147 | |
| 17148 | /* d2 */ |
| 17149 | tmp[0] = product[44]; |
| 17150 | tmp[1] = product[45]; |
| 17151 | tmp[2] = product[46]; |
| 17152 | tmp[3] = product[47]; |
| 17153 | tmp[4] = product[48]; |
| 17154 | tmp[5] = product[49]; |
| 17155 | tmp[6] = product[50]; |
| 17156 | tmp[7] = product[51]; |
| 17157 | tmp[8] = product[52]; |
| 17158 | tmp[9] = product[53]; |
| 17159 | tmp[10] = product[54]; |
| 17160 | tmp[11] = product[55]; |
| 17161 | tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; |
| 17162 | tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; |
| 17163 | tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; |
| 17164 | tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; |
| 17165 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp224r1); |
| 17166 | |
| 17167 | if (carry < 0) { |
| 17168 | do { |
| 17169 | carry += mg_uecc_vli_add(result, result, curve_secp224r1.p, |
| 17170 | num_words_secp224r1); |
| 17171 | } while (carry < 0); |
| 17172 | } else { |
| 17173 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp224r1.p, result, |
| 17174 | num_words_secp224r1) != 1) { |
| 17175 | carry -= mg_uecc_vli_sub(result, result, curve_secp224r1.p, |
| 17176 | num_words_secp224r1); |
| 17177 | } |
| 17178 | } |
| 17179 | } |
| 17180 | #elif MG_UECC_WORD_SIZE == 4 |
| 17181 | static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product) { |
| 17182 | uint32_t tmp[num_words_secp224r1]; |
| 17183 | int carry; |
| 17184 | |
| 17185 | /* t */ |
| 17186 | mg_uecc_vli_set(result, product, num_words_secp224r1); |
| 17187 | |
| 17188 | /* s1 */ |
| 17189 | tmp[0] = tmp[1] = tmp[2] = 0; |
| 17190 | tmp[3] = product[7]; |
| 17191 | tmp[4] = product[8]; |
| 17192 | tmp[5] = product[9]; |
| 17193 | tmp[6] = product[10]; |
| 17194 | carry = mg_uecc_vli_add(result, result, tmp, num_words_secp224r1); |
| 17195 | |
| 17196 | /* s2 */ |
| 17197 | tmp[3] = product[11]; |
| 17198 | tmp[4] = product[12]; |
| 17199 | tmp[5] = product[13]; |
| 17200 | tmp[6] = 0; |
| 17201 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp224r1); |
| 17202 | |
| 17203 | /* d1 */ |
| 17204 | tmp[0] = product[7]; |
| 17205 | tmp[1] = product[8]; |
| 17206 | tmp[2] = product[9]; |
| 17207 | tmp[3] = product[10]; |
| 17208 | tmp[4] = product[11]; |
| 17209 | tmp[5] = product[12]; |
| 17210 | tmp[6] = product[13]; |
| 17211 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp224r1); |
| 17212 | |
| 17213 | /* d2 */ |
| 17214 | tmp[0] = product[11]; |
| 17215 | tmp[1] = product[12]; |
| 17216 | tmp[2] = product[13]; |
| 17217 | tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0; |
| 17218 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp224r1); |
| 17219 | |
| 17220 | if (carry < 0) { |
| 17221 | do { |
| 17222 | carry += mg_uecc_vli_add(result, result, curve_secp224r1.p, |
| 17223 | num_words_secp224r1); |
| 17224 | } while (carry < 0); |
| 17225 | } else { |
| 17226 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp224r1.p, result, |
| 17227 | num_words_secp224r1) != 1) { |
| 17228 | carry -= mg_uecc_vli_sub(result, result, curve_secp224r1.p, |
| 17229 | num_words_secp224r1); |
| 17230 | } |
| 17231 | } |
| 17232 | } |
| 17233 | #else |
| 17234 | static void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product) { |
| 17235 | uint64_t tmp[num_words_secp224r1]; |
| 17236 | int carry = 0; |
| 17237 | |
| 17238 | /* t */ |
| 17239 | mg_uecc_vli_set(result, product, num_words_secp224r1); |
| 17240 | result[num_words_secp224r1 - 1] &= 0xffffffff; |
| 17241 | |
| 17242 | /* s1 */ |
| 17243 | tmp[0] = 0; |
| 17244 | tmp[1] = product[3] & 0xffffffff00000000ull; |
| 17245 | tmp[2] = product[4]; |
| 17246 | tmp[3] = product[5] & 0xffffffff; |
| 17247 | mg_uecc_vli_add(result, result, tmp, num_words_secp224r1); |
| 17248 | |
| 17249 | /* s2 */ |
| 17250 | tmp[1] = product[5] & 0xffffffff00000000ull; |
| 17251 | tmp[2] = product[6]; |
| 17252 | tmp[3] = 0; |
| 17253 | mg_uecc_vli_add(result, result, tmp, num_words_secp224r1); |
| 17254 | |
| 17255 | /* d1 */ |
| 17256 | tmp[0] = (product[3] >> 32) | (product[4] << 32); |
| 17257 | tmp[1] = (product[4] >> 32) | (product[5] << 32); |
| 17258 | tmp[2] = (product[5] >> 32) | (product[6] << 32); |
| 17259 | tmp[3] = product[6] >> 32; |
| 17260 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp224r1); |
| 17261 | |
| 17262 | /* d2 */ |
| 17263 | tmp[0] = (product[5] >> 32) | (product[6] << 32); |
| 17264 | tmp[1] = product[6] >> 32; |
| 17265 | tmp[2] = tmp[3] = 0; |
| 17266 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp224r1); |
| 17267 | |
| 17268 | if (carry < 0) { |
| 17269 | do { |
| 17270 | carry += mg_uecc_vli_add(result, result, curve_secp224r1.p, |
| 17271 | num_words_secp224r1); |
| 17272 | } while (carry < 0); |
| 17273 | } else { |
| 17274 | while (mg_uecc_vli_cmp_unsafe(curve_secp224r1.p, result, |
| 17275 | num_words_secp224r1) != 1) { |
| 17276 | mg_uecc_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); |
| 17277 | } |
| 17278 | } |
| 17279 | } |
| 17280 | #endif /* MG_UECC_WORD_SIZE */ |
| 17281 | #endif /* (MG_UECC_OPTIMIZATION_LEVEL > 0) */ |
| 17282 | |
| 17283 | #endif /* MG_UECC_SUPPORTS_secp224r1 */ |
| 17284 | |
| 17285 | #if MG_UECC_SUPPORTS_secp256r1 |
| 17286 | |
| 17287 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 17288 | static void vli_mmod_fast_secp256r1(mg_uecc_word_t *result, |
| 17289 | mg_uecc_word_t *product); |
| 17290 | #endif |
| 17291 | |
| 17292 | static const struct MG_UECC_Curve_t curve_secp256r1 = { |
| 17293 | num_words_secp256r1, |
| 17294 | num_bytes_secp256r1, |
| 17295 | 256, /* num_n_bits */ |
| 17296 | {BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 17297 | BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00), |
| 17298 | BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), |
| 17299 | BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)}, |
| 17300 | {BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3), |
| 17301 | BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC), |
| 17302 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 17303 | BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)}, |
| 17304 | {BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4), |
| 17305 | BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77), |
| 17306 | BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8), |
| 17307 | BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B), |
| 17308 | |
| 17309 | BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB), |
| 17310 | BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B), |
| 17311 | BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E), |
| 17312 | BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)}, |
| 17313 | {BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B), |
| 17314 | BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65), |
| 17315 | BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3), |
| 17316 | BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)}, |
| 17317 | &double_jacobian_default, |
| 17318 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 17319 | &mod_sqrt_default, |
| 17320 | #endif |
| 17321 | &x_side_default, |
| 17322 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 17323 | &vli_mmod_fast_secp256r1 |
| 17324 | #endif |
| 17325 | }; |
| 17326 | |
| 17327 | MG_UECC_Curve mg_uecc_secp256r1(void) { |
| 17328 | return &curve_secp256r1; |
| 17329 | } |
| 17330 | |
| 17331 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) |
| 17332 | /* Computes result = product % curve_p |
| 17333 | from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
| 17334 | #if MG_UECC_WORD_SIZE == 1 |
| 17335 | static void vli_mmod_fast_secp256r1(uint8_t *result, uint8_t *product) { |
| 17336 | uint8_t tmp[num_words_secp256r1]; |
| 17337 | int8_t carry; |
| 17338 | |
| 17339 | /* t */ |
| 17340 | mg_uecc_vli_set(result, product, num_words_secp256r1); |
| 17341 | |
| 17342 | /* s1 */ |
| 17343 | tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; |
| 17344 | tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; |
| 17345 | tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; |
| 17346 | tmp[12] = product[44]; |
| 17347 | tmp[13] = product[45]; |
| 17348 | tmp[14] = product[46]; |
| 17349 | tmp[15] = product[47]; |
| 17350 | tmp[16] = product[48]; |
| 17351 | tmp[17] = product[49]; |
| 17352 | tmp[18] = product[50]; |
| 17353 | tmp[19] = product[51]; |
| 17354 | tmp[20] = product[52]; |
| 17355 | tmp[21] = product[53]; |
| 17356 | tmp[22] = product[54]; |
| 17357 | tmp[23] = product[55]; |
| 17358 | tmp[24] = product[56]; |
| 17359 | tmp[25] = product[57]; |
| 17360 | tmp[26] = product[58]; |
| 17361 | tmp[27] = product[59]; |
| 17362 | tmp[28] = product[60]; |
| 17363 | tmp[29] = product[61]; |
| 17364 | tmp[30] = product[62]; |
| 17365 | tmp[31] = product[63]; |
| 17366 | carry = mg_uecc_vli_add(tmp, tmp, tmp, num_words_secp256r1); |
| 17367 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17368 | |
| 17369 | /* s2 */ |
| 17370 | tmp[12] = product[48]; |
| 17371 | tmp[13] = product[49]; |
| 17372 | tmp[14] = product[50]; |
| 17373 | tmp[15] = product[51]; |
| 17374 | tmp[16] = product[52]; |
| 17375 | tmp[17] = product[53]; |
| 17376 | tmp[18] = product[54]; |
| 17377 | tmp[19] = product[55]; |
| 17378 | tmp[20] = product[56]; |
| 17379 | tmp[21] = product[57]; |
| 17380 | tmp[22] = product[58]; |
| 17381 | tmp[23] = product[59]; |
| 17382 | tmp[24] = product[60]; |
| 17383 | tmp[25] = product[61]; |
| 17384 | tmp[26] = product[62]; |
| 17385 | tmp[27] = product[63]; |
| 17386 | tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0; |
| 17387 | carry += mg_uecc_vli_add(tmp, tmp, tmp, num_words_secp256r1); |
| 17388 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17389 | |
| 17390 | /* s3 */ |
| 17391 | tmp[0] = product[32]; |
| 17392 | tmp[1] = product[33]; |
| 17393 | tmp[2] = product[34]; |
| 17394 | tmp[3] = product[35]; |
| 17395 | tmp[4] = product[36]; |
| 17396 | tmp[5] = product[37]; |
| 17397 | tmp[6] = product[38]; |
| 17398 | tmp[7] = product[39]; |
| 17399 | tmp[8] = product[40]; |
| 17400 | tmp[9] = product[41]; |
| 17401 | tmp[10] = product[42]; |
| 17402 | tmp[11] = product[43]; |
| 17403 | tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; |
| 17404 | tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; |
| 17405 | tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; |
| 17406 | tmp[24] = product[56]; |
| 17407 | tmp[25] = product[57]; |
| 17408 | tmp[26] = product[58]; |
| 17409 | tmp[27] = product[59]; |
| 17410 | tmp[28] = product[60]; |
| 17411 | tmp[29] = product[61]; |
| 17412 | tmp[30] = product[62]; |
| 17413 | tmp[31] = product[63]; |
| 17414 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17415 | |
| 17416 | /* s4 */ |
| 17417 | tmp[0] = product[36]; |
| 17418 | tmp[1] = product[37]; |
| 17419 | tmp[2] = product[38]; |
| 17420 | tmp[3] = product[39]; |
| 17421 | tmp[4] = product[40]; |
| 17422 | tmp[5] = product[41]; |
| 17423 | tmp[6] = product[42]; |
| 17424 | tmp[7] = product[43]; |
| 17425 | tmp[8] = product[44]; |
| 17426 | tmp[9] = product[45]; |
| 17427 | tmp[10] = product[46]; |
| 17428 | tmp[11] = product[47]; |
| 17429 | tmp[12] = product[52]; |
| 17430 | tmp[13] = product[53]; |
| 17431 | tmp[14] = product[54]; |
| 17432 | tmp[15] = product[55]; |
| 17433 | tmp[16] = product[56]; |
| 17434 | tmp[17] = product[57]; |
| 17435 | tmp[18] = product[58]; |
| 17436 | tmp[19] = product[59]; |
| 17437 | tmp[20] = product[60]; |
| 17438 | tmp[21] = product[61]; |
| 17439 | tmp[22] = product[62]; |
| 17440 | tmp[23] = product[63]; |
| 17441 | tmp[24] = product[52]; |
| 17442 | tmp[25] = product[53]; |
| 17443 | tmp[26] = product[54]; |
| 17444 | tmp[27] = product[55]; |
| 17445 | tmp[28] = product[32]; |
| 17446 | tmp[29] = product[33]; |
| 17447 | tmp[30] = product[34]; |
| 17448 | tmp[31] = product[35]; |
| 17449 | carry += mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17450 | |
| 17451 | /* d1 */ |
| 17452 | tmp[0] = product[44]; |
| 17453 | tmp[1] = product[45]; |
| 17454 | tmp[2] = product[46]; |
| 17455 | tmp[3] = product[47]; |
| 17456 | tmp[4] = product[48]; |
| 17457 | tmp[5] = product[49]; |
| 17458 | tmp[6] = product[50]; |
| 17459 | tmp[7] = product[51]; |
| 17460 | tmp[8] = product[52]; |
| 17461 | tmp[9] = product[53]; |
| 17462 | tmp[10] = product[54]; |
| 17463 | tmp[11] = product[55]; |
| 17464 | tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; |
| 17465 | tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; |
| 17466 | tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; |
| 17467 | tmp[24] = product[32]; |
| 17468 | tmp[25] = product[33]; |
| 17469 | tmp[26] = product[34]; |
| 17470 | tmp[27] = product[35]; |
| 17471 | tmp[28] = product[40]; |
| 17472 | tmp[29] = product[41]; |
| 17473 | tmp[30] = product[42]; |
| 17474 | tmp[31] = product[43]; |
| 17475 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17476 | |
| 17477 | /* d2 */ |
| 17478 | tmp[0] = product[48]; |
| 17479 | tmp[1] = product[49]; |
| 17480 | tmp[2] = product[50]; |
| 17481 | tmp[3] = product[51]; |
| 17482 | tmp[4] = product[52]; |
| 17483 | tmp[5] = product[53]; |
| 17484 | tmp[6] = product[54]; |
| 17485 | tmp[7] = product[55]; |
| 17486 | tmp[8] = product[56]; |
| 17487 | tmp[9] = product[57]; |
| 17488 | tmp[10] = product[58]; |
| 17489 | tmp[11] = product[59]; |
| 17490 | tmp[12] = product[60]; |
| 17491 | tmp[13] = product[61]; |
| 17492 | tmp[14] = product[62]; |
| 17493 | tmp[15] = product[63]; |
| 17494 | tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; |
| 17495 | tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; |
| 17496 | tmp[24] = product[36]; |
| 17497 | tmp[25] = product[37]; |
| 17498 | tmp[26] = product[38]; |
| 17499 | tmp[27] = product[39]; |
| 17500 | tmp[28] = product[44]; |
| 17501 | tmp[29] = product[45]; |
| 17502 | tmp[30] = product[46]; |
| 17503 | tmp[31] = product[47]; |
| 17504 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17505 | |
| 17506 | /* d3 */ |
| 17507 | tmp[0] = product[52]; |
| 17508 | tmp[1] = product[53]; |
| 17509 | tmp[2] = product[54]; |
| 17510 | tmp[3] = product[55]; |
| 17511 | tmp[4] = product[56]; |
| 17512 | tmp[5] = product[57]; |
| 17513 | tmp[6] = product[58]; |
| 17514 | tmp[7] = product[59]; |
| 17515 | tmp[8] = product[60]; |
| 17516 | tmp[9] = product[61]; |
| 17517 | tmp[10] = product[62]; |
| 17518 | tmp[11] = product[63]; |
| 17519 | tmp[12] = product[32]; |
| 17520 | tmp[13] = product[33]; |
| 17521 | tmp[14] = product[34]; |
| 17522 | tmp[15] = product[35]; |
| 17523 | tmp[16] = product[36]; |
| 17524 | tmp[17] = product[37]; |
| 17525 | tmp[18] = product[38]; |
| 17526 | tmp[19] = product[39]; |
| 17527 | tmp[20] = product[40]; |
| 17528 | tmp[21] = product[41]; |
| 17529 | tmp[22] = product[42]; |
| 17530 | tmp[23] = product[43]; |
| 17531 | tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; |
| 17532 | tmp[28] = product[48]; |
| 17533 | tmp[29] = product[49]; |
| 17534 | tmp[30] = product[50]; |
| 17535 | tmp[31] = product[51]; |
| 17536 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17537 | |
| 17538 | /* d4 */ |
| 17539 | tmp[0] = product[56]; |
| 17540 | tmp[1] = product[57]; |
| 17541 | tmp[2] = product[58]; |
| 17542 | tmp[3] = product[59]; |
| 17543 | tmp[4] = product[60]; |
| 17544 | tmp[5] = product[61]; |
| 17545 | tmp[6] = product[62]; |
| 17546 | tmp[7] = product[63]; |
| 17547 | tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; |
| 17548 | tmp[12] = product[36]; |
| 17549 | tmp[13] = product[37]; |
| 17550 | tmp[14] = product[38]; |
| 17551 | tmp[15] = product[39]; |
| 17552 | tmp[16] = product[40]; |
| 17553 | tmp[17] = product[41]; |
| 17554 | tmp[18] = product[42]; |
| 17555 | tmp[19] = product[43]; |
| 17556 | tmp[20] = product[44]; |
| 17557 | tmp[21] = product[45]; |
| 17558 | tmp[22] = product[46]; |
| 17559 | tmp[23] = product[47]; |
| 17560 | tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; |
| 17561 | tmp[28] = product[52]; |
| 17562 | tmp[29] = product[53]; |
| 17563 | tmp[30] = product[54]; |
| 17564 | tmp[31] = product[55]; |
| 17565 | carry -= mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17566 | |
| 17567 | if (carry < 0) { |
| 17568 | do { |
| 17569 | carry += mg_uecc_vli_add(result, result, curve_secp256r1.p, |
| 17570 | num_words_secp256r1); |
| 17571 | } while (carry < 0); |
| 17572 | } else { |
| 17573 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp256r1.p, result, |
| 17574 | num_words_secp256r1) != 1) { |
| 17575 | carry -= mg_uecc_vli_sub(result, result, curve_secp256r1.p, |
| 17576 | num_words_secp256r1); |
| 17577 | } |
| 17578 | } |
| 17579 | } |
| 17580 | #elif MG_UECC_WORD_SIZE == 4 |
| 17581 | static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { |
| 17582 | uint32_t tmp[num_words_secp256r1]; |
| 17583 | int carry; |
| 17584 | |
| 17585 | /* t */ |
| 17586 | mg_uecc_vli_set(result, product, num_words_secp256r1); |
| 17587 | |
| 17588 | /* s1 */ |
| 17589 | tmp[0] = tmp[1] = tmp[2] = 0; |
| 17590 | tmp[3] = product[11]; |
| 17591 | tmp[4] = product[12]; |
| 17592 | tmp[5] = product[13]; |
| 17593 | tmp[6] = product[14]; |
| 17594 | tmp[7] = product[15]; |
| 17595 | carry = (int) mg_uecc_vli_add(tmp, tmp, tmp, num_words_secp256r1); |
| 17596 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17597 | |
| 17598 | /* s2 */ |
| 17599 | tmp[3] = product[12]; |
| 17600 | tmp[4] = product[13]; |
| 17601 | tmp[5] = product[14]; |
| 17602 | tmp[6] = product[15]; |
| 17603 | tmp[7] = 0; |
| 17604 | carry += (int) mg_uecc_vli_add(tmp, tmp, tmp, num_words_secp256r1); |
| 17605 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17606 | |
| 17607 | /* s3 */ |
| 17608 | tmp[0] = product[8]; |
| 17609 | tmp[1] = product[9]; |
| 17610 | tmp[2] = product[10]; |
| 17611 | tmp[3] = tmp[4] = tmp[5] = 0; |
| 17612 | tmp[6] = product[14]; |
| 17613 | tmp[7] = product[15]; |
| 17614 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17615 | |
| 17616 | /* s4 */ |
| 17617 | tmp[0] = product[9]; |
| 17618 | tmp[1] = product[10]; |
| 17619 | tmp[2] = product[11]; |
| 17620 | tmp[3] = product[13]; |
| 17621 | tmp[4] = product[14]; |
| 17622 | tmp[5] = product[15]; |
| 17623 | tmp[6] = product[13]; |
| 17624 | tmp[7] = product[8]; |
| 17625 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17626 | |
| 17627 | /* d1 */ |
| 17628 | tmp[0] = product[11]; |
| 17629 | tmp[1] = product[12]; |
| 17630 | tmp[2] = product[13]; |
| 17631 | tmp[3] = tmp[4] = tmp[5] = 0; |
| 17632 | tmp[6] = product[8]; |
| 17633 | tmp[7] = product[10]; |
| 17634 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17635 | |
| 17636 | /* d2 */ |
| 17637 | tmp[0] = product[12]; |
| 17638 | tmp[1] = product[13]; |
| 17639 | tmp[2] = product[14]; |
| 17640 | tmp[3] = product[15]; |
| 17641 | tmp[4] = tmp[5] = 0; |
| 17642 | tmp[6] = product[9]; |
| 17643 | tmp[7] = product[11]; |
| 17644 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17645 | |
| 17646 | /* d3 */ |
| 17647 | tmp[0] = product[13]; |
| 17648 | tmp[1] = product[14]; |
| 17649 | tmp[2] = product[15]; |
| 17650 | tmp[3] = product[8]; |
| 17651 | tmp[4] = product[9]; |
| 17652 | tmp[5] = product[10]; |
| 17653 | tmp[6] = 0; |
| 17654 | tmp[7] = product[12]; |
| 17655 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17656 | |
| 17657 | /* d4 */ |
| 17658 | tmp[0] = product[14]; |
| 17659 | tmp[1] = product[15]; |
| 17660 | tmp[2] = 0; |
| 17661 | tmp[3] = product[9]; |
| 17662 | tmp[4] = product[10]; |
| 17663 | tmp[5] = product[11]; |
| 17664 | tmp[6] = 0; |
| 17665 | tmp[7] = product[13]; |
| 17666 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17667 | |
| 17668 | if (carry < 0) { |
| 17669 | do { |
| 17670 | carry += (int) mg_uecc_vli_add(result, result, curve_secp256r1.p, |
| 17671 | num_words_secp256r1); |
| 17672 | } while (carry < 0); |
| 17673 | } else { |
| 17674 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp256r1.p, result, |
| 17675 | num_words_secp256r1) != 1) { |
| 17676 | carry -= (int) mg_uecc_vli_sub(result, result, curve_secp256r1.p, |
| 17677 | num_words_secp256r1); |
| 17678 | } |
| 17679 | } |
| 17680 | } |
| 17681 | #else |
| 17682 | static void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) { |
| 17683 | uint64_t tmp[num_words_secp256r1]; |
| 17684 | int carry; |
| 17685 | |
| 17686 | /* t */ |
| 17687 | mg_uecc_vli_set(result, product, num_words_secp256r1); |
| 17688 | |
| 17689 | /* s1 */ |
| 17690 | tmp[0] = 0; |
| 17691 | tmp[1] = product[5] & 0xffffffff00000000U; |
| 17692 | tmp[2] = product[6]; |
| 17693 | tmp[3] = product[7]; |
| 17694 | carry = (int) mg_uecc_vli_add(tmp, tmp, tmp, num_words_secp256r1); |
| 17695 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17696 | |
| 17697 | /* s2 */ |
| 17698 | tmp[1] = product[6] << 32; |
| 17699 | tmp[2] = (product[6] >> 32) | (product[7] << 32); |
| 17700 | tmp[3] = product[7] >> 32; |
| 17701 | carry += (int) mg_uecc_vli_add(tmp, tmp, tmp, num_words_secp256r1); |
| 17702 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17703 | |
| 17704 | /* s3 */ |
| 17705 | tmp[0] = product[4]; |
| 17706 | tmp[1] = product[5] & 0xffffffff; |
| 17707 | tmp[2] = 0; |
| 17708 | tmp[3] = product[7]; |
| 17709 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17710 | |
| 17711 | /* s4 */ |
| 17712 | tmp[0] = (product[4] >> 32) | (product[5] << 32); |
| 17713 | tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000U); |
| 17714 | tmp[2] = product[7]; |
| 17715 | tmp[3] = (product[6] >> 32) | (product[4] << 32); |
| 17716 | carry += (int) mg_uecc_vli_add(result, result, tmp, num_words_secp256r1); |
| 17717 | |
| 17718 | /* d1 */ |
| 17719 | tmp[0] = (product[5] >> 32) | (product[6] << 32); |
| 17720 | tmp[1] = (product[6] >> 32); |
| 17721 | tmp[2] = 0; |
| 17722 | tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); |
| 17723 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17724 | |
| 17725 | /* d2 */ |
| 17726 | tmp[0] = product[6]; |
| 17727 | tmp[1] = product[7]; |
| 17728 | tmp[2] = 0; |
| 17729 | tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000); |
| 17730 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17731 | |
| 17732 | /* d3 */ |
| 17733 | tmp[0] = (product[6] >> 32) | (product[7] << 32); |
| 17734 | tmp[1] = (product[7] >> 32) | (product[4] << 32); |
| 17735 | tmp[2] = (product[4] >> 32) | (product[5] << 32); |
| 17736 | tmp[3] = (product[6] << 32); |
| 17737 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17738 | |
| 17739 | /* d4 */ |
| 17740 | tmp[0] = product[7]; |
| 17741 | tmp[1] = product[4] & 0xffffffff00000000U; |
| 17742 | tmp[2] = product[5]; |
| 17743 | tmp[3] = product[6] & 0xffffffff00000000U; |
| 17744 | carry -= (int) mg_uecc_vli_sub(result, result, tmp, num_words_secp256r1); |
| 17745 | |
| 17746 | if (carry < 0) { |
| 17747 | do { |
| 17748 | carry += (int) mg_uecc_vli_add(result, result, curve_secp256r1.p, |
| 17749 | num_words_secp256r1); |
| 17750 | } while (carry < 0); |
| 17751 | } else { |
| 17752 | while (carry || mg_uecc_vli_cmp_unsafe(curve_secp256r1.p, result, |
| 17753 | num_words_secp256r1) != 1) { |
| 17754 | carry -= (int) mg_uecc_vli_sub(result, result, curve_secp256r1.p, |
| 17755 | num_words_secp256r1); |
| 17756 | } |
| 17757 | } |
| 17758 | } |
| 17759 | #endif /* MG_UECC_WORD_SIZE */ |
| 17760 | #endif /* (MG_UECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) */ |
| 17761 | |
| 17762 | #endif /* MG_UECC_SUPPORTS_secp256r1 */ |
| 17763 | |
| 17764 | #if MG_UECC_SUPPORTS_secp256k1 |
| 17765 | |
| 17766 | static void double_jacobian_secp256k1(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 17767 | mg_uecc_word_t *Z1, MG_UECC_Curve curve); |
| 17768 | static void x_side_secp256k1(mg_uecc_word_t *result, const mg_uecc_word_t *x, |
| 17769 | MG_UECC_Curve curve); |
| 17770 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 17771 | static void vli_mmod_fast_secp256k1(mg_uecc_word_t *result, |
| 17772 | mg_uecc_word_t *product); |
| 17773 | #endif |
| 17774 | |
| 17775 | static const struct MG_UECC_Curve_t curve_secp256k1 = { |
| 17776 | num_words_secp256k1, |
| 17777 | num_bytes_secp256k1, |
| 17778 | 256, /* num_n_bits */ |
| 17779 | {BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF), |
| 17780 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 17781 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), |
| 17782 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF)}, |
| 17783 | {BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF), |
| 17784 | BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA), |
| 17785 | BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), |
| 17786 | BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF)}, |
| 17787 | {BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59), |
| 17788 | BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02), |
| 17789 | BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55), |
| 17790 | BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79), |
| 17791 | |
| 17792 | BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C), |
| 17793 | BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD), |
| 17794 | BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D), |
| 17795 | BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48)}, |
| 17796 | {BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00), |
| 17797 | BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), |
| 17798 | BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), |
| 17799 | BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00)}, |
| 17800 | &double_jacobian_secp256k1, |
| 17801 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 17802 | &mod_sqrt_default, |
| 17803 | #endif |
| 17804 | &x_side_secp256k1, |
| 17805 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 17806 | &vli_mmod_fast_secp256k1 |
| 17807 | #endif |
| 17808 | }; |
| 17809 | |
| 17810 | MG_UECC_Curve mg_uecc_secp256k1(void) { |
| 17811 | return &curve_secp256k1; |
| 17812 | } |
| 17813 | |
| 17814 | /* Double in place */ |
| 17815 | static void double_jacobian_secp256k1(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 17816 | mg_uecc_word_t *Z1, MG_UECC_Curve curve) { |
| 17817 | /* t1 = X, t2 = Y, t3 = Z */ |
| 17818 | mg_uecc_word_t t4[num_words_secp256k1]; |
| 17819 | mg_uecc_word_t t5[num_words_secp256k1]; |
| 17820 | |
| 17821 | if (mg_uecc_vli_isZero(Z1, num_words_secp256k1)) { |
| 17822 | return; |
| 17823 | } |
| 17824 | |
| 17825 | mg_uecc_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ |
| 17826 | mg_uecc_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ |
| 17827 | mg_uecc_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ |
| 17828 | mg_uecc_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ |
| 17829 | mg_uecc_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ |
| 17830 | |
| 17831 | mg_uecc_vli_modAdd(Y1, X1, X1, curve->p, |
| 17832 | num_words_secp256k1); /* t2 = 2*x1^2 */ |
| 17833 | mg_uecc_vli_modAdd(Y1, Y1, X1, curve->p, |
| 17834 | num_words_secp256k1); /* t2 = 3*x1^2 */ |
| 17835 | if (mg_uecc_vli_testBit(Y1, 0)) { |
| 17836 | mg_uecc_word_t carry = |
| 17837 | mg_uecc_vli_add(Y1, Y1, curve->p, num_words_secp256k1); |
| 17838 | mg_uecc_vli_rshift1(Y1, num_words_secp256k1); |
| 17839 | Y1[num_words_secp256k1 - 1] |= carry << (MG_UECC_WORD_BITS - 1); |
| 17840 | } else { |
| 17841 | mg_uecc_vli_rshift1(Y1, num_words_secp256k1); |
| 17842 | } |
| 17843 | /* t2 = 3/2*(x1^2) = B */ |
| 17844 | |
| 17845 | mg_uecc_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ |
| 17846 | mg_uecc_vli_modSub(X1, X1, t4, curve->p, |
| 17847 | num_words_secp256k1); /* t1 = B^2 - A */ |
| 17848 | mg_uecc_vli_modSub(X1, X1, t4, curve->p, |
| 17849 | num_words_secp256k1); /* t1 = B^2 - 2A = x3 */ |
| 17850 | |
| 17851 | mg_uecc_vli_modSub(t4, t4, X1, curve->p, |
| 17852 | num_words_secp256k1); /* t4 = A - x3 */ |
| 17853 | mg_uecc_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ |
| 17854 | mg_uecc_vli_modSub(Y1, Y1, t5, curve->p, |
| 17855 | num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */ |
| 17856 | } |
| 17857 | |
| 17858 | /* Computes result = x^3 + b. result must not overlap x. */ |
| 17859 | static void x_side_secp256k1(mg_uecc_word_t *result, const mg_uecc_word_t *x, |
| 17860 | MG_UECC_Curve curve) { |
| 17861 | mg_uecc_vli_modSquare_fast(result, x, curve); /* r = x^2 */ |
| 17862 | mg_uecc_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ |
| 17863 | mg_uecc_vli_modAdd(result, result, curve->b, curve->p, |
| 17864 | num_words_secp256k1); /* r = x^3 + b */ |
| 17865 | } |
| 17866 | |
| 17867 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256k1) |
| 17868 | static void omega_mult_secp256k1(mg_uecc_word_t *result, |
| 17869 | const mg_uecc_word_t *right); |
| 17870 | static void vli_mmod_fast_secp256k1(mg_uecc_word_t *result, |
| 17871 | mg_uecc_word_t *product) { |
| 17872 | mg_uecc_word_t tmp[2 * num_words_secp256k1]; |
| 17873 | mg_uecc_word_t carry; |
| 17874 | |
| 17875 | mg_uecc_vli_clear(tmp, num_words_secp256k1); |
| 17876 | mg_uecc_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1); |
| 17877 | |
| 17878 | omega_mult_secp256k1(tmp, |
| 17879 | product + num_words_secp256k1); /* (Rq, q) = q * c */ |
| 17880 | |
| 17881 | carry = mg_uecc_vli_add(result, product, tmp, |
| 17882 | num_words_secp256k1); /* (C, r) = r + q */ |
| 17883 | mg_uecc_vli_clear(product, num_words_secp256k1); |
| 17884 | omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */ |
| 17885 | carry += mg_uecc_vli_add(result, result, product, |
| 17886 | num_words_secp256k1); /* (C1, r) = r + Rq*c */ |
| 17887 | |
| 17888 | while (carry > 0) { |
| 17889 | --carry; |
| 17890 | mg_uecc_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); |
| 17891 | } |
| 17892 | if (mg_uecc_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > |
| 17893 | 0) { |
| 17894 | mg_uecc_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); |
| 17895 | } |
| 17896 | } |
| 17897 | |
| 17898 | #if MG_UECC_WORD_SIZE == 1 |
| 17899 | static void omega_mult_secp256k1(uint8_t *result, const uint8_t *right) { |
| 17900 | /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ |
| 17901 | mg_uecc_word_t r0 = 0; |
| 17902 | mg_uecc_word_t r1 = 0; |
| 17903 | mg_uecc_word_t r2 = 0; |
| 17904 | wordcount_t k; |
| 17905 | |
| 17906 | /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ |
| 17907 | muladd(0xD1, right[0], &r0, &r1, &r2); |
| 17908 | result[0] = r0; |
| 17909 | r0 = r1; |
| 17910 | r1 = r2; |
| 17911 | /* r2 is still 0 */ |
| 17912 | |
| 17913 | for (k = 1; k < num_words_secp256k1; ++k) { |
| 17914 | muladd(0x03, right[k - 1], &r0, &r1, &r2); |
| 17915 | muladd(0xD1, right[k], &r0, &r1, &r2); |
| 17916 | result[k] = r0; |
| 17917 | r0 = r1; |
| 17918 | r1 = r2; |
| 17919 | r2 = 0; |
| 17920 | } |
| 17921 | muladd(0x03, right[num_words_secp256k1 - 1], &r0, &r1, &r2); |
| 17922 | result[num_words_secp256k1] = r0; |
| 17923 | result[num_words_secp256k1 + 1] = r1; |
| 17924 | /* add the 2^32 multiple */ |
| 17925 | result[4 + num_words_secp256k1] = |
| 17926 | mg_uecc_vli_add(result + 4, result + 4, right, num_words_secp256k1); |
| 17927 | } |
| 17928 | #elif MG_UECC_WORD_SIZE == 4 |
| 17929 | static void omega_mult_secp256k1(uint32_t *result, const uint32_t *right) { |
| 17930 | /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ |
| 17931 | uint32_t carry = 0; |
| 17932 | wordcount_t k; |
| 17933 | |
| 17934 | for (k = 0; k < num_words_secp256k1; ++k) { |
| 17935 | uint64_t p = (uint64_t) 0x3D1 * right[k] + carry; |
| 17936 | result[k] = (uint32_t) p; |
| 17937 | carry = p >> 32; |
| 17938 | } |
| 17939 | result[num_words_secp256k1] = carry; |
| 17940 | /* add the 2^32 multiple */ |
| 17941 | result[1 + num_words_secp256k1] = |
| 17942 | mg_uecc_vli_add(result + 1, result + 1, right, num_words_secp256k1); |
| 17943 | } |
| 17944 | #else |
| 17945 | static void omega_mult_secp256k1(uint64_t *result, const uint64_t *right) { |
| 17946 | mg_uecc_word_t r0 = 0; |
| 17947 | mg_uecc_word_t r1 = 0; |
| 17948 | mg_uecc_word_t r2 = 0; |
| 17949 | wordcount_t k; |
| 17950 | |
| 17951 | /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ |
| 17952 | for (k = 0; k < num_words_secp256k1; ++k) { |
| 17953 | muladd(0x1000003D1ull, right[k], &r0, &r1, &r2); |
| 17954 | result[k] = r0; |
| 17955 | r0 = r1; |
| 17956 | r1 = r2; |
| 17957 | r2 = 0; |
| 17958 | } |
| 17959 | result[num_words_secp256k1] = r0; |
| 17960 | } |
| 17961 | #endif /* MG_UECC_WORD_SIZE */ |
| 17962 | #endif /* (MG_UECC_OPTIMIZATION_LEVEL > 0 && && !asm_mmod_fast_secp256k1) */ |
| 17963 | |
| 17964 | #endif /* MG_UECC_SUPPORTS_secp256k1 */ |
| 17965 | |
| 17966 | #endif /* _UECC_CURVE_SPECIFIC_H_ */ |
| 17967 | |
| 17968 | /* Returns 1 if 'point' is the point at infinity, 0 otherwise. */ |
| 17969 | #define EccPoint_isZero(point, curve) \ |
| 17970 | mg_uecc_vli_isZero((point), (wordcount_t) ((curve)->num_words * 2)) |
| 17971 | |
| 17972 | /* Point multiplication algorithm using Montgomery's ladder with co-Z |
| 17973 | coordinates. From http://eprint.iacr.org/2011/338.pdf |
| 17974 | */ |
| 17975 | |
| 17976 | /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ |
| 17977 | static void apply_z(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 17978 | const mg_uecc_word_t *const Z, MG_UECC_Curve curve) { |
| 17979 | mg_uecc_word_t t1[MG_UECC_MAX_WORDS]; |
| 17980 | |
| 17981 | mg_uecc_vli_modSquare_fast(t1, Z, curve); /* z^2 */ |
| 17982 | mg_uecc_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ |
| 17983 | mg_uecc_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ |
| 17984 | mg_uecc_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ |
| 17985 | } |
| 17986 | |
| 17987 | /* P = (x1, y1) => 2P, (x2, y2) => P' */ |
| 17988 | static void XYcZ_initial_double(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 17989 | mg_uecc_word_t *X2, mg_uecc_word_t *Y2, |
| 17990 | const mg_uecc_word_t *const initial_Z, |
| 17991 | MG_UECC_Curve curve) { |
| 17992 | mg_uecc_word_t z[MG_UECC_MAX_WORDS]; |
| 17993 | wordcount_t num_words = curve->num_words; |
| 17994 | if (initial_Z) { |
| 17995 | mg_uecc_vli_set(z, initial_Z, num_words); |
| 17996 | } else { |
| 17997 | mg_uecc_vli_clear(z, num_words); |
| 17998 | z[0] = 1; |
| 17999 | } |
| 18000 | |
| 18001 | mg_uecc_vli_set(X2, X1, num_words); |
| 18002 | mg_uecc_vli_set(Y2, Y1, num_words); |
| 18003 | |
| 18004 | apply_z(X1, Y1, z, curve); |
| 18005 | curve->double_jacobian(X1, Y1, z, curve); |
| 18006 | apply_z(X2, Y2, z, curve); |
| 18007 | } |
| 18008 | |
| 18009 | /* Input P = (x1, y1, Z), Q = (x2, y2, Z) |
| 18010 | Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) |
| 18011 | or P => P', Q => P + Q |
| 18012 | */ |
| 18013 | static void XYcZ_add(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, mg_uecc_word_t *X2, |
| 18014 | mg_uecc_word_t *Y2, MG_UECC_Curve curve) { |
| 18015 | /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ |
| 18016 | mg_uecc_word_t t5[MG_UECC_MAX_WORDS] = {0}; |
| 18017 | wordcount_t num_words = curve->num_words; |
| 18018 | |
| 18019 | mg_uecc_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ |
| 18020 | mg_uecc_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ |
| 18021 | mg_uecc_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ |
| 18022 | mg_uecc_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ |
| 18023 | mg_uecc_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ |
| 18024 | mg_uecc_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ |
| 18025 | |
| 18026 | mg_uecc_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ |
| 18027 | mg_uecc_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ |
| 18028 | mg_uecc_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ |
| 18029 | mg_uecc_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ |
| 18030 | mg_uecc_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ |
| 18031 | mg_uecc_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ |
| 18032 | mg_uecc_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ |
| 18033 | |
| 18034 | mg_uecc_vli_set(X2, t5, num_words); |
| 18035 | } |
| 18036 | |
| 18037 | /* Input P = (x1, y1, Z), Q = (x2, y2, Z) |
| 18038 | Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) |
| 18039 | or P => P - Q, Q => P + Q |
| 18040 | */ |
| 18041 | static void XYcZ_addC(mg_uecc_word_t *X1, mg_uecc_word_t *Y1, |
| 18042 | mg_uecc_word_t *X2, mg_uecc_word_t *Y2, |
| 18043 | MG_UECC_Curve curve) { |
| 18044 | /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ |
| 18045 | mg_uecc_word_t t5[MG_UECC_MAX_WORDS] = {0}; |
| 18046 | mg_uecc_word_t t6[MG_UECC_MAX_WORDS]; |
| 18047 | mg_uecc_word_t t7[MG_UECC_MAX_WORDS]; |
| 18048 | wordcount_t num_words = curve->num_words; |
| 18049 | |
| 18050 | mg_uecc_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ |
| 18051 | mg_uecc_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ |
| 18052 | mg_uecc_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ |
| 18053 | mg_uecc_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ |
| 18054 | mg_uecc_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ |
| 18055 | mg_uecc_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ |
| 18056 | |
| 18057 | mg_uecc_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ |
| 18058 | mg_uecc_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ |
| 18059 | mg_uecc_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ |
| 18060 | mg_uecc_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ |
| 18061 | mg_uecc_vli_modSub(X2, X2, t6, curve->p, |
| 18062 | num_words); /* t3 = D - (B + C) = x3 */ |
| 18063 | |
| 18064 | mg_uecc_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ |
| 18065 | mg_uecc_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ |
| 18066 | mg_uecc_vli_modSub(Y2, Y2, Y1, curve->p, |
| 18067 | num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ |
| 18068 | |
| 18069 | mg_uecc_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ |
| 18070 | mg_uecc_vli_modSub(t7, t7, t6, curve->p, |
| 18071 | num_words); /* t7 = F - (B + C) = x3' */ |
| 18072 | mg_uecc_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ |
| 18073 | mg_uecc_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ |
| 18074 | mg_uecc_vli_modSub(Y1, t6, Y1, curve->p, |
| 18075 | num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ |
| 18076 | |
| 18077 | mg_uecc_vli_set(X1, t7, num_words); |
| 18078 | } |
| 18079 | |
| 18080 | /* result may overlap point. */ |
| 18081 | static void EccPoint_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point, |
| 18082 | const mg_uecc_word_t *scalar, |
| 18083 | const mg_uecc_word_t *initial_Z, bitcount_t num_bits, |
| 18084 | MG_UECC_Curve curve) { |
| 18085 | /* R0 and R1 */ |
| 18086 | mg_uecc_word_t Rx[2][MG_UECC_MAX_WORDS]; |
| 18087 | mg_uecc_word_t Ry[2][MG_UECC_MAX_WORDS]; |
| 18088 | mg_uecc_word_t z[MG_UECC_MAX_WORDS]; |
| 18089 | bitcount_t i; |
| 18090 | mg_uecc_word_t nb; |
| 18091 | wordcount_t num_words = curve->num_words; |
| 18092 | |
| 18093 | mg_uecc_vli_set(Rx[1], point, num_words); |
| 18094 | mg_uecc_vli_set(Ry[1], point + num_words, num_words); |
| 18095 | |
| 18096 | XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); |
| 18097 | |
| 18098 | for (i = num_bits - 2; i > 0; --i) { |
| 18099 | nb = !mg_uecc_vli_testBit(scalar, i); |
| 18100 | XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); |
| 18101 | XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); |
| 18102 | } |
| 18103 | |
| 18104 | nb = !mg_uecc_vli_testBit(scalar, 0); |
| 18105 | XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); |
| 18106 | |
| 18107 | /* Find final 1/Z value. */ |
| 18108 | mg_uecc_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ |
| 18109 | mg_uecc_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ |
| 18110 | mg_uecc_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ |
| 18111 | mg_uecc_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ |
| 18112 | /* yP / (xP * Yb * (X1 - X0)) */ |
| 18113 | mg_uecc_vli_modMult_fast(z, z, point + num_words, curve); |
| 18114 | mg_uecc_vli_modMult_fast(z, z, Rx[1 - nb], |
| 18115 | curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ |
| 18116 | /* End 1/Z calculation */ |
| 18117 | |
| 18118 | XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); |
| 18119 | apply_z(Rx[0], Ry[0], z, curve); |
| 18120 | |
| 18121 | mg_uecc_vli_set(result, Rx[0], num_words); |
| 18122 | mg_uecc_vli_set(result + num_words, Ry[0], num_words); |
| 18123 | } |
| 18124 | |
| 18125 | static mg_uecc_word_t regularize_k(const mg_uecc_word_t *const k, |
| 18126 | mg_uecc_word_t *k0, mg_uecc_word_t *k1, |
| 18127 | MG_UECC_Curve curve) { |
| 18128 | wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); |
| 18129 | bitcount_t num_n_bits = curve->num_n_bits; |
| 18130 | mg_uecc_word_t carry = |
| 18131 | mg_uecc_vli_add(k0, k, curve->n, num_n_words) || |
| 18132 | (num_n_bits < ((bitcount_t) num_n_words * MG_UECC_WORD_SIZE * 8) && |
| 18133 | mg_uecc_vli_testBit(k0, num_n_bits)); |
| 18134 | mg_uecc_vli_add(k1, k0, curve->n, num_n_words); |
| 18135 | return carry; |
| 18136 | } |
| 18137 | |
| 18138 | /* Generates a random integer in the range 0 < random < top. |
| 18139 | Both random and top have num_words words. */ |
| 18140 | MG_UECC_VLI_API int mg_uecc_generate_random_int(mg_uecc_word_t *random, |
| 18141 | const mg_uecc_word_t *top, |
| 18142 | wordcount_t num_words) { |
| 18143 | mg_uecc_word_t mask = (mg_uecc_word_t) -1; |
| 18144 | mg_uecc_word_t tries; |
| 18145 | bitcount_t num_bits = mg_uecc_vli_numBits(top, num_words); |
| 18146 | |
| 18147 | if (!g_rng_function) { |
| 18148 | return 0; |
| 18149 | } |
| 18150 | |
| 18151 | for (tries = 0; tries < MG_UECC_RNG_MAX_TRIES; ++tries) { |
| 18152 | if (!g_rng_function((uint8_t *) random, |
| 18153 | (unsigned int) (num_words * MG_UECC_WORD_SIZE))) { |
| 18154 | return 0; |
| 18155 | } |
| 18156 | random[num_words - 1] &= |
| 18157 | mask >> ((bitcount_t) (num_words * MG_UECC_WORD_SIZE * 8 - num_bits)); |
| 18158 | if (!mg_uecc_vli_isZero(random, num_words) && |
| 18159 | mg_uecc_vli_cmp(top, random, num_words) == 1) { |
| 18160 | return 1; |
| 18161 | } |
| 18162 | } |
| 18163 | return 0; |
| 18164 | } |
| 18165 | |
| 18166 | static mg_uecc_word_t EccPoint_compute_public_key(mg_uecc_word_t *result, |
| 18167 | mg_uecc_word_t *private_key, |
| 18168 | MG_UECC_Curve curve) { |
| 18169 | mg_uecc_word_t tmp1[MG_UECC_MAX_WORDS]; |
| 18170 | mg_uecc_word_t tmp2[MG_UECC_MAX_WORDS]; |
| 18171 | mg_uecc_word_t *p2[2] = {tmp1, tmp2}; |
| 18172 | mg_uecc_word_t *initial_Z = 0; |
| 18173 | mg_uecc_word_t carry; |
| 18174 | |
| 18175 | /* Regularize the bitcount for the private key so that attackers cannot use a |
| 18176 | side channel attack to learn the number of leading zeros. */ |
| 18177 | carry = regularize_k(private_key, tmp1, tmp2, curve); |
| 18178 | |
| 18179 | /* If an RNG function was specified, try to get a random initial Z value to |
| 18180 | improve protection against side-channel attacks. */ |
| 18181 | if (g_rng_function) { |
| 18182 | if (!mg_uecc_generate_random_int(p2[carry], curve->p, curve->num_words)) { |
| 18183 | return 0; |
| 18184 | } |
| 18185 | initial_Z = p2[carry]; |
| 18186 | } |
| 18187 | EccPoint_mult(result, curve->G, p2[!carry], initial_Z, |
| 18188 | (bitcount_t) (curve->num_n_bits + 1), curve); |
| 18189 | |
| 18190 | if (EccPoint_isZero(result, curve)) { |
| 18191 | return 0; |
| 18192 | } |
| 18193 | return 1; |
| 18194 | } |
| 18195 | |
| 18196 | #if MG_UECC_WORD_SIZE == 1 |
| 18197 | |
| 18198 | MG_UECC_VLI_API void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes, |
| 18199 | const uint8_t *native) { |
| 18200 | wordcount_t i; |
| 18201 | for (i = 0; i < num_bytes; ++i) { |
| 18202 | bytes[i] = native[(num_bytes - 1) - i]; |
| 18203 | } |
| 18204 | } |
| 18205 | |
| 18206 | MG_UECC_VLI_API void mg_uecc_vli_bytesToNative(uint8_t *native, |
| 18207 | const uint8_t *bytes, |
| 18208 | int num_bytes) { |
| 18209 | mg_uecc_vli_nativeToBytes(native, num_bytes, bytes); |
| 18210 | } |
| 18211 | |
| 18212 | #else |
| 18213 | |
| 18214 | MG_UECC_VLI_API void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes, |
| 18215 | const mg_uecc_word_t *native) { |
| 18216 | int i; |
| 18217 | for (i = 0; i < num_bytes; ++i) { |
| 18218 | unsigned b = (unsigned) (num_bytes - 1 - i); |
| 18219 | bytes[i] = (uint8_t) (native[b / MG_UECC_WORD_SIZE] >> |
| 18220 | (8 * (b % MG_UECC_WORD_SIZE))); |
| 18221 | } |
| 18222 | } |
| 18223 | |
| 18224 | MG_UECC_VLI_API void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, |
| 18225 | const uint8_t *bytes, |
| 18226 | int num_bytes) { |
| 18227 | int i; |
| 18228 | mg_uecc_vli_clear(native, |
| 18229 | (wordcount_t) ((num_bytes + (MG_UECC_WORD_SIZE - 1)) / |
| 18230 | MG_UECC_WORD_SIZE)); |
| 18231 | for (i = 0; i < num_bytes; ++i) { |
| 18232 | unsigned b = (unsigned) (num_bytes - 1 - i); |
| 18233 | native[b / MG_UECC_WORD_SIZE] |= (mg_uecc_word_t) bytes[i] |
| 18234 | << (8 * (b % MG_UECC_WORD_SIZE)); |
| 18235 | } |
| 18236 | } |
| 18237 | |
| 18238 | #endif /* MG_UECC_WORD_SIZE */ |
| 18239 | |
| 18240 | int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key, |
| 18241 | MG_UECC_Curve curve) { |
| 18242 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18243 | mg_uecc_word_t *_private = (mg_uecc_word_t *) private_key; |
| 18244 | mg_uecc_word_t *_public = (mg_uecc_word_t *) public_key; |
| 18245 | #else |
| 18246 | mg_uecc_word_t _private[MG_UECC_MAX_WORDS]; |
| 18247 | mg_uecc_word_t _public[MG_UECC_MAX_WORDS * 2]; |
| 18248 | #endif |
| 18249 | mg_uecc_word_t tries; |
| 18250 | |
| 18251 | for (tries = 0; tries < MG_UECC_RNG_MAX_TRIES; ++tries) { |
| 18252 | if (!mg_uecc_generate_random_int(_private, curve->n, |
| 18253 | BITS_TO_WORDS(curve->num_n_bits))) { |
| 18254 | return 0; |
| 18255 | } |
| 18256 | |
| 18257 | if (EccPoint_compute_public_key(_public, _private, curve)) { |
| 18258 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN == 0 |
| 18259 | mg_uecc_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), |
| 18260 | _private); |
| 18261 | mg_uecc_vli_nativeToBytes(public_key, curve->num_bytes, _public); |
| 18262 | mg_uecc_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, |
| 18263 | _public + curve->num_words); |
| 18264 | #endif |
| 18265 | return 1; |
| 18266 | } |
| 18267 | } |
| 18268 | return 0; |
| 18269 | } |
| 18270 | |
| 18271 | int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key, |
| 18272 | uint8_t *secret, MG_UECC_Curve curve) { |
| 18273 | mg_uecc_word_t _public[MG_UECC_MAX_WORDS * 2]; |
| 18274 | mg_uecc_word_t _private[MG_UECC_MAX_WORDS]; |
| 18275 | |
| 18276 | mg_uecc_word_t tmp[MG_UECC_MAX_WORDS]; |
| 18277 | mg_uecc_word_t *p2[2] = {_private, tmp}; |
| 18278 | mg_uecc_word_t *initial_Z = 0; |
| 18279 | mg_uecc_word_t carry; |
| 18280 | wordcount_t num_words = curve->num_words; |
| 18281 | wordcount_t num_bytes = curve->num_bytes; |
| 18282 | |
| 18283 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18284 | bcopy((uint8_t *) _private, private_key, num_bytes); |
| 18285 | bcopy((uint8_t *) _public, public_key, num_bytes * 2); |
| 18286 | #else |
| 18287 | mg_uecc_vli_bytesToNative(_private, private_key, |
| 18288 | BITS_TO_BYTES(curve->num_n_bits)); |
| 18289 | mg_uecc_vli_bytesToNative(_public, public_key, num_bytes); |
| 18290 | mg_uecc_vli_bytesToNative(_public + num_words, public_key + num_bytes, |
| 18291 | num_bytes); |
| 18292 | #endif |
| 18293 | |
| 18294 | /* Regularize the bitcount for the private key so that attackers cannot use a |
| 18295 | side channel attack to learn the number of leading zeros. */ |
| 18296 | carry = regularize_k(_private, _private, tmp, curve); |
| 18297 | |
| 18298 | /* If an RNG function was specified, try to get a random initial Z value to |
| 18299 | improve protection against side-channel attacks. */ |
| 18300 | if (g_rng_function) { |
| 18301 | if (!mg_uecc_generate_random_int(p2[carry], curve->p, num_words)) { |
| 18302 | return 0; |
| 18303 | } |
| 18304 | initial_Z = p2[carry]; |
| 18305 | } |
| 18306 | |
| 18307 | EccPoint_mult(_public, _public, p2[!carry], initial_Z, |
| 18308 | (bitcount_t) (curve->num_n_bits + 1), curve); |
| 18309 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18310 | bcopy((uint8_t *) secret, (uint8_t *) _public, num_bytes); |
| 18311 | #else |
| 18312 | mg_uecc_vli_nativeToBytes(secret, num_bytes, _public); |
| 18313 | #endif |
| 18314 | return !EccPoint_isZero(_public, curve); |
| 18315 | } |
| 18316 | |
| 18317 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 18318 | void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed, |
| 18319 | MG_UECC_Curve curve) { |
| 18320 | wordcount_t i; |
| 18321 | for (i = 0; i < curve->num_bytes; ++i) { |
| 18322 | compressed[i + 1] = public_key[i]; |
| 18323 | } |
| 18324 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18325 | compressed[0] = 2 + (public_key[curve->num_bytes] & 0x01); |
| 18326 | #else |
| 18327 | compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); |
| 18328 | #endif |
| 18329 | } |
| 18330 | |
| 18331 | void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key, |
| 18332 | MG_UECC_Curve curve) { |
| 18333 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18334 | mg_uecc_word_t *point = (mg_uecc_word_t *) public_key; |
| 18335 | #else |
| 18336 | mg_uecc_word_t point[MG_UECC_MAX_WORDS * 2]; |
| 18337 | #endif |
| 18338 | mg_uecc_word_t *y = point + curve->num_words; |
| 18339 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18340 | bcopy(public_key, compressed + 1, curve->num_bytes); |
| 18341 | #else |
| 18342 | mg_uecc_vli_bytesToNative(point, compressed + 1, curve->num_bytes); |
| 18343 | #endif |
| 18344 | curve->x_side(y, point, curve); |
| 18345 | curve->mod_sqrt(y, curve); |
| 18346 | |
| 18347 | if ((uint8_t) (y[0] & 0x01) != (compressed[0] & 0x01)) { |
| 18348 | mg_uecc_vli_sub(y, curve->p, y, curve->num_words); |
| 18349 | } |
| 18350 | |
| 18351 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN == 0 |
| 18352 | mg_uecc_vli_nativeToBytes(public_key, curve->num_bytes, point); |
| 18353 | mg_uecc_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); |
| 18354 | #endif |
| 18355 | } |
| 18356 | #endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */ |
| 18357 | |
| 18358 | MG_UECC_VLI_API int mg_uecc_valid_point(const mg_uecc_word_t *point, |
| 18359 | MG_UECC_Curve curve) { |
| 18360 | mg_uecc_word_t tmp1[MG_UECC_MAX_WORDS]; |
| 18361 | mg_uecc_word_t tmp2[MG_UECC_MAX_WORDS]; |
| 18362 | wordcount_t num_words = curve->num_words; |
| 18363 | |
| 18364 | /* The point at infinity is invalid. */ |
| 18365 | if (EccPoint_isZero(point, curve)) { |
| 18366 | return 0; |
| 18367 | } |
| 18368 | |
| 18369 | /* x and y must be smaller than p. */ |
| 18370 | if (mg_uecc_vli_cmp_unsafe(curve->p, point, num_words) != 1 || |
| 18371 | mg_uecc_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { |
| 18372 | return 0; |
| 18373 | } |
| 18374 | |
| 18375 | mg_uecc_vli_modSquare_fast(tmp1, point + num_words, curve); |
| 18376 | curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ |
| 18377 | |
| 18378 | /* Make sure that y^2 == x^3 + ax + b */ |
| 18379 | return (int) (mg_uecc_vli_equal(tmp1, tmp2, num_words)); |
| 18380 | } |
| 18381 | |
| 18382 | int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve) { |
| 18383 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18384 | mg_uecc_word_t *_public = (mg_uecc_word_t *) public_key; |
| 18385 | #else |
| 18386 | mg_uecc_word_t _public[MG_UECC_MAX_WORDS * 2]; |
| 18387 | #endif |
| 18388 | |
| 18389 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN == 0 |
| 18390 | mg_uecc_vli_bytesToNative(_public, public_key, curve->num_bytes); |
| 18391 | mg_uecc_vli_bytesToNative(_public + curve->num_words, |
| 18392 | public_key + curve->num_bytes, curve->num_bytes); |
| 18393 | #endif |
| 18394 | return mg_uecc_valid_point(_public, curve); |
| 18395 | } |
| 18396 | |
| 18397 | int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key, |
| 18398 | MG_UECC_Curve curve) { |
| 18399 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18400 | mg_uecc_word_t *_private = (mg_uecc_word_t *) private_key; |
| 18401 | mg_uecc_word_t *_public = (mg_uecc_word_t *) public_key; |
| 18402 | #else |
| 18403 | mg_uecc_word_t _private[MG_UECC_MAX_WORDS]; |
| 18404 | mg_uecc_word_t _public[MG_UECC_MAX_WORDS * 2]; |
| 18405 | #endif |
| 18406 | |
| 18407 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN == 0 |
| 18408 | mg_uecc_vli_bytesToNative(_private, private_key, |
| 18409 | BITS_TO_BYTES(curve->num_n_bits)); |
| 18410 | #endif |
| 18411 | |
| 18412 | /* Make sure the private key is in the range [1, n-1]. */ |
| 18413 | if (mg_uecc_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) { |
| 18414 | return 0; |
| 18415 | } |
| 18416 | |
| 18417 | if (mg_uecc_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != |
| 18418 | 1) { |
| 18419 | return 0; |
| 18420 | } |
| 18421 | |
| 18422 | /* Compute public key. */ |
| 18423 | if (!EccPoint_compute_public_key(_public, _private, curve)) { |
| 18424 | return 0; |
| 18425 | } |
| 18426 | |
| 18427 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN == 0 |
| 18428 | mg_uecc_vli_nativeToBytes(public_key, curve->num_bytes, _public); |
| 18429 | mg_uecc_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, |
| 18430 | _public + curve->num_words); |
| 18431 | #endif |
| 18432 | return 1; |
| 18433 | } |
| 18434 | |
| 18435 | /* -------- ECDSA code -------- */ |
| 18436 | |
| 18437 | static void bits2int(mg_uecc_word_t *native, const uint8_t *bits, |
| 18438 | unsigned bits_size, MG_UECC_Curve curve) { |
| 18439 | unsigned num_n_bytes = (unsigned) BITS_TO_BYTES(curve->num_n_bits); |
| 18440 | unsigned num_n_words = (unsigned) BITS_TO_WORDS(curve->num_n_bits); |
| 18441 | int shift; |
| 18442 | mg_uecc_word_t carry; |
| 18443 | mg_uecc_word_t *ptr; |
| 18444 | |
| 18445 | if (bits_size > num_n_bytes) { |
| 18446 | bits_size = num_n_bytes; |
| 18447 | } |
| 18448 | |
| 18449 | mg_uecc_vli_clear(native, (wordcount_t) num_n_words); |
| 18450 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18451 | bcopy((uint8_t *) native, bits, bits_size); |
| 18452 | #else |
| 18453 | mg_uecc_vli_bytesToNative(native, bits, (int) bits_size); |
| 18454 | #endif |
| 18455 | if (bits_size * 8 <= (unsigned) curve->num_n_bits) { |
| 18456 | return; |
| 18457 | } |
| 18458 | shift = (int) bits_size * 8 - curve->num_n_bits; |
| 18459 | carry = 0; |
| 18460 | ptr = native + num_n_words; |
| 18461 | while (ptr-- > native) { |
| 18462 | mg_uecc_word_t temp = *ptr; |
| 18463 | *ptr = (temp >> shift) | carry; |
| 18464 | carry = temp << (MG_UECC_WORD_BITS - shift); |
| 18465 | } |
| 18466 | |
| 18467 | /* Reduce mod curve_n */ |
| 18468 | if (mg_uecc_vli_cmp_unsafe(curve->n, native, (wordcount_t) num_n_words) != |
| 18469 | 1) { |
| 18470 | mg_uecc_vli_sub(native, native, curve->n, (wordcount_t) num_n_words); |
| 18471 | } |
| 18472 | } |
| 18473 | |
| 18474 | static int mg_uecc_sign_with_k_internal(const uint8_t *private_key, |
| 18475 | const uint8_t *message_hash, |
| 18476 | unsigned hash_size, mg_uecc_word_t *k, |
| 18477 | uint8_t *signature, |
| 18478 | MG_UECC_Curve curve) { |
| 18479 | mg_uecc_word_t tmp[MG_UECC_MAX_WORDS]; |
| 18480 | mg_uecc_word_t s[MG_UECC_MAX_WORDS]; |
| 18481 | mg_uecc_word_t *k2[2] = {tmp, s}; |
| 18482 | mg_uecc_word_t *initial_Z = 0; |
| 18483 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18484 | mg_uecc_word_t *p = (mg_uecc_word_t *) signature; |
| 18485 | #else |
| 18486 | mg_uecc_word_t p[MG_UECC_MAX_WORDS * 2]; |
| 18487 | #endif |
| 18488 | mg_uecc_word_t carry; |
| 18489 | wordcount_t num_words = curve->num_words; |
| 18490 | wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); |
| 18491 | bitcount_t num_n_bits = curve->num_n_bits; |
| 18492 | |
| 18493 | /* Make sure 0 < k < curve_n */ |
| 18494 | if (mg_uecc_vli_isZero(k, num_words) || |
| 18495 | mg_uecc_vli_cmp(curve->n, k, num_n_words) != 1) { |
| 18496 | return 0; |
| 18497 | } |
| 18498 | |
| 18499 | carry = regularize_k(k, tmp, s, curve); |
| 18500 | /* If an RNG function was specified, try to get a random initial Z value to |
| 18501 | improve protection against side-channel attacks. */ |
| 18502 | if (g_rng_function) { |
| 18503 | if (!mg_uecc_generate_random_int(k2[carry], curve->p, num_words)) { |
| 18504 | return 0; |
| 18505 | } |
| 18506 | initial_Z = k2[carry]; |
| 18507 | } |
| 18508 | EccPoint_mult(p, curve->G, k2[!carry], initial_Z, |
| 18509 | (bitcount_t) (num_n_bits + 1), curve); |
| 18510 | if (mg_uecc_vli_isZero(p, num_words)) { |
| 18511 | return 0; |
| 18512 | } |
| 18513 | |
| 18514 | /* If an RNG function was specified, get a random number |
| 18515 | to prevent side channel analysis of k. */ |
| 18516 | if (!g_rng_function) { |
| 18517 | mg_uecc_vli_clear(tmp, num_n_words); |
| 18518 | tmp[0] = 1; |
| 18519 | } else if (!mg_uecc_generate_random_int(tmp, curve->n, num_n_words)) { |
| 18520 | return 0; |
| 18521 | } |
| 18522 | |
| 18523 | /* Prevent side channel analysis of mg_uecc_vli_modInv() to determine |
| 18524 | bits of k / the private key by premultiplying by a random number */ |
| 18525 | mg_uecc_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ |
| 18526 | mg_uecc_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ |
| 18527 | mg_uecc_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ |
| 18528 | |
| 18529 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN == 0 |
| 18530 | mg_uecc_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ |
| 18531 | #endif |
| 18532 | |
| 18533 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18534 | bcopy((uint8_t *) tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); |
| 18535 | #else |
| 18536 | mg_uecc_vli_bytesToNative(tmp, private_key, |
| 18537 | BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */ |
| 18538 | #endif |
| 18539 | |
| 18540 | s[num_n_words - 1] = 0; |
| 18541 | mg_uecc_vli_set(s, p, num_words); |
| 18542 | mg_uecc_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ |
| 18543 | |
| 18544 | bits2int(tmp, message_hash, hash_size, curve); |
| 18545 | mg_uecc_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ |
| 18546 | mg_uecc_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ |
| 18547 | if (mg_uecc_vli_numBits(s, num_n_words) > (bitcount_t) curve->num_bytes * 8) { |
| 18548 | return 0; |
| 18549 | } |
| 18550 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18551 | bcopy((uint8_t *) signature + curve->num_bytes, (uint8_t *) s, |
| 18552 | curve->num_bytes); |
| 18553 | #else |
| 18554 | mg_uecc_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); |
| 18555 | #endif |
| 18556 | return 1; |
| 18557 | } |
| 18558 | |
| 18559 | #if 0 |
| 18560 | /* For testing - sign with an explicitly specified k value */ |
| 18561 | int mg_uecc_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, |
| 18562 | unsigned hash_size, const uint8_t *k, uint8_t *signature, |
| 18563 | MG_UECC_Curve curve) { |
| 18564 | mg_uecc_word_t k2[MG_UECC_MAX_WORDS]; |
| 18565 | bits2int(k2, k, (unsigned) BITS_TO_BYTES(curve->num_n_bits), curve); |
| 18566 | return mg_uecc_sign_with_k_internal(private_key, message_hash, hash_size, k2, |
| 18567 | signature, curve); |
| 18568 | } |
| 18569 | #endif |
| 18570 | |
| 18571 | int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash, |
| 18572 | unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve) { |
| 18573 | mg_uecc_word_t k[MG_UECC_MAX_WORDS]; |
| 18574 | mg_uecc_word_t tries; |
| 18575 | |
| 18576 | for (tries = 0; tries < MG_UECC_RNG_MAX_TRIES; ++tries) { |
| 18577 | if (!mg_uecc_generate_random_int(k, curve->n, |
| 18578 | BITS_TO_WORDS(curve->num_n_bits))) { |
| 18579 | return 0; |
| 18580 | } |
| 18581 | |
| 18582 | if (mg_uecc_sign_with_k_internal(private_key, message_hash, hash_size, k, |
| 18583 | signature, curve)) { |
| 18584 | return 1; |
| 18585 | } |
| 18586 | } |
| 18587 | return 0; |
| 18588 | } |
| 18589 | |
| 18590 | /* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always |
| 18591 | the same size as the hash result size. */ |
| 18592 | static void HMAC_init(const MG_UECC_HashContext *hash_context, |
| 18593 | const uint8_t *K) { |
| 18594 | uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; |
| 18595 | unsigned i; |
| 18596 | for (i = 0; i < hash_context->result_size; ++i) pad[i] = K[i] ^ 0x36; |
| 18597 | for (; i < hash_context->block_size; ++i) pad[i] = 0x36; |
| 18598 | |
| 18599 | hash_context->init_hash(hash_context); |
| 18600 | hash_context->update_hash(hash_context, pad, hash_context->block_size); |
| 18601 | } |
| 18602 | |
| 18603 | static void HMAC_update(const MG_UECC_HashContext *hash_context, |
| 18604 | const uint8_t *message, unsigned message_size) { |
| 18605 | hash_context->update_hash(hash_context, message, message_size); |
| 18606 | } |
| 18607 | |
| 18608 | static void HMAC_finish(const MG_UECC_HashContext *hash_context, |
| 18609 | const uint8_t *K, uint8_t *result) { |
| 18610 | uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; |
| 18611 | unsigned i; |
| 18612 | for (i = 0; i < hash_context->result_size; ++i) pad[i] = K[i] ^ 0x5c; |
| 18613 | for (; i < hash_context->block_size; ++i) pad[i] = 0x5c; |
| 18614 | |
| 18615 | hash_context->finish_hash(hash_context, result); |
| 18616 | |
| 18617 | hash_context->init_hash(hash_context); |
| 18618 | hash_context->update_hash(hash_context, pad, hash_context->block_size); |
| 18619 | hash_context->update_hash(hash_context, result, hash_context->result_size); |
| 18620 | hash_context->finish_hash(hash_context, result); |
| 18621 | } |
| 18622 | |
| 18623 | /* V = HMAC_K(V) */ |
| 18624 | static void update_V(const MG_UECC_HashContext *hash_context, uint8_t *K, |
| 18625 | uint8_t *V) { |
| 18626 | HMAC_init(hash_context, K); |
| 18627 | HMAC_update(hash_context, V, hash_context->result_size); |
| 18628 | HMAC_finish(hash_context, K, V); |
| 18629 | } |
| 18630 | |
| 18631 | /* Deterministic signing, similar to RFC 6979. Differences are: |
| 18632 | * We just use H(m) directly rather than bits2octets(H(m)) |
| 18633 | (it is not reduced modulo curve_n). |
| 18634 | * We generate a value for k (aka T) directly rather than converting |
| 18635 | endianness. |
| 18636 | |
| 18637 | Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / |
| 18638 | <HMAC pad> */ |
| 18639 | int mg_uecc_sign_deterministic(const uint8_t *private_key, |
| 18640 | const uint8_t *message_hash, unsigned hash_size, |
| 18641 | const MG_UECC_HashContext *hash_context, |
| 18642 | uint8_t *signature, MG_UECC_Curve curve) { |
| 18643 | uint8_t *K = hash_context->tmp; |
| 18644 | uint8_t *V = K + hash_context->result_size; |
| 18645 | wordcount_t num_bytes = curve->num_bytes; |
| 18646 | wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); |
| 18647 | bitcount_t num_n_bits = curve->num_n_bits; |
| 18648 | mg_uecc_word_t tries; |
| 18649 | unsigned i; |
| 18650 | for (i = 0; i < hash_context->result_size; ++i) { |
| 18651 | V[i] = 0x01; |
| 18652 | K[i] = 0; |
| 18653 | } |
| 18654 | |
| 18655 | /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ |
| 18656 | HMAC_init(hash_context, K); |
| 18657 | V[hash_context->result_size] = 0x00; |
| 18658 | HMAC_update(hash_context, V, hash_context->result_size + 1); |
| 18659 | HMAC_update(hash_context, private_key, (unsigned int) num_bytes); |
| 18660 | HMAC_update(hash_context, message_hash, hash_size); |
| 18661 | HMAC_finish(hash_context, K, K); |
| 18662 | |
| 18663 | update_V(hash_context, K, V); |
| 18664 | |
| 18665 | /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ |
| 18666 | HMAC_init(hash_context, K); |
| 18667 | V[hash_context->result_size] = 0x01; |
| 18668 | HMAC_update(hash_context, V, hash_context->result_size + 1); |
| 18669 | HMAC_update(hash_context, private_key, (unsigned int) num_bytes); |
| 18670 | HMAC_update(hash_context, message_hash, hash_size); |
| 18671 | HMAC_finish(hash_context, K, K); |
| 18672 | |
| 18673 | update_V(hash_context, K, V); |
| 18674 | |
| 18675 | for (tries = 0; tries < MG_UECC_RNG_MAX_TRIES; ++tries) { |
| 18676 | mg_uecc_word_t T[MG_UECC_MAX_WORDS]; |
| 18677 | uint8_t *T_ptr = (uint8_t *) T; |
| 18678 | wordcount_t T_bytes = 0; |
| 18679 | for (;;) { |
| 18680 | update_V(hash_context, K, V); |
| 18681 | for (i = 0; i < hash_context->result_size; ++i) { |
| 18682 | T_ptr[T_bytes++] = V[i]; |
| 18683 | if (T_bytes >= num_n_words * MG_UECC_WORD_SIZE) { |
| 18684 | goto filled; |
| 18685 | } |
| 18686 | } |
| 18687 | } |
| 18688 | filled: |
| 18689 | if ((bitcount_t) num_n_words * MG_UECC_WORD_SIZE * 8 > num_n_bits) { |
| 18690 | mg_uecc_word_t mask = (mg_uecc_word_t) -1; |
| 18691 | T[num_n_words - 1] &= |
| 18692 | mask >> |
| 18693 | ((bitcount_t) (num_n_words * MG_UECC_WORD_SIZE * 8 - num_n_bits)); |
| 18694 | } |
| 18695 | |
| 18696 | if (mg_uecc_sign_with_k_internal(private_key, message_hash, hash_size, T, |
| 18697 | signature, curve)) { |
| 18698 | return 1; |
| 18699 | } |
| 18700 | |
| 18701 | /* K = HMAC_K(V || 0x00) */ |
| 18702 | HMAC_init(hash_context, K); |
| 18703 | V[hash_context->result_size] = 0x00; |
| 18704 | HMAC_update(hash_context, V, hash_context->result_size + 1); |
| 18705 | HMAC_finish(hash_context, K, K); |
| 18706 | |
| 18707 | update_V(hash_context, K, V); |
| 18708 | } |
| 18709 | return 0; |
| 18710 | } |
| 18711 | |
| 18712 | static bitcount_t smax(bitcount_t a, bitcount_t b) { |
| 18713 | return (a > b ? a : b); |
| 18714 | } |
| 18715 | |
| 18716 | int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash, |
| 18717 | unsigned hash_size, const uint8_t *signature, |
| 18718 | MG_UECC_Curve curve) { |
| 18719 | mg_uecc_word_t u1[MG_UECC_MAX_WORDS], u2[MG_UECC_MAX_WORDS]; |
| 18720 | mg_uecc_word_t z[MG_UECC_MAX_WORDS]; |
| 18721 | mg_uecc_word_t sum[MG_UECC_MAX_WORDS * 2]; |
| 18722 | mg_uecc_word_t rx[MG_UECC_MAX_WORDS]; |
| 18723 | mg_uecc_word_t ry[MG_UECC_MAX_WORDS]; |
| 18724 | mg_uecc_word_t tx[MG_UECC_MAX_WORDS]; |
| 18725 | mg_uecc_word_t ty[MG_UECC_MAX_WORDS]; |
| 18726 | mg_uecc_word_t tz[MG_UECC_MAX_WORDS]; |
| 18727 | const mg_uecc_word_t *points[4]; |
| 18728 | const mg_uecc_word_t *point; |
| 18729 | bitcount_t num_bits; |
| 18730 | bitcount_t i; |
| 18731 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18732 | mg_uecc_word_t *_public = (mg_uecc_word_t *) public_key; |
| 18733 | #else |
| 18734 | mg_uecc_word_t _public[MG_UECC_MAX_WORDS * 2]; |
| 18735 | #endif |
| 18736 | mg_uecc_word_t r[MG_UECC_MAX_WORDS], s[MG_UECC_MAX_WORDS]; |
| 18737 | wordcount_t num_words = curve->num_words; |
| 18738 | wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); |
| 18739 | |
| 18740 | rx[num_n_words - 1] = 0; |
| 18741 | r[num_n_words - 1] = 0; |
| 18742 | s[num_n_words - 1] = 0; |
| 18743 | |
| 18744 | #if MG_UECC_VLI_NATIVE_LITTLE_ENDIAN |
| 18745 | bcopy((uint8_t *) r, signature, curve->num_bytes); |
| 18746 | bcopy((uint8_t *) s, signature + curve->num_bytes, curve->num_bytes); |
| 18747 | #else |
| 18748 | mg_uecc_vli_bytesToNative(_public, public_key, curve->num_bytes); |
| 18749 | mg_uecc_vli_bytesToNative(_public + num_words, public_key + curve->num_bytes, |
| 18750 | curve->num_bytes); |
| 18751 | mg_uecc_vli_bytesToNative(r, signature, curve->num_bytes); |
| 18752 | mg_uecc_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); |
| 18753 | #endif |
| 18754 | |
| 18755 | /* r, s must not be 0. */ |
| 18756 | if (mg_uecc_vli_isZero(r, num_words) || mg_uecc_vli_isZero(s, num_words)) { |
| 18757 | return 0; |
| 18758 | } |
| 18759 | |
| 18760 | /* r, s must be < n. */ |
| 18761 | if (mg_uecc_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || |
| 18762 | mg_uecc_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { |
| 18763 | return 0; |
| 18764 | } |
| 18765 | |
| 18766 | /* Calculate u1 and u2. */ |
| 18767 | mg_uecc_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ |
| 18768 | u1[num_n_words - 1] = 0; |
| 18769 | bits2int(u1, message_hash, hash_size, curve); |
| 18770 | mg_uecc_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ |
| 18771 | mg_uecc_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ |
| 18772 | |
| 18773 | /* Calculate sum = G + Q. */ |
| 18774 | mg_uecc_vli_set(sum, _public, num_words); |
| 18775 | mg_uecc_vli_set(sum + num_words, _public + num_words, num_words); |
| 18776 | mg_uecc_vli_set(tx, curve->G, num_words); |
| 18777 | mg_uecc_vli_set(ty, curve->G + num_words, num_words); |
| 18778 | mg_uecc_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ |
| 18779 | XYcZ_add(tx, ty, sum, sum + num_words, curve); |
| 18780 | mg_uecc_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ |
| 18781 | apply_z(sum, sum + num_words, z, curve); |
| 18782 | |
| 18783 | /* Use Shamir's trick to calculate u1*G + u2*Q */ |
| 18784 | points[0] = 0; |
| 18785 | points[1] = curve->G; |
| 18786 | points[2] = _public; |
| 18787 | points[3] = sum; |
| 18788 | num_bits = smax(mg_uecc_vli_numBits(u1, num_n_words), |
| 18789 | mg_uecc_vli_numBits(u2, num_n_words)); |
| 18790 | point = |
| 18791 | points[(!!mg_uecc_vli_testBit(u1, (bitcount_t) (num_bits - 1))) | |
| 18792 | ((!!mg_uecc_vli_testBit(u2, (bitcount_t) (num_bits - 1))) << 1)]; |
| 18793 | mg_uecc_vli_set(rx, point, num_words); |
| 18794 | mg_uecc_vli_set(ry, point + num_words, num_words); |
| 18795 | mg_uecc_vli_clear(z, num_words); |
| 18796 | z[0] = 1; |
| 18797 | |
| 18798 | for (i = num_bits - 2; i >= 0; --i) { |
| 18799 | mg_uecc_word_t index; |
| 18800 | curve->double_jacobian(rx, ry, z, curve); |
| 18801 | |
| 18802 | index = (!!mg_uecc_vli_testBit(u1, i)) | |
| 18803 | (mg_uecc_word_t) ((!!mg_uecc_vli_testBit(u2, i)) << 1); |
| 18804 | point = points[index]; |
| 18805 | if (point) { |
| 18806 | mg_uecc_vli_set(tx, point, num_words); |
| 18807 | mg_uecc_vli_set(ty, point + num_words, num_words); |
| 18808 | apply_z(tx, ty, z, curve); |
| 18809 | mg_uecc_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ |
| 18810 | XYcZ_add(tx, ty, rx, ry, curve); |
| 18811 | mg_uecc_vli_modMult_fast(z, z, tz, curve); |
| 18812 | } |
| 18813 | } |
| 18814 | |
| 18815 | mg_uecc_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ |
| 18816 | apply_z(rx, ry, z, curve); |
| 18817 | |
| 18818 | /* v = x1 (mod n) */ |
| 18819 | if (mg_uecc_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { |
| 18820 | mg_uecc_vli_sub(rx, rx, curve->n, num_n_words); |
| 18821 | } |
| 18822 | |
| 18823 | /* Accept only if v == r. */ |
| 18824 | return (int) (mg_uecc_vli_equal(rx, r, num_words)); |
| 18825 | } |
| 18826 | |
| 18827 | #if MG_UECC_ENABLE_VLI_API |
| 18828 | |
| 18829 | unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve) { |
| 18830 | return curve->num_words; |
| 18831 | } |
| 18832 | |
| 18833 | unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve) { |
| 18834 | return curve->num_bytes; |
| 18835 | } |
| 18836 | |
| 18837 | unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve) { |
| 18838 | return curve->num_bytes * 8; |
| 18839 | } |
| 18840 | |
| 18841 | unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve) { |
| 18842 | return BITS_TO_WORDS(curve->num_n_bits); |
| 18843 | } |
| 18844 | |
| 18845 | unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve) { |
| 18846 | return BITS_TO_BYTES(curve->num_n_bits); |
| 18847 | } |
| 18848 | |
| 18849 | unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve) { |
| 18850 | return curve->num_n_bits; |
| 18851 | } |
| 18852 | |
| 18853 | const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve) { |
| 18854 | return curve->p; |
| 18855 | } |
| 18856 | |
| 18857 | const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve) { |
| 18858 | return curve->n; |
| 18859 | } |
| 18860 | |
| 18861 | const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve) { |
| 18862 | return curve->G; |
| 18863 | } |
| 18864 | |
| 18865 | const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve) { |
| 18866 | return curve->b; |
| 18867 | } |
| 18868 | |
| 18869 | #if MG_UECC_SUPPORT_COMPRESSED_POINT |
| 18870 | void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve) { |
| 18871 | curve->mod_sqrt(a, curve); |
| 18872 | } |
| 18873 | #endif |
| 18874 | |
| 18875 | void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product, |
| 18876 | MG_UECC_Curve curve) { |
| 18877 | #if (MG_UECC_OPTIMIZATION_LEVEL > 0) |
| 18878 | curve->mmod_fast(result, product); |
| 18879 | #else |
| 18880 | mg_uecc_vli_mmod(result, product, curve->p, curve->num_words); |
| 18881 | #endif |
| 18882 | } |
| 18883 | |
| 18884 | void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point, |
| 18885 | const mg_uecc_word_t *scalar, MG_UECC_Curve curve) { |
| 18886 | mg_uecc_word_t tmp1[MG_UECC_MAX_WORDS]; |
| 18887 | mg_uecc_word_t tmp2[MG_UECC_MAX_WORDS]; |
| 18888 | mg_uecc_word_t *p2[2] = {tmp1, tmp2}; |
| 18889 | mg_uecc_word_t carry = regularize_k(scalar, tmp1, tmp2, curve); |
| 18890 | |
| 18891 | EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve); |
| 18892 | } |
| 18893 | |
| 18894 | #endif /* MG_UECC_ENABLE_VLI_API */ |
| 18895 | #endif // MG_TLS_BUILTIN |
| 18896 | // End of uecc BSD-2 |
| 18897 | |
| 18898 | #ifdef MG_ENABLE_LINES |
| 18899 | #line 1 "src/tls_x25519.c" |
| 18900 | #endif |
| 18901 | /** |
| 18902 | * Adapted from STROBE: https://strobe.sourceforge.io/ |
| 18903 | * Copyright (c) 2015-2016 Cryptography Research, Inc. |
| 18904 | * Author: Mike Hamburg |
| 18905 | * License: MIT License |
| 18906 | */ |
| 18907 | |
| 18908 | |
| 18909 | |
| 18910 | |
| 18911 | #if MG_TLS == MG_TLS_BUILTIN |
| 18912 | |
| 18913 | const uint8_t X25519_BASE_POINT[X25519_BYTES] = {9}; |
| 18914 | |
| 18915 | #define X25519_WBITS 32 |
| 18916 | |
| 18917 | typedef uint32_t limb_t; |
| 18918 | typedef uint64_t dlimb_t; |
| 18919 | typedef int64_t sdlimb_t; |
| 18920 | |
| 18921 | #define NLIMBS (256 / X25519_WBITS) |
| 18922 | typedef limb_t mg_fe[NLIMBS]; |
| 18923 | |
| 18924 | static limb_t umaal(limb_t *carry, limb_t acc, limb_t mand, limb_t mier) { |
| 18925 | dlimb_t tmp = (dlimb_t) mand * mier + acc + *carry; |
| 18926 | *carry = (limb_t) (tmp >> X25519_WBITS); |
| 18927 | return (limb_t) tmp; |
| 18928 | } |
| 18929 | |
| 18930 | // These functions are implemented in terms of umaal on ARM |
| 18931 | static limb_t adc(limb_t *carry, limb_t acc, limb_t mand) { |
| 18932 | dlimb_t total = (dlimb_t) *carry + acc + mand; |
| 18933 | *carry = (limb_t) (total >> X25519_WBITS); |
| 18934 | return (limb_t) total; |
| 18935 | } |
| 18936 | |
| 18937 | static limb_t adc0(limb_t *carry, limb_t acc) { |
| 18938 | dlimb_t total = (dlimb_t) *carry + acc; |
| 18939 | *carry = (limb_t) (total >> X25519_WBITS); |
| 18940 | return (limb_t) total; |
| 18941 | } |
| 18942 | |
| 18943 | // - Precondition: carry is small. |
| 18944 | // - Invariant: result of propagate is < 2^255 + 1 word |
| 18945 | // - In particular, always less than 2p. |
| 18946 | // - Also, output x >= min(x,19) |
| 18947 | static void propagate(mg_fe x, limb_t over) { |
| 18948 | unsigned i; |
| 18949 | limb_t carry; |
| 18950 | over = x[NLIMBS - 1] >> (X25519_WBITS - 1) | over << 1; |
| 18951 | x[NLIMBS - 1] &= ~((limb_t) 1 << (X25519_WBITS - 1)); |
| 18952 | |
| 18953 | carry = over * 19; |
| 18954 | for (i = 0; i < NLIMBS; i++) { |
| 18955 | x[i] = adc0(&carry, x[i]); |
| 18956 | } |
| 18957 | } |
| 18958 | |
| 18959 | static void add(mg_fe out, const mg_fe a, const mg_fe b) { |
| 18960 | unsigned i; |
| 18961 | limb_t carry = 0; |
| 18962 | for (i = 0; i < NLIMBS; i++) { |
| 18963 | out[i] = adc(&carry, a[i], b[i]); |
| 18964 | } |
| 18965 | propagate(out, carry); |
| 18966 | } |
| 18967 | |
| 18968 | static void sub(mg_fe out, const mg_fe a, const mg_fe b) { |
| 18969 | unsigned i; |
| 18970 | sdlimb_t carry = -38; |
| 18971 | for (i = 0; i < NLIMBS; i++) { |
| 18972 | carry = carry + a[i] - b[i]; |
| 18973 | out[i] = (limb_t) carry; |
| 18974 | carry >>= X25519_WBITS; |
| 18975 | } |
| 18976 | propagate(out, (limb_t) (1 + carry)); |
| 18977 | } |
| 18978 | |
| 18979 | // `b` can contain less than 8 limbs, thus we use `limb_t *` instead of `mg_fe` |
| 18980 | // to avoid build warnings |
| 18981 | static void mul(mg_fe out, const mg_fe a, const limb_t *b, unsigned nb) { |
| 18982 | limb_t accum[2 * NLIMBS] = {0}; |
| 18983 | unsigned i, j; |
| 18984 | |
| 18985 | limb_t carry2; |
| 18986 | for (i = 0; i < nb; i++) { |
| 18987 | limb_t mand = b[i]; |
| 18988 | carry2 = 0; |
| 18989 | for (j = 0; j < NLIMBS; j++) { |
| 18990 | limb_t tmp; // "a" may be misaligned |
| 18991 | memcpy(&tmp, &a[j], sizeof(tmp)); // So make an aligned copy |
| 18992 | accum[i + j] = umaal(&carry2, accum[i + j], mand, tmp); |
| 18993 | } |
| 18994 | accum[i + j] = carry2; |
| 18995 | } |
| 18996 | |
| 18997 | carry2 = 0; |
| 18998 | for (j = 0; j < NLIMBS; j++) { |
| 18999 | out[j] = umaal(&carry2, accum[j], 38, accum[j + NLIMBS]); |
| 19000 | } |
| 19001 | propagate(out, carry2); |
| 19002 | } |
| 19003 | |
| 19004 | static void sqr(mg_fe out, const mg_fe a) { |
| 19005 | mul(out, a, a, NLIMBS); |
| 19006 | } |
| 19007 | static void mul1(mg_fe out, const mg_fe a) { |
| 19008 | mul(out, a, out, NLIMBS); |
| 19009 | } |
| 19010 | static void sqr1(mg_fe a) { |
| 19011 | mul1(a, a); |
| 19012 | } |
| 19013 | |
| 19014 | static void condswap(limb_t a[2 * NLIMBS], limb_t b[2 * NLIMBS], |
| 19015 | limb_t doswap) { |
| 19016 | unsigned i; |
| 19017 | for (i = 0; i < 2 * NLIMBS; i++) { |
| 19018 | limb_t xor_ab = (a[i] ^ b[i]) & doswap; |
| 19019 | a[i] ^= xor_ab; |
| 19020 | b[i] ^= xor_ab; |
| 19021 | } |
| 19022 | } |
| 19023 | |
| 19024 | // Canonicalize a field element x, reducing it to the least residue which is |
| 19025 | // congruent to it mod 2^255-19 |
| 19026 | // - Precondition: x < 2^255 + 1 word |
| 19027 | static limb_t canon(mg_fe x) { |
| 19028 | // First, add 19. |
| 19029 | unsigned i; |
| 19030 | limb_t carry0 = 19; |
| 19031 | limb_t res; |
| 19032 | sdlimb_t carry; |
| 19033 | for (i = 0; i < NLIMBS; i++) { |
| 19034 | x[i] = adc0(&carry0, x[i]); |
| 19035 | } |
| 19036 | propagate(x, carry0); |
| 19037 | |
| 19038 | // Here, 19 <= x2 < 2^255 |
| 19039 | // - This is because we added 19, so before propagate it can't be less |
| 19040 | // than 19. After propagate, it still can't be less than 19, because if |
| 19041 | // propagate does anything it adds 19. |
| 19042 | // - We know that the high bit must be clear, because either the input was ~ |
| 19043 | // 2^255 + one word + 19 (in which case it propagates to at most 2 words) or |
| 19044 | // it was < 2^255. So now, if we subtract 19, we will get back to something in |
| 19045 | // [0,2^255-19). |
| 19046 | carry = -19; |
| 19047 | res = 0; |
| 19048 | for (i = 0; i < NLIMBS; i++) { |
| 19049 | carry += x[i]; |
| 19050 | res |= x[i] = (limb_t) carry; |
| 19051 | carry >>= X25519_WBITS; |
| 19052 | } |
| 19053 | return (limb_t) (((dlimb_t) res - 1) >> X25519_WBITS); |
| 19054 | } |
| 19055 | |
| 19056 | static const limb_t a24[1] = {121665}; |
| 19057 | |
| 19058 | static void ladder_part1(mg_fe xs[5]) { |
| 19059 | limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4]; |
| 19060 | add(t1, x2, z2); // t1 = A |
| 19061 | sub(z2, x2, z2); // z2 = B |
| 19062 | add(x2, x3, z3); // x2 = C |
| 19063 | sub(z3, x3, z3); // z3 = D |
| 19064 | mul1(z3, t1); // z3 = DA |
| 19065 | mul1(x2, z2); // x3 = BC |
| 19066 | add(x3, z3, x2); // x3 = DA+CB |
| 19067 | sub(z3, z3, x2); // z3 = DA-CB |
| 19068 | sqr1(t1); // t1 = AA |
| 19069 | sqr1(z2); // z2 = BB |
| 19070 | sub(x2, t1, z2); // x2 = E = AA-BB |
| 19071 | mul(z2, x2, a24, sizeof(a24) / sizeof(a24[0])); // z2 = E*a24 |
| 19072 | add(z2, z2, t1); // z2 = E*a24 + AA |
| 19073 | } |
| 19074 | |
| 19075 | static void ladder_part2(mg_fe xs[5], const mg_fe x1) { |
| 19076 | limb_t *x2 = xs[0], *z2 = xs[1], *x3 = xs[2], *z3 = xs[3], *t1 = xs[4]; |
| 19077 | sqr1(z3); // z3 = (DA-CB)^2 |
| 19078 | mul1(z3, x1); // z3 = x1 * (DA-CB)^2 |
| 19079 | sqr1(x3); // x3 = (DA+CB)^2 |
| 19080 | mul1(z2, x2); // z2 = AA*(E*a24+AA) |
| 19081 | sub(x2, t1, x2); // x2 = BB again |
| 19082 | mul1(x2, t1); // x2 = AA*BB |
| 19083 | } |
| 19084 | |
| 19085 | static void x25519_core(mg_fe xs[5], const uint8_t scalar[X25519_BYTES], |
| 19086 | const uint8_t *x1, int clamp) { |
| 19087 | int i; |
| 19088 | mg_fe x1_limbs; |
| 19089 | limb_t swap = 0; |
| 19090 | limb_t *x2 = xs[0], *x3 = xs[2], *z3 = xs[3]; |
| 19091 | memset(xs, 0, 4 * sizeof(mg_fe)); |
| 19092 | x2[0] = z3[0] = 1; |
| 19093 | for (i = 0; i < NLIMBS; i++) { |
| 19094 | x3[i] = x1_limbs[i] = |
| 19095 | MG_U32(x1[i * 4 + 3], x1[i * 4 + 2], x1[i * 4 + 1], x1[i * 4]); |
| 19096 | } |
| 19097 | |
| 19098 | for (i = 255; i >= 0; i--) { |
| 19099 | uint8_t bytei = scalar[i / 8]; |
| 19100 | limb_t doswap; |
| 19101 | if (clamp) { |
| 19102 | if (i / 8 == 0) { |
| 19103 | bytei &= (uint8_t) ~7U; |
| 19104 | } else if (i / 8 == X25519_BYTES - 1) { |
| 19105 | bytei &= 0x7F; |
| 19106 | bytei |= 0x40; |
| 19107 | } |
| 19108 | } |
| 19109 | doswap = 0 - (limb_t) ((bytei >> (i % 8)) & 1); |
| 19110 | condswap(x2, x3, swap ^ doswap); |
| 19111 | swap = doswap; |
| 19112 | |
| 19113 | ladder_part1(xs); |
| 19114 | ladder_part2(xs, (const limb_t *) x1_limbs); |
| 19115 | } |
| 19116 | condswap(x2, x3, swap); |
| 19117 | } |
| 19118 | |
| 19119 | int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES], |
| 19120 | const uint8_t x1[X25519_BYTES], int clamp) { |
| 19121 | int i, ret; |
| 19122 | mg_fe xs[5], out_limbs; |
| 19123 | limb_t *x2, *z2, *z3, *prev; |
| 19124 | static const struct { |
| 19125 | uint8_t a, c, n; |
| 19126 | } steps[13] = {{2, 1, 1}, {2, 1, 1}, {4, 2, 3}, {2, 4, 6}, {3, 1, 1}, |
| 19127 | {3, 2, 12}, {4, 3, 25}, {2, 3, 25}, {2, 4, 50}, {3, 2, 125}, |
| 19128 | {3, 1, 2}, {3, 1, 2}, {3, 1, 1}}; |
| 19129 | x25519_core(xs, scalar, x1, clamp); |
| 19130 | |
| 19131 | // Precomputed inversion chain |
| 19132 | x2 = xs[0]; |
| 19133 | z2 = xs[1]; |
| 19134 | z3 = xs[3]; |
| 19135 | |
| 19136 | prev = z2; |
| 19137 | for (i = 0; i < 13; i++) { |
| 19138 | int j; |
| 19139 | limb_t *a = xs[steps[i].a]; |
| 19140 | for (j = steps[i].n; j > 0; j--) { |
| 19141 | sqr(a, prev); |
| 19142 | prev = a; |
| 19143 | } |
| 19144 | mul1(a, xs[steps[i].c]); |
| 19145 | } |
| 19146 | |
| 19147 | // Here prev = z3 |
| 19148 | // x2 /= z2 |
| 19149 | mul(out_limbs, x2, z3, NLIMBS); |
| 19150 | ret = (int) canon(out_limbs); |
| 19151 | if (!clamp) ret = 0; |
| 19152 | for (i = 0; i < NLIMBS; i++) { |
| 19153 | uint32_t n = out_limbs[i]; |
| 19154 | out[i * 4] = (uint8_t) (n & 0xff); |
| 19155 | out[i * 4 + 1] = (uint8_t) ((n >> 8) & 0xff); |
| 19156 | out[i * 4 + 2] = (uint8_t) ((n >> 16) & 0xff); |
| 19157 | out[i * 4 + 3] = (uint8_t) ((n >> 24) & 0xff); |
| 19158 | } |
| 19159 | return ret; |
| 19160 | } |
| 19161 | |
| 19162 | #endif |
| 19163 | |
| 19164 | #ifdef MG_ENABLE_LINES |
| 19165 | #line 1 "src/url.c" |
| 19166 | #endif |
| 19167 | |
| 19168 | |
| 19169 | struct url { |
| 19170 | size_t key, user, pass, host, port, uri, end; |
| 19171 | }; |
| 19172 | |
| 19173 | int mg_url_is_ssl(const char *url) { |
| 19174 | return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 || |
| 19175 | strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 || |
| 19176 | strncmp(url, "tls:", 4) == 0 || strncmp(url, "tcps:", 5) == 0; |
| 19177 | } |
| 19178 | |
| 19179 | static struct url urlparse(const char *url) { |
| 19180 | size_t i; |
| 19181 | struct url u; |
| 19182 | memset(&u, 0, sizeof(u)); |
| 19183 | for (i = 0; url[i] != '\0'; i++) { |
| 19184 | if (url[i] == '/' && i > 0 && u.host == 0 && url[i - 1] == '/') { |
| 19185 | u.host = i + 1; |
| 19186 | u.port = 0; |
| 19187 | } else if (url[i] == ']') { |
| 19188 | u.port = 0; // IPv6 URLs, like http://[::1]/bar |
| 19189 | } else if (url[i] == ':' && u.port == 0 && u.uri == 0) { |
| 19190 | u.port = i + 1; |
| 19191 | } else if (url[i] == '@' && u.user == 0 && u.pass == 0 && u.uri == 0) { |
| 19192 | u.user = u.host; |
| 19193 | u.pass = u.port; |
| 19194 | u.host = i + 1; |
| 19195 | u.port = 0; |
| 19196 | } else if (url[i] == '/' && u.host && u.uri == 0) { |
| 19197 | u.uri = i; |
| 19198 | } |
| 19199 | } |
| 19200 | u.end = i; |
| 19201 | #if 0 |
| 19202 | printf("[%s] %d %d %d %d %d\n", url, u.user, u.pass, u.host, u.port, u.uri); |
| 19203 | #endif |
| 19204 | return u; |
| 19205 | } |
| 19206 | |
| 19207 | struct mg_str mg_url_host(const char *url) { |
| 19208 | struct url u = urlparse(url); |
| 19209 | size_t n = u.port ? u.port - u.host - 1 |
| 19210 | : u.uri ? u.uri - u.host |
| 19211 | : u.end - u.host; |
| 19212 | struct mg_str s = mg_str_n(url + u.host, n); |
| 19213 | return s; |
| 19214 | } |
| 19215 | |
| 19216 | const char *mg_url_uri(const char *url) { |
| 19217 | struct url u = urlparse(url); |
| 19218 | return u.uri ? url + u.uri : "/"; |
| 19219 | } |
| 19220 | |
| 19221 | unsigned short mg_url_port(const char *url) { |
| 19222 | struct url u = urlparse(url); |
| 19223 | unsigned short port = 0; |
| 19224 | if (strncmp(url, "http:", 5) == 0 || strncmp(url, "ws:", 3) == 0) port = 80; |
| 19225 | if (strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0) |
| 19226 | port = 443; |
| 19227 | if (strncmp(url, "mqtt:", 5) == 0) port = 1883; |
| 19228 | if (strncmp(url, "mqtts:", 6) == 0) port = 8883; |
| 19229 | if (u.port) port = (unsigned short) atoi(url + u.port); |
| 19230 | return port; |
| 19231 | } |
| 19232 | |
| 19233 | struct mg_str mg_url_user(const char *url) { |
| 19234 | struct url u = urlparse(url); |
| 19235 | struct mg_str s = mg_str(""); |
| 19236 | if (u.user && (u.pass || u.host)) { |
| 19237 | size_t n = u.pass ? u.pass - u.user - 1 : u.host - u.user - 1; |
| 19238 | s = mg_str_n(url + u.user, n); |
| 19239 | } |
| 19240 | return s; |
| 19241 | } |
| 19242 | |
| 19243 | struct mg_str mg_url_pass(const char *url) { |
| 19244 | struct url u = urlparse(url); |
| 19245 | struct mg_str s = mg_str_n("", 0UL); |
| 19246 | if (u.pass && u.host) { |
| 19247 | size_t n = u.host - u.pass - 1; |
| 19248 | s = mg_str_n(url + u.pass, n); |
| 19249 | } |
| 19250 | return s; |
| 19251 | } |
| 19252 | |
| 19253 | #ifdef MG_ENABLE_LINES |
| 19254 | #line 1 "src/util.c" |
| 19255 | #endif |
| 19256 | |
| 19257 | |
| 19258 | |
| 19259 | // Not using memset for zeroing memory, cause it can be dropped by compiler |
| 19260 | // See https://github.com/cesanta/mongoose/pull/1265 |
| 19261 | void mg_bzero(volatile unsigned char *buf, size_t len) { |
| 19262 | if (buf != NULL) { |
| 19263 | while (len--) *buf++ = 0; |
| 19264 | } |
| 19265 | } |
| 19266 | |
| 19267 | #if MG_ENABLE_CUSTOM_RANDOM |
| 19268 | #else |
| 19269 | bool mg_random(void *buf, size_t len) { |
| 19270 | bool success = false; |
| 19271 | unsigned char *p = (unsigned char *) buf; |
| 19272 | #if MG_ARCH == MG_ARCH_ESP32 |
| 19273 | while (len--) *p++ = (unsigned char) (esp_random() & 255); |
| 19274 | success = true; |
| 19275 | #elif MG_ARCH == MG_ARCH_PICOSDK |
| 19276 | while (len--) *p++ = (unsigned char) (get_rand_32() & 255); |
| 19277 | success = true; |
| 19278 | #elif MG_ARCH == MG_ARCH_WIN32 |
| 19279 | #if defined(_MSC_VER) && _MSC_VER < 1700 |
| 19280 | static bool initialised = false; |
| 19281 | static HCRYPTPROV hProv; |
| 19282 | // CryptGenRandom() implementation earlier than 2008 is weak, see |
| 19283 | // https://en.wikipedia.org/wiki/CryptGenRandom |
| 19284 | if (!initialised) { |
| 19285 | initialised = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, |
| 19286 | CRYPT_VERIFYCONTEXT); |
| 19287 | } |
| 19288 | if (initialised) success = CryptGenRandom(hProv, len, p); |
| 19289 | #else |
| 19290 | size_t i; |
| 19291 | for (i = 0; i < len; i++) { |
| 19292 | unsigned int rand_v; |
| 19293 | if (rand_s(&rand_v) == 0) { |
| 19294 | p[i] = (unsigned char) (rand_v & 255); |
| 19295 | } else { |
| 19296 | break; |
| 19297 | } |
| 19298 | } |
| 19299 | success = (i == len); |
| 19300 | #endif |
| 19301 | |
| 19302 | #elif MG_ARCH == MG_ARCH_UNIX |
| 19303 | FILE *fp = fopen("/dev/urandom", "rb"); |
| 19304 | if (fp != NULL) { |
| 19305 | if (fread(buf, 1, len, fp) == len) success = true; |
| 19306 | fclose(fp); |
| 19307 | } |
| 19308 | #endif |
| 19309 | // If everything above did not work, fallback to a pseudo random generator |
| 19310 | if (success == false) { |
| 19311 | MG_ERROR(("Weak RNG: using rand()")); |
| 19312 | while (len--) *p++ = (unsigned char) (rand() & 255); |
| 19313 | } |
| 19314 | return success; |
| 19315 | } |
| 19316 | #endif |
| 19317 | |
| 19318 | char *mg_random_str(char *buf, size_t len) { |
| 19319 | size_t i; |
| 19320 | mg_random(buf, len); |
| 19321 | for (i = 0; i < len; i++) { |
| 19322 | uint8_t c = ((uint8_t *) buf)[i] % 62U; |
| 19323 | buf[i] = i == len - 1 ? (char) '\0' // 0-terminate last byte |
| 19324 | : c < 26 ? (char) ('a' + c) // lowercase |
| 19325 | : c < 52 ? (char) ('A' + c - 26) // uppercase |
| 19326 | : (char) ('0' + c - 52); // numeric |
| 19327 | } |
| 19328 | return buf; |
| 19329 | } |
| 19330 | |
| 19331 | uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len) { |
| 19332 | static const uint32_t crclut[16] = { |
| 19333 | // table for polynomial 0xEDB88320 (reflected) |
| 19334 | 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4, |
| 19335 | 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C, |
| 19336 | 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C}; |
| 19337 | crc = ~crc; |
| 19338 | while (len--) { |
| 19339 | uint8_t b = *(uint8_t *) buf++; |
| 19340 | crc = crclut[(crc ^ b) & 0x0F] ^ (crc >> 4); |
| 19341 | crc = crclut[(crc ^ (b >> 4)) & 0x0F] ^ (crc >> 4); |
| 19342 | } |
| 19343 | return ~crc; |
| 19344 | } |
| 19345 | |
| 19346 | static int isbyte(int n) { |
| 19347 | return n >= 0 && n <= 255; |
| 19348 | } |
| 19349 | |
| 19350 | static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) { |
| 19351 | int n, a, b, c, d, slash = 32, len = 0; |
| 19352 | if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 || |
| 19353 | sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) && |
| 19354 | isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 && |
| 19355 | slash < 33) { |
| 19356 | len = n; |
| 19357 | *net = ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | |
| 19358 | (uint32_t) d; |
| 19359 | *mask = slash ? (uint32_t) (0xffffffffU << (32 - slash)) : (uint32_t) 0; |
| 19360 | } |
| 19361 | return len; |
| 19362 | } |
| 19363 | |
| 19364 | int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip) { |
| 19365 | struct mg_str entry; |
| 19366 | int allowed = acl.len == 0 ? '+' : '-'; // If any ACL is set, deny by default |
| 19367 | uint32_t remote_ip4; |
| 19368 | if (remote_ip->is_ip6) { |
| 19369 | return -1; // TODO(): handle IPv6 ACL and addresses |
| 19370 | } else { // IPv4 |
| 19371 | memcpy((void *) &remote_ip4, remote_ip->ip, sizeof(remote_ip4)); |
| 19372 | while (mg_span(acl, &entry, &acl, ',')) { |
| 19373 | uint32_t net, mask; |
| 19374 | if (entry.buf[0] != '+' && entry.buf[0] != '-') return -1; |
| 19375 | if (parse_net(&entry.buf[1], &net, &mask) == 0) return -2; |
| 19376 | if ((mg_ntohl(remote_ip4) & mask) == net) allowed = entry.buf[0]; |
| 19377 | } |
| 19378 | } |
| 19379 | return allowed == '+'; |
| 19380 | } |
| 19381 | |
| 19382 | bool mg_path_is_sane(const struct mg_str path) { |
| 19383 | const char *s = path.buf; |
| 19384 | size_t n = path.len; |
| 19385 | if (path.buf[0] == '.' && path.buf[1] == '.') return false; // Starts with .. |
| 19386 | for (; s[0] != '\0' && n > 0; s++, n--) { |
| 19387 | if ((s[0] == '/' || s[0] == '\\') && n >= 2) { // Subdir? |
| 19388 | if (s[1] == '.' && s[2] == '.') return false; // Starts with .. |
| 19389 | } |
| 19390 | } |
| 19391 | return true; |
| 19392 | } |
| 19393 | |
| 19394 | #if MG_ENABLE_CUSTOM_MILLIS |
| 19395 | #else |
| 19396 | uint64_t mg_millis(void) { |
| 19397 | #if MG_ARCH == MG_ARCH_WIN32 |
| 19398 | return GetTickCount(); |
| 19399 | #elif MG_ARCH == MG_ARCH_PICOSDK |
| 19400 | return time_us_64() / 1000; |
| 19401 | #elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_ESP32 || \ |
| 19402 | MG_ARCH == MG_ARCH_FREERTOS |
| 19403 | return xTaskGetTickCount() * portTICK_PERIOD_MS; |
| 19404 | #elif MG_ARCH == MG_ARCH_AZURERTOS |
| 19405 | return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND); |
| 19406 | #elif MG_ARCH == MG_ARCH_TIRTOS |
| 19407 | return (uint64_t) Clock_getTicks(); |
| 19408 | #elif MG_ARCH == MG_ARCH_ZEPHYR |
| 19409 | return (uint64_t) k_uptime_get(); |
| 19410 | #elif MG_ARCH == MG_ARCH_CMSIS_RTOS1 |
| 19411 | return (uint64_t) rt_time_get(); |
| 19412 | #elif MG_ARCH == MG_ARCH_CMSIS_RTOS2 |
| 19413 | return (uint64_t) ((osKernelGetTickCount() * 1000) / osKernelGetTickFreq()); |
| 19414 | #elif MG_ARCH == MG_ARCH_RTTHREAD |
| 19415 | return (uint64_t) ((rt_tick_get() * 1000) / RT_TICK_PER_SECOND); |
| 19416 | #elif MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__) |
| 19417 | // Apple CLOCK_MONOTONIC_RAW is equivalent to CLOCK_BOOTTIME on linux |
| 19418 | // Apple CLOCK_UPTIME_RAW is equivalent to CLOCK_MONOTONIC_RAW on linux |
| 19419 | return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000; |
| 19420 | #elif MG_ARCH == MG_ARCH_UNIX |
| 19421 | struct timespec ts = {0, 0}; |
| 19422 | // See #1615 - prefer monotonic clock |
| 19423 | #if defined(CLOCK_MONOTONIC_RAW) |
| 19424 | // Raw hardware-based time that is not subject to NTP adjustment |
| 19425 | clock_gettime(CLOCK_MONOTONIC_RAW, &ts); |
| 19426 | #elif defined(CLOCK_MONOTONIC) |
| 19427 | // Affected by the incremental adjustments performed by adjtime and NTP |
| 19428 | clock_gettime(CLOCK_MONOTONIC, &ts); |
| 19429 | #else |
| 19430 | // Affected by discontinuous jumps in the system time and by the incremental |
| 19431 | // adjustments performed by adjtime and NTP |
| 19432 | clock_gettime(CLOCK_REALTIME, &ts); |
| 19433 | #endif |
| 19434 | return ((uint64_t) ts.tv_sec * 1000 + (uint64_t) ts.tv_nsec / 1000000); |
| 19435 | #elif defined(ARDUINO) |
| 19436 | return (uint64_t) millis(); |
| 19437 | #else |
| 19438 | return (uint64_t) (time(NULL) * 1000); |
| 19439 | #endif |
| 19440 | } |
| 19441 | #endif |
| 19442 | |
| 19443 | // network format equates big endian order |
| 19444 | uint16_t mg_ntohs(uint16_t net) { |
| 19445 | return MG_LOAD_BE16(&net); |
| 19446 | } |
| 19447 | |
| 19448 | uint32_t mg_ntohl(uint32_t net) { |
| 19449 | return MG_LOAD_BE32(&net); |
| 19450 | } |
| 19451 | |
| 19452 | void mg_delayms(unsigned int ms) { |
| 19453 | uint64_t to = mg_millis() + ms + 1; |
| 19454 | while (mg_millis() < to) (void) 0; |
| 19455 | } |
| 19456 | |
| 19457 | #ifdef MG_ENABLE_LINES |
| 19458 | #line 1 "src/wifi_dummy.c" |
| 19459 | #endif |
| 19460 | |
| 19461 | |
| 19462 | #if (!defined(MG_ENABLE_DRIVER_PICO_W) || !MG_ENABLE_DRIVER_PICO_W) && \ |
| 19463 | (!defined(MG_ENABLE_DRIVER_CYW) || !MG_ENABLE_DRIVER_CYW) |
| 19464 | |
| 19465 | bool mg_wifi_scan(void) { |
| 19466 | MG_ERROR(("No Wi-Fi driver enabled")); |
| 19467 | return false; |
| 19468 | } |
| 19469 | |
| 19470 | bool mg_wifi_connect(char *ssid, char *pass) { |
| 19471 | (void) ssid; |
| 19472 | (void) pass; |
| 19473 | return mg_wifi_scan(); |
| 19474 | } |
| 19475 | |
| 19476 | bool mg_wifi_disconnect(void) { |
| 19477 | return mg_wifi_scan(); |
| 19478 | } |
| 19479 | |
| 19480 | bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { |
| 19481 | (void) ssid; |
| 19482 | (void) pass; |
| 19483 | (void) channel; |
| 19484 | return mg_wifi_scan(); |
| 19485 | } |
| 19486 | |
| 19487 | bool mg_wifi_ap_stop(void) { |
| 19488 | return mg_wifi_scan(); |
| 19489 | } |
| 19490 | |
| 19491 | #endif |
| 19492 | |
| 19493 | #ifdef MG_ENABLE_LINES |
| 19494 | #line 1 "src/ws.c" |
| 19495 | #endif |
| 19496 | |
| 19497 | |
| 19498 | |
| 19499 | |
| 19500 | |
| 19501 | |
| 19502 | |
| 19503 | |
| 19504 | |
| 19505 | |
| 19506 | |
| 19507 | struct ws_msg { |
| 19508 | uint8_t flags; |
| 19509 | size_t header_len; |
| 19510 | size_t data_len; |
| 19511 | }; |
| 19512 | |
| 19513 | size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt, |
| 19514 | va_list *ap) { |
| 19515 | size_t len = c->send.len; |
| 19516 | size_t n = mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); |
| 19517 | mg_ws_wrap(c, c->send.len - len, op); |
| 19518 | return n; |
| 19519 | } |
| 19520 | |
| 19521 | size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...) { |
| 19522 | size_t len = 0; |
| 19523 | va_list ap; |
| 19524 | va_start(ap, fmt); |
| 19525 | len = mg_ws_vprintf(c, op, fmt, &ap); |
| 19526 | va_end(ap); |
| 19527 | return len; |
| 19528 | } |
| 19529 | |
| 19530 | static void ws_handshake(struct mg_connection *c, const struct mg_str *wskey, |
| 19531 | const struct mg_str *wsproto, const char *fmt, |
| 19532 | va_list *ap) { |
| 19533 | const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
| 19534 | unsigned char sha[20], b64_sha[30]; |
| 19535 | |
| 19536 | mg_sha1_ctx sha_ctx; |
| 19537 | mg_sha1_init(&sha_ctx); |
| 19538 | mg_sha1_update(&sha_ctx, (unsigned char *) wskey->buf, wskey->len); |
| 19539 | mg_sha1_update(&sha_ctx, (unsigned char *) magic, 36); |
| 19540 | mg_sha1_final(sha, &sha_ctx); |
| 19541 | mg_base64_encode(sha, sizeof(sha), (char *) b64_sha, sizeof(b64_sha)); |
| 19542 | mg_xprintf(mg_pfn_iobuf, &c->send, |
| 19543 | "HTTP/1.1 101 Switching Protocols\r\n" |
| 19544 | "Upgrade: websocket\r\n" |
| 19545 | "Connection: Upgrade\r\n" |
| 19546 | "Sec-WebSocket-Accept: %s\r\n", |
| 19547 | b64_sha); |
| 19548 | if (fmt != NULL) mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); |
| 19549 | if (wsproto != NULL) { |
| 19550 | mg_printf(c, "Sec-WebSocket-Protocol: %.*s\r\n", (int) wsproto->len, |
| 19551 | wsproto->buf); |
| 19552 | } |
| 19553 | mg_send(c, "\r\n", 2); |
| 19554 | } |
| 19555 | |
| 19556 | static uint32_t be32(const uint8_t *p) { |
| 19557 | return (((uint32_t) p[3]) << 0) | (((uint32_t) p[2]) << 8) | |
| 19558 | (((uint32_t) p[1]) << 16) | (((uint32_t) p[0]) << 24); |
| 19559 | } |
| 19560 | |
| 19561 | static size_t ws_process(uint8_t *buf, size_t len, struct ws_msg *msg) { |
| 19562 | size_t i, n = 0, mask_len = 0; |
| 19563 | memset(msg, 0, sizeof(*msg)); |
| 19564 | if (len >= 2) { |
| 19565 | n = buf[1] & 0x7f; // Frame length |
| 19566 | mask_len = buf[1] & 128 ? 4 : 0; // last bit is a mask bit |
| 19567 | msg->flags = buf[0]; |
| 19568 | if (n < 126 && len >= mask_len) { |
| 19569 | msg->data_len = n; |
| 19570 | msg->header_len = 2 + mask_len; |
| 19571 | } else if (n == 126 && len >= 4 + mask_len) { |
| 19572 | msg->header_len = 4 + mask_len; |
| 19573 | msg->data_len = (((size_t) buf[2]) << 8) | buf[3]; |
| 19574 | } else if (len >= 10 + mask_len) { |
| 19575 | msg->header_len = 10 + mask_len; |
| 19576 | msg->data_len = |
| 19577 | (size_t) (((uint64_t) be32(buf + 2) << 32) + be32(buf + 6)); |
| 19578 | } |
| 19579 | } |
| 19580 | // Sanity check, and integer overflow protection for the boundary check below |
| 19581 | // data_len should not be larger than 1 Gb |
| 19582 | if (msg->data_len > 1024 * 1024 * 1024) return 0; |
| 19583 | if (msg->header_len + msg->data_len > len) return 0; |
| 19584 | if (mask_len > 0) { |
| 19585 | uint8_t *p = buf + msg->header_len, *m = p - mask_len; |
| 19586 | for (i = 0; i < msg->data_len; i++) p[i] ^= m[i & 3]; |
| 19587 | } |
| 19588 | return msg->header_len + msg->data_len; |
| 19589 | } |
| 19590 | |
| 19591 | static size_t mkhdr(size_t len, int op, bool is_client, uint8_t *buf) { |
| 19592 | size_t n = 0; |
| 19593 | buf[0] = (uint8_t) (op | 128); |
| 19594 | if (len < 126) { |
| 19595 | buf[1] = (unsigned char) len; |
| 19596 | n = 2; |
| 19597 | } else if (len < 65536) { |
| 19598 | uint16_t tmp = mg_htons((uint16_t) len); |
| 19599 | buf[1] = 126; |
| 19600 | memcpy(&buf[2], &tmp, sizeof(tmp)); |
| 19601 | n = 4; |
| 19602 | } else { |
| 19603 | uint32_t tmp; |
| 19604 | buf[1] = 127; |
| 19605 | tmp = mg_htonl((uint32_t) (((uint64_t) len) >> 32)); |
| 19606 | memcpy(&buf[2], &tmp, sizeof(tmp)); |
| 19607 | tmp = mg_htonl((uint32_t) (len & 0xffffffffU)); |
| 19608 | memcpy(&buf[6], &tmp, sizeof(tmp)); |
| 19609 | n = 10; |
| 19610 | } |
| 19611 | if (is_client) { |
| 19612 | buf[1] |= 1 << 7; // Set masking flag |
| 19613 | mg_random(&buf[n], 4); |
| 19614 | n += 4; |
| 19615 | } |
| 19616 | return n; |
| 19617 | } |
| 19618 | |
| 19619 | static void mg_ws_mask(struct mg_connection *c, size_t len) { |
| 19620 | if (c->is_client && c->send.buf != NULL) { |
| 19621 | size_t i; |
| 19622 | uint8_t *p = c->send.buf + c->send.len - len, *mask = p - 4; |
| 19623 | for (i = 0; i < len; i++) p[i] ^= mask[i & 3]; |
| 19624 | } |
| 19625 | } |
| 19626 | |
| 19627 | size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len, |
| 19628 | int op) { |
| 19629 | uint8_t header[14]; |
| 19630 | size_t header_len = mkhdr(len, op, c->is_client, header); |
| 19631 | if (!mg_send(c, header, header_len)) return 0; |
| 19632 | if (!mg_send(c, buf, len)) return header_len; |
| 19633 | MG_VERBOSE(("WS out: %d [%.*s]", (int) len, (int) len, buf)); |
| 19634 | mg_ws_mask(c, len); |
| 19635 | return header_len + len; |
| 19636 | } |
| 19637 | |
| 19638 | static bool mg_ws_client_handshake(struct mg_connection *c) { |
| 19639 | int n = mg_http_get_request_len(c->recv.buf, c->recv.len); |
| 19640 | if (n < 0) { |
| 19641 | mg_error(c, "not http"); // Some just, not an HTTP request |
| 19642 | } else if (n > 0) { |
| 19643 | if (n < 15 || memcmp(c->recv.buf + 9, "101", 3) != 0) { |
| 19644 | mg_error(c, "ws handshake error"); |
| 19645 | } else { |
| 19646 | struct mg_http_message hm; |
| 19647 | if (mg_http_parse((char *) c->recv.buf, c->recv.len, &hm)) { |
| 19648 | c->is_websocket = 1; |
| 19649 | mg_call(c, MG_EV_WS_OPEN, &hm); |
| 19650 | } else { |
| 19651 | mg_error(c, "ws handshake error"); |
| 19652 | } |
| 19653 | } |
| 19654 | mg_iobuf_del(&c->recv, 0, (size_t) n); |
| 19655 | } else { |
| 19656 | return true; // Request is not yet received, quit event handler |
| 19657 | } |
| 19658 | return false; // Continue event handler |
| 19659 | } |
| 19660 | |
| 19661 | static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) { |
| 19662 | struct ws_msg msg; |
| 19663 | size_t ofs = (size_t) c->pfn_data; |
| 19664 | |
| 19665 | // assert(ofs < c->recv.len); |
| 19666 | if (ev == MG_EV_READ) { |
| 19667 | if (c->is_client && !c->is_websocket && mg_ws_client_handshake(c)) return; |
| 19668 | |
| 19669 | while (ws_process(c->recv.buf + ofs, c->recv.len - ofs, &msg) > 0) { |
| 19670 | char *s = (char *) c->recv.buf + ofs + msg.header_len; |
| 19671 | struct mg_ws_message m = {{s, msg.data_len}, msg.flags}; |
| 19672 | size_t len = msg.header_len + msg.data_len; |
| 19673 | uint8_t final = msg.flags & 128, op = msg.flags & 15; |
| 19674 | // MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op, |
| 19675 | // (int) m.data.len, (int) m.data.len, m.data.buf)); |
| 19676 | switch (op) { |
| 19677 | case WEBSOCKET_OP_CONTINUE: |
| 19678 | mg_call(c, MG_EV_WS_CTL, &m); |
| 19679 | break; |
| 19680 | case WEBSOCKET_OP_PING: |
| 19681 | MG_DEBUG(("%s", "WS PONG")); |
| 19682 | mg_ws_send(c, s, msg.data_len, WEBSOCKET_OP_PONG); |
| 19683 | mg_call(c, MG_EV_WS_CTL, &m); |
| 19684 | break; |
| 19685 | case WEBSOCKET_OP_PONG: |
| 19686 | mg_call(c, MG_EV_WS_CTL, &m); |
| 19687 | break; |
| 19688 | case WEBSOCKET_OP_TEXT: |
| 19689 | case WEBSOCKET_OP_BINARY: |
| 19690 | if (final) mg_call(c, MG_EV_WS_MSG, &m); |
| 19691 | break; |
| 19692 | case WEBSOCKET_OP_CLOSE: |
| 19693 | MG_DEBUG(("%lu WS CLOSE", c->id)); |
| 19694 | mg_call(c, MG_EV_WS_CTL, &m); |
| 19695 | // Echo the payload of the received CLOSE message back to the sender |
| 19696 | mg_ws_send(c, m.data.buf, m.data.len, WEBSOCKET_OP_CLOSE); |
| 19697 | c->is_draining = 1; |
| 19698 | break; |
| 19699 | default: |
| 19700 | // Per RFC6455, close conn when an unknown op is recvd |
| 19701 | mg_error(c, "unknown WS op %d", op); |
| 19702 | break; |
| 19703 | } |
| 19704 | |
| 19705 | // Handle fragmented frames: strip header, keep in c->recv |
| 19706 | if (final == 0 || op == 0) { |
| 19707 | if (op) ofs++, len--, msg.header_len--; // First frame |
| 19708 | mg_iobuf_del(&c->recv, ofs, msg.header_len); // Strip header |
| 19709 | len -= msg.header_len; |
| 19710 | ofs += len; |
| 19711 | c->pfn_data = (void *) ofs; |
| 19712 | // MG_INFO(("FRAG %d [%.*s]", (int) ofs, (int) ofs, c->recv.buf)); |
| 19713 | } |
| 19714 | // Remove non-fragmented frame |
| 19715 | if (final && op) mg_iobuf_del(&c->recv, ofs, len); |
| 19716 | // Last chunk of the fragmented frame |
| 19717 | if (final && !op) { |
| 19718 | m.flags = c->recv.buf[0]; |
| 19719 | m.data = mg_str_n((char *) &c->recv.buf[1], (size_t) (ofs - 1)); |
| 19720 | mg_call(c, MG_EV_WS_MSG, &m); |
| 19721 | mg_iobuf_del(&c->recv, 0, ofs); |
| 19722 | ofs = 0; |
| 19723 | c->pfn_data = NULL; |
| 19724 | } |
| 19725 | } |
| 19726 | } |
| 19727 | (void) ev_data; |
| 19728 | } |
| 19729 | |
| 19730 | struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url, |
| 19731 | mg_event_handler_t fn, void *fn_data, |
| 19732 | const char *fmt, ...) { |
| 19733 | struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); |
| 19734 | if (c != NULL) { |
| 19735 | char nonce[16], key[30]; |
| 19736 | struct mg_str host = mg_url_host(url); |
| 19737 | mg_random(nonce, sizeof(nonce)); |
| 19738 | mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key, sizeof(key)); |
| 19739 | mg_xprintf(mg_pfn_iobuf, &c->send, |
| 19740 | "GET %s HTTP/1.1\r\n" |
| 19741 | "Upgrade: websocket\r\n" |
| 19742 | "Host: %.*s\r\n" |
| 19743 | "Connection: Upgrade\r\n" |
| 19744 | "Sec-WebSocket-Version: 13\r\n" |
| 19745 | "Sec-WebSocket-Key: %s\r\n", |
| 19746 | mg_url_uri(url), (int) host.len, host.buf, key); |
| 19747 | if (fmt != NULL) { |
| 19748 | va_list ap; |
| 19749 | va_start(ap, fmt); |
| 19750 | mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap); |
| 19751 | va_end(ap); |
| 19752 | } |
| 19753 | mg_xprintf(mg_pfn_iobuf, &c->send, "\r\n"); |
| 19754 | c->pfn = mg_ws_cb; |
| 19755 | c->pfn_data = NULL; |
| 19756 | } |
| 19757 | return c; |
| 19758 | } |
| 19759 | |
| 19760 | void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm, |
| 19761 | const char *fmt, ...) { |
| 19762 | struct mg_str *wskey = mg_http_get_header(hm, "Sec-WebSocket-Key"); |
| 19763 | c->pfn = mg_ws_cb; |
| 19764 | c->pfn_data = NULL; |
| 19765 | if (wskey == NULL) { |
| 19766 | mg_http_reply(c, 426, "", "WS upgrade expected\n"); |
| 19767 | c->is_draining = 1; |
| 19768 | } else { |
| 19769 | struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol"); |
| 19770 | va_list ap; |
| 19771 | va_start(ap, fmt); |
| 19772 | ws_handshake(c, wskey, wsproto, fmt, &ap); |
| 19773 | va_end(ap); |
| 19774 | c->is_websocket = 1; |
| 19775 | c->is_resp = 0; |
| 19776 | mg_call(c, MG_EV_WS_OPEN, hm); |
| 19777 | } |
| 19778 | } |
| 19779 | |
| 19780 | size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op) { |
| 19781 | uint8_t header[14], *p; |
| 19782 | size_t header_len = mkhdr(len, op, c->is_client, header); |
| 19783 | |
| 19784 | // NOTE: order of operations is important! |
| 19785 | if (mg_iobuf_add(&c->send, c->send.len, NULL, header_len) != 0) { |
| 19786 | p = &c->send.buf[c->send.len - len]; // p points to data |
| 19787 | memmove(p, p - header_len, len); // Shift data |
| 19788 | memcpy(p - header_len, header, header_len); // Prepend header |
| 19789 | mg_ws_mask(c, len); // Mask data |
| 19790 | } |
| 19791 | return c->send.len; |
| 19792 | } |
| 19793 | |
| 19794 | #ifdef MG_ENABLE_LINES |
| 19795 | #line 1 "src/drivers/cmsis.c" |
| 19796 | #endif |
| 19797 | // https://arm-software.github.io/CMSIS_5/Driver/html/index.html |
| 19798 | |
| 19799 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CMSIS) && MG_ENABLE_DRIVER_CMSIS |
| 19800 | |
| 19801 | |
| 19802 | |
| 19803 | |
| 19804 | |
| 19805 | extern ARM_DRIVER_ETH_MAC Driver_ETH_MAC0; |
| 19806 | extern ARM_DRIVER_ETH_PHY Driver_ETH_PHY0; |
| 19807 | |
| 19808 | static struct mg_tcpip_if *s_ifp; |
| 19809 | |
| 19810 | static void mac_cb(uint32_t); |
| 19811 | static bool cmsis_init(struct mg_tcpip_if *); |
| 19812 | static bool cmsis_poll(struct mg_tcpip_if *, bool); |
| 19813 | static size_t cmsis_tx(const void *, size_t, struct mg_tcpip_if *); |
| 19814 | static size_t cmsis_rx(void *, size_t, struct mg_tcpip_if *); |
| 19815 | |
| 19816 | struct mg_tcpip_driver mg_tcpip_driver_cmsis = {cmsis_init, cmsis_tx, NULL, |
| 19817 | cmsis_poll}; |
| 19818 | |
| 19819 | static bool cmsis_init(struct mg_tcpip_if *ifp) { |
| 19820 | ARM_ETH_MAC_ADDR addr; |
| 19821 | s_ifp = ifp; |
| 19822 | |
| 19823 | ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; |
| 19824 | ARM_DRIVER_ETH_PHY *phy = &Driver_ETH_PHY0; |
| 19825 | ARM_ETH_MAC_CAPABILITIES cap = mac->GetCapabilities(); |
| 19826 | if (mac->Initialize(mac_cb) != ARM_DRIVER_OK) return false; |
| 19827 | if (phy->Initialize(mac->PHY_Read, mac->PHY_Write) != ARM_DRIVER_OK) |
| 19828 | return false; |
| 19829 | if (cap.event_rx_frame == 0) // polled mode driver |
| 19830 | mg_tcpip_driver_cmsis.rx = cmsis_rx; |
| 19831 | mac->PowerControl(ARM_POWER_FULL); |
| 19832 | if (cap.mac_address) { // driver provides MAC address |
| 19833 | mac->GetMacAddress(&addr); |
| 19834 | memcpy(ifp->mac, &addr, sizeof(ifp->mac)); |
| 19835 | } else { // we provide MAC address |
| 19836 | memcpy(&addr, ifp->mac, sizeof(addr)); |
| 19837 | mac->SetMacAddress(&addr); |
| 19838 | } |
| 19839 | phy->PowerControl(ARM_POWER_FULL); |
| 19840 | phy->SetInterface(cap.media_interface); |
| 19841 | phy->SetMode(ARM_ETH_PHY_AUTO_NEGOTIATE); |
| 19842 | return true; |
| 19843 | } |
| 19844 | |
| 19845 | static size_t cmsis_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) { |
| 19846 | ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; |
| 19847 | if (mac->SendFrame(buf, (uint32_t) len, 0) != ARM_DRIVER_OK) { |
| 19848 | ifp->nerr++; |
| 19849 | return 0; |
| 19850 | } |
| 19851 | ifp->nsent++; |
| 19852 | return len; |
| 19853 | } |
| 19854 | |
| 19855 | static void cmsis_update_hash_table(struct mg_tcpip_if *ifp) { |
| 19856 | // TODO(): read database, rebuild hash table |
| 19857 | ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; |
| 19858 | ARM_ETH_MAC_ADDR addr; |
| 19859 | memcpy(&addr, mcast_addr, sizeof(addr)); |
| 19860 | mac->SetAddressFilter(&addr, 1); |
| 19861 | (void) ifp; |
| 19862 | } |
| 19863 | |
| 19864 | static bool cmsis_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 19865 | if (ifp->update_mac_hash_table) { |
| 19866 | cmsis_update_hash_table(ifp); |
| 19867 | ifp->update_mac_hash_table = false; |
| 19868 | } |
| 19869 | if (!s1) return false; |
| 19870 | ARM_DRIVER_ETH_PHY *phy = &Driver_ETH_PHY0; |
| 19871 | ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; |
| 19872 | bool up = (phy->GetLinkState() == ARM_ETH_LINK_UP) ? 1 : 0; // link state |
| 19873 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // just went up |
| 19874 | ARM_ETH_LINK_INFO st = phy->GetLinkInfo(); |
| 19875 | mac->Control(ARM_ETH_MAC_CONFIGURE, |
| 19876 | (st.speed << ARM_ETH_MAC_SPEED_Pos) | |
| 19877 | (st.duplex << ARM_ETH_MAC_DUPLEX_Pos) | |
| 19878 | ARM_ETH_MAC_ADDRESS_BROADCAST); |
| 19879 | MG_DEBUG(("Link is %uM %s-duplex", |
| 19880 | (st.speed == 2) ? 1000 |
| 19881 | : st.speed ? 100 |
| 19882 | : 10, |
| 19883 | st.duplex ? "full" : "half")); |
| 19884 | mac->Control(ARM_ETH_MAC_CONTROL_TX, 1); |
| 19885 | mac->Control(ARM_ETH_MAC_CONTROL_RX, 1); |
| 19886 | } else if ((ifp->state != MG_TCPIP_STATE_DOWN) && !up) { // just went down |
| 19887 | mac->Control(ARM_ETH_MAC_FLUSH, |
| 19888 | ARM_ETH_MAC_FLUSH_TX | ARM_ETH_MAC_FLUSH_RX); |
| 19889 | mac->Control(ARM_ETH_MAC_CONTROL_TX, 0); |
| 19890 | mac->Control(ARM_ETH_MAC_CONTROL_RX, 0); |
| 19891 | } |
| 19892 | return up; |
| 19893 | } |
| 19894 | |
| 19895 | static void mac_cb(uint32_t ev) { |
| 19896 | if ((ev & ARM_ETH_MAC_EVENT_RX_FRAME) == 0) return; |
| 19897 | ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; |
| 19898 | uint32_t len = mac->GetRxFrameSize(); // CRC already stripped |
| 19899 | if (len >= 60 && len <= 1518) { // proper frame |
| 19900 | char *p; |
| 19901 | if (mg_queue_book(&s_ifp->recv_queue, &p, len) >= len) { // have room |
| 19902 | if ((len = mac->ReadFrame((uint8_t *) p, len)) > 0) { // copy succeeds |
| 19903 | mg_queue_add(&s_ifp->recv_queue, len); |
| 19904 | s_ifp->nrecv++; |
| 19905 | } |
| 19906 | return; |
| 19907 | } |
| 19908 | s_ifp->ndrop++; |
| 19909 | } |
| 19910 | mac->ReadFrame(NULL, 0); // otherwise, discard |
| 19911 | } |
| 19912 | |
| 19913 | static size_t cmsis_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) { |
| 19914 | ARM_DRIVER_ETH_MAC *mac = &Driver_ETH_MAC0; |
| 19915 | uint32_t len = mac->GetRxFrameSize(); // CRC already stripped |
| 19916 | if (len >= 60 && len <= 1518 && |
| 19917 | ((len = mac->ReadFrame(buf, (uint32_t) buflen)) > 0)) |
| 19918 | return len; |
| 19919 | if (len > 0) mac->ReadFrame(NULL, 0); // discard bad frames |
| 19920 | (void) ifp; |
| 19921 | return 0; |
| 19922 | } |
| 19923 | |
| 19924 | #endif |
| 19925 | |
| 19926 | #ifdef MG_ENABLE_LINES |
| 19927 | #line 1 "src/drivers/cyw.c" |
| 19928 | #endif |
| 19929 | |
| 19930 | |
| 19931 | |
| 19932 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CYW) && MG_ENABLE_DRIVER_CYW |
| 19933 | |
| 19934 | |
| 19935 | static struct mg_tcpip_if *s_ifp; |
| 19936 | static bool s_link, s_auth, s_join; |
| 19937 | |
| 19938 | static bool cyw_init(uint8_t *mac); |
| 19939 | static void cyw_poll(void); |
| 19940 | |
| 19941 | static bool mg_tcpip_driver_cyw_init(struct mg_tcpip_if *ifp) { |
| 19942 | struct mg_tcpip_driver_cyw_data *d = |
| 19943 | (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; |
| 19944 | if (MG_BIG_ENDIAN) { |
| 19945 | MG_ERROR(("Big-endian host")); |
| 19946 | return false; |
| 19947 | } |
| 19948 | s_ifp = ifp; |
| 19949 | s_link = s_auth = s_join = false; |
| 19950 | if (!cyw_init(ifp->mac)) return false; |
| 19951 | |
| 19952 | if (d->apmode) { |
| 19953 | MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel)); |
| 19954 | return mg_wifi_ap_start(d->apssid, d->appass, d->apchannel); |
| 19955 | } else if (d->ssid != NULL && d->pass != NULL) { |
| 19956 | MG_DEBUG(("Connecting to '%s'", d->ssid)); |
| 19957 | return mg_wifi_connect(d->ssid, d->pass); |
| 19958 | } |
| 19959 | return true; |
| 19960 | } |
| 19961 | |
| 19962 | static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len); |
| 19963 | size_t mg_tcpip_driver_cyw_output(const void *buf, size_t len, |
| 19964 | struct mg_tcpip_if *ifp) { |
| 19965 | struct mg_tcpip_driver_cyw_data *d = |
| 19966 | (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; |
| 19967 | return mg_cyw_tx(d->apmode ? 1 : 0, (void *) buf, len) >= len ? len : 0; |
| 19968 | } |
| 19969 | |
| 19970 | static bool mg_tcpip_driver_cyw_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 19971 | cyw_poll(); |
| 19972 | if (!s1) return false; |
| 19973 | struct mg_tcpip_driver_cyw_data *d = |
| 19974 | (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; |
| 19975 | return d->apmode ? s_link : s_link && s_auth && s_join; |
| 19976 | } |
| 19977 | |
| 19978 | struct mg_tcpip_driver mg_tcpip_driver_cyw = {mg_tcpip_driver_cyw_init, |
| 19979 | mg_tcpip_driver_cyw_output, NULL, |
| 19980 | mg_tcpip_driver_cyw_poll}; |
| 19981 | |
| 19982 | // - DS: |
| 19983 | // https://www.mouser.com/datasheet/2/196/Infineon_CYW43439_DataSheet_v03_00_EN-3074791.pdf |
| 19984 | // - WHD: https://github.com/Infineon/wifi-host-driver |
| 19985 | // |
| 19986 | // | e <-- event data |
| 19987 | // |----- |
| 19988 | // net | vnd <-- network (TCP/IP) | vendor header (Broadcom (bcm)) |
| 19989 | // -----|----- |
| 19990 | // IOCTL | ETH | ETH <-- IOCTL/IOVAR: chip control | ETH: Ethernet header |
| 19991 | // -------|-----|----- |
| 19992 | // CDC | BDC | BDC |
| 19993 | // ------- ----- ----- |
| 19994 | // SDPCM <-- includes SDIO bus arbitration, not used in SPI |
| 19995 | // ------------------- |
| 19996 | // SPI | SDIO <-- padded to 32-bit | 64-bytes |
| 19997 | // |
| 19998 | // - SDPCM has 3 channels (control, data, and asynchronous data) |
| 19999 | // - SPI (and SDIO) has 4 "functions", F0 to F3, to access different |
| 20000 | // blocks in the chip, like the SPI/SDIO controller, chip backplane, and 2 DMA |
| 20001 | // I/Os; these are usually handled by SDPCM but we need to explicitly access |
| 20002 | // the I/O controller and chip backplane during initialization |
| 20003 | |
| 20004 | // Processor core firmware is loaded to TCM RAM, along with module-dependent |
| 20005 | // (hardware design) NVRAM data, via the chip backplane access through the bus |
| 20006 | // Once the chip has been initialized, information regarding regulatory |
| 20007 | // constraints (CLM blob, “Country Locale Matrix”), is loaded as an IOVAR. This |
| 20008 | // is tied to the module being certified, hence it is also module-dependent. |
| 20009 | // - Result: chip firmware + module NVRAM data + module CLM blob |
| 20010 | |
| 20011 | #pragma pack(push, 1) |
| 20012 | // all little endian |
| 20013 | |
| 20014 | struct cdc_hdr { |
| 20015 | uint32_t cmd; // ioctl command value |
| 20016 | uint16_t olen; // output buflen |
| 20017 | uint16_t ilen; // input buflen (excludes header) |
| 20018 | uint32_t flags; |
| 20019 | uint32_t status; |
| 20020 | }; |
| 20021 | |
| 20022 | struct bdc_hdr { |
| 20023 | uint8_t flags; // Flags |
| 20024 | uint8_t priority; // 802.1d Priority (low 3 bits) |
| 20025 | uint8_t flags2; |
| 20026 | uint8_t data_offset; // Offset from end of BDC header to packet data, in |
| 20027 | // 4-uint8_t words. Leaves room for optional headers. |
| 20028 | }; |
| 20029 | |
| 20030 | struct sdpcm_sw_hdr { |
| 20031 | uint8_t sequence; // Sequence number of pkt |
| 20032 | uint8_t channel_and_flags; // IOCTL/IOVAR or User Data or Event |
| 20033 | uint8_t next_length; |
| 20034 | uint8_t header_length; // Offset to BDC or CDC header |
| 20035 | uint8_t wireless_flow_control; |
| 20036 | uint8_t bus_data_credit; // Credit from WLAN Chip |
| 20037 | uint8_t _reserved[2]; |
| 20038 | }; |
| 20039 | |
| 20040 | struct sdpcm_hdr { |
| 20041 | uint16_t len; |
| 20042 | uint16_t _len; // ~len |
| 20043 | struct sdpcm_sw_hdr sw_hdr; |
| 20044 | }; |
| 20045 | |
| 20046 | struct data_hdr { |
| 20047 | struct sdpcm_hdr sdpcm; |
| 20048 | uint8_t pad[2]; |
| 20049 | struct bdc_hdr bdc; |
| 20050 | }; |
| 20051 | |
| 20052 | // gSPI, DS 4.2.1 Fig.12, 2-bit field |
| 20053 | #define CYW_SD_FUNC_BUS 0 // F0 |
| 20054 | #define CYW_SD_FUNC_CHIP 1 // F1 |
| 20055 | #define CYW_SD_FUNC_WLAN 2 // F2 |
| 20056 | |
| 20057 | #define CYW_SDPCM_CTRL_HDR 0 |
| 20058 | #define CYW_SDPCM_ASYNC_HDR 1 |
| 20059 | #define CYW_SDPCM_DATA_HDR 2 |
| 20060 | |
| 20061 | #pragma pack(pop) |
| 20062 | |
| 20063 | static uint8_t s_tx_seqno; |
| 20064 | static uint32_t txdata[2048 / 4], resp[2048 / 4]; |
| 20065 | |
| 20066 | static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len); |
| 20067 | static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len); |
| 20068 | static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len); |
| 20069 | |
| 20070 | static size_t cyw_spi_poll(uint8_t *dest); |
| 20071 | static void cyw_update_hash_table(void); |
| 20072 | |
| 20073 | // High-level comm stuff |
| 20074 | |
| 20075 | static void cyw_poll(void) { |
| 20076 | struct sdpcm_hdr *sdpcm = (struct sdpcm_hdr *) resp; |
| 20077 | unsigned int channel; |
| 20078 | if (s_ifp->update_mac_hash_table) { |
| 20079 | // first call to _poll() is after _init(), so this is safe |
| 20080 | cyw_update_hash_table(); |
| 20081 | s_ifp->update_mac_hash_table = false; |
| 20082 | } |
| 20083 | if (cyw_spi_poll((uint8_t *) resp) == 0) return; // BUS DEPENDENCY |
| 20084 | if ((sdpcm->len ^ sdpcm->_len) != 0xffff || sdpcm->len < sizeof(*sdpcm) || |
| 20085 | sdpcm->len > 2048 - sizeof(*sdpcm)) |
| 20086 | return; |
| 20087 | channel = sdpcm->sw_hdr.channel_and_flags & 0x0F; |
| 20088 | if (channel == CYW_SDPCM_CTRL_HDR) { |
| 20089 | if (sdpcm->len >= sizeof(*sdpcm) + sizeof(struct cdc_hdr)) { |
| 20090 | struct cdc_hdr *cdc = |
| 20091 | (struct cdc_hdr *) ((size_t) sdpcm + sdpcm->sw_hdr.header_length); |
| 20092 | size_t len = sdpcm->len - sdpcm->sw_hdr.header_length; |
| 20093 | cyw_handle_cdc(cdc, len); |
| 20094 | } |
| 20095 | } else if (channel == CYW_SDPCM_DATA_HDR) { |
| 20096 | if (sdpcm->len >= sizeof(*sdpcm) + sizeof(struct bdc_hdr)) { |
| 20097 | struct bdc_hdr *bdc = |
| 20098 | (struct bdc_hdr *) ((size_t) sdpcm + sdpcm->sw_hdr.header_length); |
| 20099 | size_t len = sdpcm->len - sdpcm->sw_hdr.header_length; |
| 20100 | cyw_handle_bdc(bdc, len); |
| 20101 | } |
| 20102 | } else if (channel == CYW_SDPCM_ASYNC_HDR) { |
| 20103 | struct bdc_hdr *bdc = |
| 20104 | (struct bdc_hdr *) ((size_t) sdpcm + sdpcm->sw_hdr.header_length); |
| 20105 | size_t len_ = sdpcm->len - sdpcm->sw_hdr.header_length; |
| 20106 | cyw_handle_bdc_evnt(bdc, len_); |
| 20107 | } // else silently discard |
| 20108 | } |
| 20109 | |
| 20110 | // WLAN frame reception |
| 20111 | static void cyw_handle_bdc(struct bdc_hdr *bdc, size_t len) { |
| 20112 | uint8_t *payload = (uint8_t *) &bdc[bdc->data_offset + 1]; |
| 20113 | mg_tcpip_qwrite(payload, len - (payload - (uint8_t *) bdc), s_ifp); |
| 20114 | } |
| 20115 | |
| 20116 | static size_t cyw_bus_tx(uint32_t *data, uint16_t len); |
| 20117 | |
| 20118 | // WLAN frame transmission |
| 20119 | static size_t mg_cyw_tx(unsigned int ifc, void *data, size_t len) { |
| 20120 | struct data_hdr *hdr = (struct data_hdr *) txdata; |
| 20121 | uint16_t txlen = (uint16_t) (len + sizeof(*hdr)); |
| 20122 | memset(txdata, 0, sizeof(*hdr)); |
| 20123 | memcpy((uint8_t *) txdata + sizeof(*hdr), data, len); |
| 20124 | // TODO(): hdr->bdc.priority = map IP to TOS if supporting QoS/ToS |
| 20125 | hdr->bdc.flags = 2 << 4; // BDC version 2 |
| 20126 | hdr->bdc.flags2 = ifc; // 0 -> STA, 1 -> AP |
| 20127 | // hdr->bdc.data_offset = 0; // actually zeroed above |
| 20128 | hdr->sdpcm.len = txlen; |
| 20129 | hdr->sdpcm._len = (uint16_t) ~txlen; |
| 20130 | hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno; |
| 20131 | hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_DATA_HDR, |
| 20132 | hdr->sdpcm.sw_hdr.header_length = offsetof(struct data_hdr, bdc); |
| 20133 | return cyw_bus_tx(txdata, txlen); |
| 20134 | } |
| 20135 | |
| 20136 | // WLAN event handling |
| 20137 | #pragma pack(push, 1) |
| 20138 | // all in network order |
| 20139 | |
| 20140 | struct eth_hdr { // TODO(scaprile) reuse 'eth' in net_builtin.c |
| 20141 | uint8_t dest[6]; |
| 20142 | uint8_t src[6]; |
| 20143 | uint16_t type; |
| 20144 | }; |
| 20145 | |
| 20146 | struct bcm_vendor_hdr { |
| 20147 | uint16_t subtype; // vendor specific: 0x8001 |
| 20148 | uint16_t length; // bytes following this field |
| 20149 | uint8_t version; // 0 |
| 20150 | uint8_t oui[3]; // vendor specific: 0x00 0x10 0x18 |
| 20151 | uint16_t usr_subtype; |
| 20152 | }; |
| 20153 | |
| 20154 | struct bcm_evnt_hdr { |
| 20155 | uint16_t version; // 1: fields up to ifname; 2: as shown |
| 20156 | uint16_t flags; |
| 20157 | uint32_t event_type; |
| 20158 | uint32_t status; |
| 20159 | uint32_t reason; |
| 20160 | uint32_t auth_type; |
| 20161 | uint32_t datalen; |
| 20162 | uint8_t addr[6]; // Station address (if applicable) |
| 20163 | char ifname[16]; |
| 20164 | uint8_t ifidx; |
| 20165 | uint8_t bss_cfg_idx; |
| 20166 | }; |
| 20167 | |
| 20168 | struct evnt_msg { |
| 20169 | struct eth_hdr eth; |
| 20170 | // struct vendor_hdr; but we only handle Broadcom (Wi-Fi processor) events |
| 20171 | struct bcm_vendor_hdr bcm; |
| 20172 | struct bcm_evnt_hdr event; |
| 20173 | }; |
| 20174 | |
| 20175 | #pragma pack(pop) |
| 20176 | |
| 20177 | struct scan_result; |
| 20178 | static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, |
| 20179 | size_t len); |
| 20180 | |
| 20181 | static void cyw_handle_bdc_evnt(struct bdc_hdr *bdc, size_t len) { |
| 20182 | struct evnt_msg *msg = (struct evnt_msg *) &bdc[bdc->data_offset + 1]; |
| 20183 | MG_VERBOSE(("%u bytes event", len)); |
| 20184 | if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) bdc, len); |
| 20185 | if (mg_ntohs(msg->eth.type) != 0x886C || msg->bcm.oui[0] != 0x00 || |
| 20186 | msg->bcm.oui[1] != 0x10 || msg->bcm.oui[2] != 0x18) |
| 20187 | return; // discard if not Broadcom |
| 20188 | if (mg_ntohl(msg->event.datalen) <= |
| 20189 | len - ((uint8_t *) msg - (uint8_t *) bdc)) { |
| 20190 | uint32_t event_type = mg_ntohl(msg->event.event_type); |
| 20191 | uint32_t status = mg_ntohl(msg->event.status); |
| 20192 | uint32_t reason = mg_ntohl(msg->event.reason); |
| 20193 | uint16_t flags = mg_ntohs(msg->event.flags); |
| 20194 | MG_DEBUG(("BCM event %lu %lu %lu %p", event_type, status, reason, flags)); |
| 20195 | if (event_type == 16 && status == 0) { // Link |
| 20196 | s_link = flags & 1; |
| 20197 | } else if (event_type == 46 && s_link) { // PSK sup with link up |
| 20198 | if (status == 6) { // Keyed |
| 20199 | } else if ((status == 4 || status == 8 || status == 10) && |
| 20200 | reason == 15) { // Wait M1/M3/G1 |
| 20201 | MG_ERROR(("AUTH TIMEOUT")); |
| 20202 | s_auth = false; |
| 20203 | } else { |
| 20204 | MG_ERROR(("AUTH FAILED")); |
| 20205 | s_auth = false; |
| 20206 | } |
| 20207 | } else if (event_type == 3 && status != 6) { // Auth (not unsolicited) |
| 20208 | if (status == 0) { // Success |
| 20209 | s_auth = true; |
| 20210 | } else { |
| 20211 | MG_ERROR(("AUTH TIMEOUT")); |
| 20212 | s_auth = false; |
| 20213 | } |
| 20214 | } else if (event_type == 1) { // Join |
| 20215 | if (status == 0) { // Success |
| 20216 | s_join = true; |
| 20217 | } else { |
| 20218 | MG_ERROR(("%s", status == 3 /* No networks */ ? "SSID NOT FOUND" |
| 20219 | : "JOIN FAILED")); |
| 20220 | s_join = false; |
| 20221 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &status); |
| 20222 | } |
| 20223 | } else if (event_type == 12 || event_type == 5) { // Disassoc, Deauth |
| 20224 | s_auth = false; |
| 20225 | } else if (event_type == 69) { // Scan result |
| 20226 | struct scan_result *data = (struct scan_result *) (&msg->event + 1); |
| 20227 | size_t dlen = mg_ntohl(msg->event.datalen); |
| 20228 | if (dlen > len - ((uint8_t *) data - (uint8_t *) bdc)) return; |
| 20229 | cyw_handle_scan_result(status, data, dlen); |
| 20230 | } |
| 20231 | } // else silently discard |
| 20232 | } |
| 20233 | |
| 20234 | static bool cyw_ioctl_get_(unsigned int ifc, unsigned int cmd, void *data, |
| 20235 | size_t len); |
| 20236 | static bool cyw_ioctl_set_(unsigned int ifc, unsigned int cmd, void *data, |
| 20237 | size_t len); |
| 20238 | static bool cyw_ioctl_iovar_get_(unsigned int ifc, char *var, void *data, |
| 20239 | size_t len); |
| 20240 | static bool cyw_ioctl_iovar_set_(unsigned int ifc, char *var, void *data, |
| 20241 | size_t len); |
| 20242 | // clang-format off |
| 20243 | // convenience: ioctl funcs on default ifc (0), as only AP needs ifc 1 |
| 20244 | static bool cyw_ioctl_get(unsigned int cmd, void *data, size_t len) { return cyw_ioctl_get_(0, cmd, data, len); } |
| 20245 | static bool cyw_ioctl_set(unsigned int cmd, void *data, size_t len) { return cyw_ioctl_set_(0, cmd, data, len); } |
| 20246 | static bool cyw_ioctl_iovar_get(char *var, void *data, size_t len) { return cyw_ioctl_iovar_get_(0, var, data, len); } |
| 20247 | static bool cyw_ioctl_iovar_set(char *var, void *data, size_t len) { return cyw_ioctl_iovar_set_(0, var, data, len); } |
| 20248 | // clang-format on |
| 20249 | |
| 20250 | // Wi-Fi network stuff |
| 20251 | |
| 20252 | // clang-format off |
| 20253 | static bool cyw_wifi_connect(char *ssid, char *pass) { |
| 20254 | uint32_t sup_wpa[2] = {0, 1}; // bss index 0 = STA, not open |
| 20255 | static const uint32_t const eapver[2] = {0, (uint32_t) -1}, // accept AP version |
| 20256 | tmo[2] = {0, 2500}; |
| 20257 | uint32_t data[64/4 + 1]; // max pass length: 64 for WPA, 128 for WPA3 SAE |
| 20258 | unsigned int len; |
| 20259 | uint32_t val; |
| 20260 | val = 4; // security type: 0 for none, 2 for WPA, 4 for WPA2/WPA3, 6 for mixed WPA/WPA2 |
| 20261 | // sup_wpa[1] = 0 if not using security |
| 20262 | if (!(cyw_ioctl_set(134 /* SET_WSEC */, (uint8_t *)&val, sizeof(val)) |
| 20263 | && cyw_ioctl_iovar_set("bsscfg:sup_wpa", (void *)sup_wpa, sizeof(sup_wpa)) |
| 20264 | && cyw_ioctl_iovar_set("bsscfg:sup_wpa2_eapver", (void *)eapver, sizeof(eapver)) |
| 20265 | && cyw_ioctl_iovar_set("bsscfg:sup_wpa_tmo", (void *)tmo, sizeof(tmo))) |
| 20266 | ) return false; |
| 20267 | mg_delayms(2); // allow radio firmware to be ready |
| 20268 | // skip if not using auth |
| 20269 | memset(data, 0, sizeof(data)); |
| 20270 | len = strlen(pass); |
| 20271 | ((uint16_t *)data)[0] = (uint16_t) len; |
| 20272 | ((uint16_t *)data)[1] = 1; // indicates wireless security key, skip for WPA3 SAE |
| 20273 | memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE |
| 20274 | if (!cyw_ioctl_set(268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA |
| 20275 | // for WPA3 SAE: memcpy((uint8_t *)data + sizeof(uint16_t), pass, len); cyw_ioctl_iovar_set("sae_password", data, sizeof(data)); |
| 20276 | // resume if not using auth |
| 20277 | val = 1; if (!cyw_ioctl_set(20 /* SET_INFRA */, (uint8_t *)&val, sizeof(val))) return false; |
| 20278 | val = 0; // auth type: 0 for open, 3 for SAE |
| 20279 | if (!cyw_ioctl_set(22 /* SET_AUTH */, (uint8_t *)&val, sizeof(val))) return false; |
| 20280 | val = 1; // MFP capable: 1 for yes, 0 for no; recommended to be set for WPA2+ (2 for 'required', WPA3) |
| 20281 | cyw_ioctl_iovar_set("mfp", (uint8_t *)&val, sizeof(val)); // Old chipsets do not support MFP |
| 20282 | val = 0x80; // auth type: 0 for none, 4 for WPA PSK, 0x80 for WPA2 PSK, 0x40000 for WPA3 SAE PSK |
| 20283 | if (!cyw_ioctl_set(165 /* SET_WPA_AUTH */, (uint8_t *)&val, sizeof(val))) return false; |
| 20284 | len = strlen(ssid); |
| 20285 | data[0] = (uint32_t) len; |
| 20286 | memcpy((uint8_t *)&data[1], ssid, len); |
| 20287 | if (!cyw_ioctl_set(26 /* SET_SSID */, data, len + sizeof(uint32_t))) return false; |
| 20288 | return true; |
| 20289 | } |
| 20290 | |
| 20291 | static bool cyw_wifi_disconnect(void) { |
| 20292 | return cyw_ioctl_set(52 /* DISASSOC */, NULL, 0); |
| 20293 | } |
| 20294 | |
| 20295 | // For AP functions, we use explicit ifc selection; both for clarity and maintenance, as some actions are performed on ifc 0, with or without a bss_index, and others are performed on ifc 1 |
| 20296 | |
| 20297 | static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { |
| 20298 | uint32_t data[64/4 + 2]; // max pass length: 64 for WPA, 128 for WPA3 SAE |
| 20299 | unsigned int len; |
| 20300 | uint32_t val; |
| 20301 | // CHIP DEPENDENCY |
| 20302 | // RPi set the AMPDU parameter for AP (window size = 2) ***************** |
| 20303 | // val = 2 ; cyw_ioctl_iovar_set_(0, "ampdu_ba_wsize", (uint8_t *)&val, sizeof(val)); |
| 20304 | // some chips might require to turn APSTA off and issue a SET_AP IOCTL |
| 20305 | len = strlen(ssid); |
| 20306 | data[0] = 1; // bss index 1 = AP |
| 20307 | data[1] = (uint32_t) len; |
| 20308 | memcpy((uint8_t *)&data[2], ssid, len); |
| 20309 | // TODO(scaprile): this takes some time to process, or requires a delay before doing it |
| 20310 | if (!cyw_ioctl_iovar_set_(0, "bsscfg:ssid", (uint8_t *)&data, len + 2 * sizeof(uint32_t))) return false; |
| 20311 | // TODO(scaprile): but sometimes this one takes some time to process |
| 20312 | val = (uint32_t) channel; if (!cyw_ioctl_set_(0, 30 /* SET_CHANNEL */, (uint8_t *)&val, sizeof(val))) return false; |
| 20313 | data[0] = 1; // bss index 1 = AP |
| 20314 | data[1] = 0x00400004; // security type: 0 for none, 0x00200002 for WPA, 0x00400004 for WPA2, 0x01000004 for WPA3, 0x01400004 for mixed WPA2/WPA3, 0x00400006 for mixed WPA/WPA2 |
| 20315 | // NOTE(): WHD writes & 0xFF if WPS is not enabled (?) |
| 20316 | if (!cyw_ioctl_iovar_set_(0, "bsscfg:wsec", (uint8_t *)&data, 2 * sizeof(uint32_t))) return false; |
| 20317 | val = 1; // MFP capable: 1 for yes, 0 for no; recommended to be set for WPA2+ (2 for 'required', WPA3) |
| 20318 | cyw_ioctl_iovar_set_(1, "mfp", (uint8_t *)&val, sizeof(val)); // Old chipsets do not support MFP |
| 20319 | mg_delayms(2); // allow radio firmware to be ready |
| 20320 | // skip if not using auth |
| 20321 | // WPA, WPA2, mixed WPA/WPA2, mixed WPA2/WPA3 |
| 20322 | // NOTE(): WHD does not set SAE password for shared WPA2/WPA3, same do we |
| 20323 | memset(data, 0, sizeof(data)); |
| 20324 | len = strlen(pass); |
| 20325 | ((uint16_t *)data)[0] = (uint16_t) len; // skip for WPA3 SAE |
| 20326 | ((uint16_t *)data)[1] = 1; // indicates wireless security key, skip for WPA3 SAE |
| 20327 | memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE |
| 20328 | if (!cyw_ioctl_set_(1, 268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA |
| 20329 | /* for WPA3 SAE: |
| 20330 | memcpy((uint8_t *)data + sizeof(uint16_t), pass, len); |
| 20331 | cyw_ioctl_iovar_set_(1, "sae_password", data, sizeof(data)); */ |
| 20332 | /* for WPA3 or mixed WPA2/WPA3: |
| 20333 | val = 5 ; cyw_ioctl_iovar_set_(1, "sae_max_pwe_loop", (uint8_t *)&val, sizeof(val)); // Some chipsets do not support this */ |
| 20334 | // resume if not using auth |
| 20335 | |
| 20336 | data[0] = 1; // bss index 1 = AP |
| 20337 | data[1] = 0x80; // auth type: 0 for none, 4 for WPA PSK, 0x80 for WPA2 PSK, 0x40000 for WPA3 SAE PSK; ored if mixed |
| 20338 | if (!cyw_ioctl_iovar_set_(0, "bsscfg:wpa_auth", (uint8_t *)&data, 2 * sizeof(uint32_t))) return false; |
| 20339 | |
| 20340 | val = 1 /* auto */; if (!cyw_ioctl_set_(1, 110 /* SET_GMODE */, (uint8_t *)&val, sizeof(val))) return false; |
| 20341 | // Set multicast tx rate to 11Mbps, may fail in some chipsets, we are enforcing it |
| 20342 | val = 11000000 / 500000; if (!cyw_ioctl_iovar_set_(1, "2g_mrate", (uint8_t *)&val, sizeof(val))) return false; |
| 20343 | val = 1; if (!cyw_ioctl_set_(1, 78 /* SET_DTIMPRD */, (uint8_t *)&val, sizeof(val))) return false; |
| 20344 | data[0] = 1; // bss index 1 = AP |
| 20345 | data[1] = 1; // UP |
| 20346 | // TODO(scaprile): this takes a long time to process |
| 20347 | if (!cyw_ioctl_iovar_set_(0, "bss", (uint8_t *)&data, 2 * sizeof(uint32_t))) return false; |
| 20348 | return true; |
| 20349 | } |
| 20350 | |
| 20351 | static bool cyw_wifi_ap_stop(void) { |
| 20352 | uint32_t data[2]; |
| 20353 | data[0] = 1; // bss index 1 = AP |
| 20354 | data[1] = 0; // DOWN |
| 20355 | if (!cyw_ioctl_iovar_set_(0, "bss", (uint8_t *)&data, 2 * sizeof(uint32_t))) return false; |
| 20356 | // DO WE NEED TO CLEAR CHANNEL ??? |
| 20357 | // CHIP DEPENDENCY |
| 20358 | //val = 8 ; cyw_ioctl_iovar_set_(0, "ampdu_ba_wsize", (uint8_t *)&val, sizeof(val)); |
| 20359 | return true; |
| 20360 | } |
| 20361 | |
| 20362 | // WLAN scan handling |
| 20363 | |
| 20364 | #pragma pack(push, 1) |
| 20365 | // in little endian |
| 20366 | |
| 20367 | struct wifi_scan_opt { |
| 20368 | uint32_t version; |
| 20369 | uint16_t action; |
| 20370 | uint16_t _; |
| 20371 | uint32_t ssid_len; |
| 20372 | uint8_t ssid[32]; |
| 20373 | uint8_t bssid[6]; |
| 20374 | int8_t bss_type; |
| 20375 | int8_t scan_type; |
| 20376 | int32_t nprobes; |
| 20377 | int32_t active_time; |
| 20378 | int32_t passive_time; |
| 20379 | int32_t home_time; |
| 20380 | int32_t channel_num; |
| 20381 | uint16_t channel_list[1]; |
| 20382 | }; |
| 20383 | #pragma pack(pop) |
| 20384 | |
| 20385 | static bool cyw_wifi_scan(void) { |
| 20386 | struct wifi_scan_opt opts; |
| 20387 | memset(&opts, 0, sizeof(opts)); |
| 20388 | opts.version = 1; |
| 20389 | opts.action = 1; // start |
| 20390 | opts._ = 0; |
| 20391 | memset(opts.bssid, 0xff, sizeof(opts.bssid)); |
| 20392 | opts.bss_type = 2; // any |
| 20393 | opts.nprobes = -1; |
| 20394 | opts.active_time = -1; |
| 20395 | opts.passive_time = -1; |
| 20396 | opts.home_time = -1; |
| 20397 | opts.channel_num = 0; |
| 20398 | opts.channel_list[0] = 0; |
| 20399 | return cyw_ioctl_iovar_set("escan", (uint8_t *)&opts, sizeof(opts)); |
| 20400 | } |
| 20401 | |
| 20402 | |
| 20403 | #pragma pack(push, 1) |
| 20404 | // in little endian |
| 20405 | |
| 20406 | struct scan_bss { |
| 20407 | uint32_t version; // version field |
| 20408 | uint32_t length; // byte length of data in this record, starting at version and including IEs |
| 20409 | uint8_t BSSID[6]; // Unique 6-byte MAC address |
| 20410 | uint16_t beacon_period; // Interval between two consecutive beacon frames. Units are Kusec |
| 20411 | uint16_t capability; // Capability information |
| 20412 | uint8_t SSID_len; // SSID length |
| 20413 | uint8_t SSID[32]; // Array to store SSID |
| 20414 | uint8_t reserved1[1]; // Reserved(padding) |
| 20415 | uint32_t rateset_count; // Count of rates in this set |
| 20416 | uint8_t rateset_rates[16]; // rates in 500kbps units, higher bit set if basic |
| 20417 | uint16_t chanspec; // Channel specification for basic service set |
| 20418 | uint16_t atim_window; // Announcement traffic indication message window size. Units are Kusec |
| 20419 | uint8_t dtim_period; // Delivery traffic indication message period |
| 20420 | uint8_t reserved2[1]; // Reserved(padding) |
| 20421 | int16_t RSSI; // receive signal strength (in dBm) |
| 20422 | int8_t phy_noise; // noise (in dBm) |
| 20423 | uint8_t n_cap; // BSS is 802.11n Capable |
| 20424 | uint8_t reserved3[2]; // Reserved(padding) |
| 20425 | uint32_t nbss_cap; // 802.11n BSS Capabilities (based on HT_CAP_*) |
| 20426 | uint8_t ctl_ch; // 802.11n BSS control channel number |
| 20427 | uint8_t reserved4[3]; // Reserved(padding) |
| 20428 | uint32_t reserved32[1]; // Reserved for expansion of BSS properties |
| 20429 | uint8_t flags; // flags |
| 20430 | uint8_t vht_cap; // BSS is vht capable |
| 20431 | uint8_t reserved5[2]; // Reserved(padding) |
| 20432 | uint8_t basic_mcs[16]; // 802.11N BSS required MCS set |
| 20433 | uint16_t ie_offset; // offset at which IEs start, from beginning |
| 20434 | uint16_t reserved16[1]; // Reserved(padding) |
| 20435 | uint32_t ie_length; // byte length of Information Elements |
| 20436 | int16_t SNR; // Average SNR during frame reception |
| 20437 | }; |
| 20438 | |
| 20439 | struct scan_result { |
| 20440 | uint32_t buflen; |
| 20441 | uint32_t version; |
| 20442 | uint16_t sync_id; |
| 20443 | uint16_t bss_count; |
| 20444 | struct scan_bss bss[1]; |
| 20445 | }; |
| 20446 | |
| 20447 | #pragma pack(pop) |
| 20448 | |
| 20449 | // CHIP DEPENDENCY |
| 20450 | #define CYW_BSS_BANDMASK 0xc000 |
| 20451 | #define CYW_BSS_BAND2G 0 |
| 20452 | // |
| 20453 | |
| 20454 | static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, size_t len) { |
| 20455 | MG_VERBOSE(("scan event, status: %ld", status)); |
| 20456 | if (status == 0) { // SUCCESS |
| 20457 | MG_VERBOSE(("scan complete")); |
| 20458 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL); |
| 20459 | } else if (status == 8) { // PARTIAL |
| 20460 | struct mg_wifi_scan_bss_data bss; |
| 20461 | struct scan_bss *sbss = data->bss; |
| 20462 | unsigned int band = sbss->chanspec & CYW_BSS_BANDMASK; |
| 20463 | if (data->version != 109 || data->bss_count != 1) { |
| 20464 | MG_ERROR(("Unsupported: %lu %u", data->version, data->bss_count)); |
| 20465 | return; |
| 20466 | } |
| 20467 | if (sbss->length > len - offsetof(struct scan_result, bss) || sbss->SSID_len > sizeof(sbss->SSID) || sbss->ie_offset < sizeof(*sbss) || sbss->ie_offset > (sizeof(*sbss) + sbss->ie_length) || sbss->ie_offset + sbss->ie_length > sbss->length) |
| 20468 | return; // silently discard malformed data |
| 20469 | if (!(sbss->flags & MG_BIT(2))) return; // RSSI_ONCHANNEL, ignore off-channel results |
| 20470 | bss.SSID = mg_str_n(sbss->SSID, sbss->SSID_len); |
| 20471 | bss.BSSID = sbss->BSSID; |
| 20472 | bss.RSSI = (int8_t)sbss->RSSI; |
| 20473 | bss.has_n = sbss->n_cap != 0; |
| 20474 | bss.channel = bss.has_n ? sbss->ctl_ch : (uint8_t)(sbss->chanspec & 0xff); // n 40MHz vs a/b/g and 20MHz |
| 20475 | bss.band = band & CYW_BSS_BAND2G ? MG_WIFI_BAND_2G : MG_WIFI_BAND_5G; |
| 20476 | bss.security = (sbss->capability & MG_BIT(4) /* CAP_PRIVACY */) ? MG_WIFI_SECURITY_WEP : MG_WIFI_SECURITY_OPEN; |
| 20477 | { // travel IEs (Information Elements) in search of security definitions |
| 20478 | const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1 |
| 20479 | uint8_t *ie = (uint8_t *)sbss + sbss->ie_offset; |
| 20480 | int bytes = (int) sbss->ie_length; |
| 20481 | while (bytes > 0 && ie[1] + 2 < bytes) { // ie[0] -> type, ie[1] -> bytes from ie[2] |
| 20482 | if (ie[0] == 48 /* IE_ID_RSN */) bss.security |= MG_WIFI_SECURITY_WPA2; |
| 20483 | if (ie[0] == 221 /* IE_ID_VENDOR_SPECIFIC */ && memcmp(&ie[2], wot1, 4) == 0) |
| 20484 | bss.security |= MG_WIFI_SECURITY_WPA; |
| 20485 | ie += ie[1] + 2; |
| 20486 | bytes -= ie[1] + 2; |
| 20487 | } |
| 20488 | } |
| 20489 | MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security)); |
| 20490 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss); |
| 20491 | } else { |
| 20492 | MG_ERROR(("scan error")); |
| 20493 | } |
| 20494 | } |
| 20495 | // clang-format on |
| 20496 | |
| 20497 | // IOCTL stuff. All values read and written are in little endian format |
| 20498 | |
| 20499 | static uint16_t s_ioctl_reqid; |
| 20500 | |
| 20501 | // CDC handler for waiting loop |
| 20502 | static uint8_t *s_ioctl_resp; |
| 20503 | static bool s_ioctl_err; |
| 20504 | |
| 20505 | static void cyw_handle_cdc(struct cdc_hdr *cdc, size_t len) { |
| 20506 | uint8_t *resp = (uint8_t *) cdc + sizeof(*cdc); |
| 20507 | MG_VERBOSE(("%u bytes CDC frame", len)); |
| 20508 | if ((cdc->flags >> 16) != s_ioctl_reqid) return; |
| 20509 | if (cdc->flags & 1) { |
| 20510 | MG_ERROR(("IOCTL error: %ld", -cdc->status)); |
| 20511 | s_ioctl_err = true; |
| 20512 | return; |
| 20513 | } |
| 20514 | if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump((void *) cdc, len); |
| 20515 | MG_DEBUG(("IOCTL result: %02x %02x %02x %02x ...", resp[0], resp[1], resp[2], |
| 20516 | resp[3])); |
| 20517 | s_ioctl_resp = resp; |
| 20518 | } |
| 20519 | // NOTE(): alt no loop handler dispatching IOCTL response to current handler: |
| 20520 | // static void *s_ioctl_hnd; *s_ioctl_hnd(ioctl, len); |
| 20521 | // app is a state machine calling get/sets and advancing via these callbacks |
| 20522 | |
| 20523 | #pragma pack(push, 1) |
| 20524 | // all little endian |
| 20525 | |
| 20526 | struct ctrl_hdr { |
| 20527 | struct sdpcm_hdr sdpcm; |
| 20528 | struct cdc_hdr cdc; |
| 20529 | }; |
| 20530 | |
| 20531 | #pragma pack(pop) |
| 20532 | |
| 20533 | // IOCTL command send |
| 20534 | static void cyw_ioctl_send_cmd(unsigned int ifc, unsigned int cmd, bool set, |
| 20535 | size_t len) { |
| 20536 | struct ctrl_hdr *hdr = (struct ctrl_hdr *) txdata; |
| 20537 | uint16_t txlen = (uint16_t) (len + sizeof(*hdr)); |
| 20538 | memset(txdata, 0, sizeof(*hdr)); |
| 20539 | hdr->cdc.cmd = cmd; |
| 20540 | hdr->cdc.olen = (uint16_t) len; |
| 20541 | // hdr->cdc.ilen = 0; // actually zeroed above |
| 20542 | hdr->cdc.flags = ((uint32_t) ++s_ioctl_reqid << 16) | ((ifc & 0xf) << 12) | |
| 20543 | (set ? MG_BIT(1) : 0); |
| 20544 | hdr->sdpcm.len = txlen; |
| 20545 | hdr->sdpcm._len = (uint16_t) ~txlen; |
| 20546 | hdr->sdpcm.sw_hdr.sequence = ++s_tx_seqno; |
| 20547 | hdr->sdpcm.sw_hdr.channel_and_flags = CYW_SDPCM_CTRL_HDR; |
| 20548 | hdr->sdpcm.sw_hdr.header_length = offsetof(struct ctrl_hdr, cdc); |
| 20549 | cyw_bus_tx(txdata, txlen); |
| 20550 | } |
| 20551 | |
| 20552 | // just send respective commands, response handled via CDC handler |
| 20553 | static void cyw_ioctl_send_get(unsigned int ifc, unsigned int cmd) { |
| 20554 | cyw_ioctl_send_cmd(ifc, cmd, false, 0); |
| 20555 | } |
| 20556 | |
| 20557 | static void cyw_ioctl_send_set(unsigned int ifc, unsigned int cmd, void *data, |
| 20558 | size_t len) { |
| 20559 | if (data != NULL && len > 0) |
| 20560 | memcpy((uint8_t *) txdata + sizeof(struct ctrl_hdr), data, len); |
| 20561 | cyw_ioctl_send_cmd(ifc, cmd, true, (uint16_t) len); |
| 20562 | } |
| 20563 | |
| 20564 | static void cyw_ioctl_send_iovar_get(unsigned int ifc, char *var, size_t len) { |
| 20565 | unsigned int namelen = strlen(var) + 1; // include '\0' |
| 20566 | // cmd = GET IOVAR, "set" the name... |
| 20567 | cyw_ioctl_send_set(ifc, 262, var, len > namelen ? len : namelen); |
| 20568 | } |
| 20569 | |
| 20570 | static void cyw_ioctl_send_iovar_set2(unsigned int ifc, char *var, void *data1, |
| 20571 | size_t len1, void *data2, size_t len2) { |
| 20572 | struct ctrl_hdr *hdr = (struct ctrl_hdr *) txdata; |
| 20573 | unsigned int namelen = strlen(var) + 1; // include '\0' |
| 20574 | uint16_t txlen, payload_len = (uint16_t) (namelen + len1 + len2); |
| 20575 | memcpy((uint8_t *) txdata + sizeof(*hdr), var, namelen); |
| 20576 | memcpy((uint8_t *) txdata + namelen + sizeof(*hdr), data1, len1); |
| 20577 | if (data2 != NULL) |
| 20578 | memcpy((uint8_t *) txdata + namelen + sizeof(*hdr) + len1, data2, len2); |
| 20579 | txlen = (uint16_t) (payload_len + sizeof(*hdr)); |
| 20580 | cyw_ioctl_send_cmd(ifc, 263, true, txlen); // cmd = SET IOVAR |
| 20581 | } |
| 20582 | |
| 20583 | static void cyw_ioctl_send_iovar_set(unsigned int ifc, char *var, void *data, |
| 20584 | size_t len) { |
| 20585 | cyw_ioctl_send_iovar_set2(ifc, var, data, len, NULL, 0); |
| 20586 | } |
| 20587 | |
| 20588 | // wait for a response, meanwhile delivering received frames and events |
| 20589 | static bool cyw_ioctl_wait(void) { |
| 20590 | unsigned int times = 6000; |
| 20591 | s_ioctl_resp = NULL; |
| 20592 | s_ioctl_err = false; |
| 20593 | while (s_ioctl_resp == NULL && !s_ioctl_err && times-- > 0) |
| 20594 | cyw_poll(); // TODO(scaprile): review wait/sleep strategy (this loop is executed only when initializing/acting on the chip) |
| 20595 | MG_DEBUG(("resp: %lp, err: %c, times: %d", s_ioctl_resp, |
| 20596 | s_ioctl_err ? '1' : '0', (int) times)); |
| 20597 | return s_ioctl_resp != NULL; |
| 20598 | } |
| 20599 | |
| 20600 | static bool cyw_ioctl_waitdata(void *data, size_t len) { |
| 20601 | if (!cyw_ioctl_wait()) return false; |
| 20602 | memcpy(data, s_ioctl_resp, len); |
| 20603 | return true; |
| 20604 | } |
| 20605 | |
| 20606 | // send respective commands, wait for a response or timeout |
| 20607 | static bool cyw_ioctl_get_(unsigned int ifc, unsigned int cmd, void *data, |
| 20608 | size_t len) { |
| 20609 | cyw_ioctl_send_get(ifc, cmd); |
| 20610 | return cyw_ioctl_waitdata(data, len); |
| 20611 | } |
| 20612 | static bool cyw_ioctl_set_(unsigned int ifc, unsigned int cmd, void *data, |
| 20613 | size_t len) { |
| 20614 | cyw_ioctl_send_set(ifc, cmd, data, len); |
| 20615 | return cyw_ioctl_wait(); |
| 20616 | } |
| 20617 | |
| 20618 | static bool cyw_ioctl_iovar_get_(unsigned int ifc, char *var, void *data, |
| 20619 | size_t len) { |
| 20620 | cyw_ioctl_send_iovar_get(ifc, var, len); |
| 20621 | return cyw_ioctl_waitdata(data, len); |
| 20622 | } |
| 20623 | static bool cyw_ioctl_iovar_set2_(unsigned int ifc, char *var, void *data1, |
| 20624 | size_t len1, void *data2, size_t len2) { |
| 20625 | cyw_ioctl_send_iovar_set2(ifc, var, data1, len1, data2, len2); |
| 20626 | return cyw_ioctl_wait(); |
| 20627 | } |
| 20628 | static bool cyw_ioctl_iovar_set_(unsigned int ifc, char *var, void *data, |
| 20629 | size_t len) { |
| 20630 | return cyw_ioctl_iovar_set2_(ifc, var, data, len, NULL, 0); |
| 20631 | } |
| 20632 | |
| 20633 | // CYW43 chipset specifics. All values read and written are in little endian |
| 20634 | // format |
| 20635 | |
| 20636 | #pragma pack(push, 1) |
| 20637 | // all little endian |
| 20638 | |
| 20639 | struct cyw_country { |
| 20640 | uint32_t a; |
| 20641 | int32_t rev; |
| 20642 | uint32_t c; |
| 20643 | }; |
| 20644 | |
| 20645 | struct clm_hdr { |
| 20646 | uint16_t flag; |
| 20647 | uint16_t type; |
| 20648 | uint32_t len; |
| 20649 | uint32_t crc; |
| 20650 | }; |
| 20651 | |
| 20652 | #pragma pack(pop) |
| 20653 | |
| 20654 | // worlwide rev0, try rev 17 for 4343W |
| 20655 | static const uint32_t country_code = 'X' + ('X' << 8) + (0 << 16); |
| 20656 | |
| 20657 | static bool cyw_spi_init(); |
| 20658 | |
| 20659 | // clang-format off |
| 20660 | static bool cyw_init(uint8_t *mac) { |
| 20661 | uint32_t val = 0; |
| 20662 | if (!cyw_spi_init()) return false; // BUS DEPENDENCY |
| 20663 | // BT-ENABLED DEPENDENCY |
| 20664 | // set Wi-Fi up |
| 20665 | val = 0 /* disable */; cyw_ioctl_iovar_set("bus:txglom", (uint8_t *)&val, sizeof(val)); |
| 20666 | val = 1 /* on */; cyw_ioctl_iovar_set("apsta", (uint8_t *)&val, sizeof(val)); |
| 20667 | // CHIP DEPENDENCY |
| 20668 | val = 8 ; cyw_ioctl_iovar_set("ampdu_ba_wsize", (uint8_t *)&val, sizeof(val)); |
| 20669 | val = 4 ; cyw_ioctl_iovar_set("ampdu_mpdu", (uint8_t *)&val, sizeof(val)); |
| 20670 | val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val)); |
| 20671 | // |
| 20672 | { |
| 20673 | struct cyw_country c; |
| 20674 | unsigned int rev = (unsigned int) (country_code >> 16) & 0xffff; |
| 20675 | c.c = c.a = country_code & 0xffff; |
| 20676 | c.rev = rev == 0 ? -1 : (int32_t) rev; // if rev is 0, set it to -1, the chip will use any NVRAM/OTP configured aggregate or default to rev 0 |
| 20677 | cyw_ioctl_iovar_set("country", (void *)&c, sizeof(c)); |
| 20678 | } // this takes some time to process |
| 20679 | { // so do some retries while enabling events of interest |
| 20680 | // we care for SET_SSID(0), JOIN(1), AUTH(3), DEAUTH(5), DISASSOC_IND(12), LINK(16), PSK_SUP(46), SCAN_RESULT(69); all < 128 |
| 20681 | uint32_t data[128/8/4 + 1]; |
| 20682 | data[0] = 0; // bss index: 0 = STA |
| 20683 | memset(&data[1], 0, 128/8); // mark all as not desired |
| 20684 | data[1] = MG_BIT(0) | MG_BIT(1) | MG_BIT(3) | MG_BIT(5) | MG_BIT(12) | MG_BIT(16); // events 0 to 31 |
| 20685 | data[2] = MG_BIT(46 - 32); // events 32 to 63 |
| 20686 | data[3] = MG_BIT(69 - 64); // events 64 to 95 |
| 20687 | unsigned int times = 100; |
| 20688 | while (times --) |
| 20689 | if (cyw_ioctl_iovar_set("bsscfg:event_msgs", (uint8_t *)data, sizeof(data))) break; |
| 20690 | if (times == ~0) return false; |
| 20691 | } |
| 20692 | val = 0; if (!cyw_ioctl_set(64 /* SET_ANTDIV */, (uint8_t *)&val, sizeof(val))) return false; |
| 20693 | if (!cyw_ioctl_set(2 /* UP, interface up */, NULL, 0)) return false; |
| 20694 | // use PM2 power saving for max throughput |
| 20695 | val = 200 /* ms */; if (!cyw_ioctl_iovar_set("pm2_sleep_ret", (uint8_t *)&val, sizeof(val))) return false; |
| 20696 | // set beacon intervals to reduce power consumption while associated to an AP but idle |
| 20697 | val = 1; if (!cyw_ioctl_iovar_set("bcn_li_bcn", (uint8_t *)&val, sizeof(val))) return false; |
| 20698 | val = 1; if (!cyw_ioctl_iovar_set("bcn_li_dtim", (uint8_t *)&val, sizeof(val))) return false; |
| 20699 | val = 10; if (!cyw_ioctl_iovar_set("assoc_listen", (uint8_t *)&val, sizeof(val))) return false; |
| 20700 | val = 1 /* auto */; if (!cyw_ioctl_set(110 /* SET_GMODE */, (uint8_t *)&val, sizeof(val))) return false; |
| 20701 | val = 0 /* any */; if (!cyw_ioctl_set(142 /* SET_BAND */, (uint8_t *)&val, sizeof(val))) return false; |
| 20702 | if (mg_log_level >= MG_LL_DEBUG) { |
| 20703 | char text[256]; // this is huge, but we're just starting up |
| 20704 | if (cyw_ioctl_iovar_get("ver", (uint8_t *)text, sizeof(text))) { |
| 20705 | unsigned int len = strnlen(text, sizeof(text)); |
| 20706 | MG_DEBUG(("Firmware:\n%.*s", len, text)); |
| 20707 | } |
| 20708 | text[0] = '\0'; |
| 20709 | if (cyw_ioctl_iovar_get("clmver", (uint8_t *)text, sizeof(text)) && text[0] != '\0') { |
| 20710 | unsigned int len = strnlen(text, sizeof(text)); |
| 20711 | MG_DEBUG(("CLM:\n%.*s", len, text)); |
| 20712 | } |
| 20713 | } |
| 20714 | { |
| 20715 | if(cyw_ioctl_iovar_get("cur_etheraddr", mac, 6)) { |
| 20716 | MG_DEBUG(("MAC: %M", mg_print_mac, mac)); |
| 20717 | } else { |
| 20718 | MG_ERROR(("read MAC failed")); |
| 20719 | } |
| 20720 | } |
| 20721 | return true; |
| 20722 | } |
| 20723 | // clang-format on |
| 20724 | |
| 20725 | static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, |
| 20726 | size_t nvramlen); |
| 20727 | |
| 20728 | static bool cyw_load_firmware(struct mg_tcpip_driver_cyw_firmware *fw) { |
| 20729 | return cyw_load_fwll((void *) fw->code_addr, fw->code_len, |
| 20730 | (void *) fw->nvram_addr, fw->nvram_len); |
| 20731 | } |
| 20732 | |
| 20733 | // clang-format off |
| 20734 | static bool cyw_load_clmll(void *data, size_t len) { |
| 20735 | unsigned int sent = 0, offset = 0; |
| 20736 | struct clm_hdr hdr = { |
| 20737 | .flag = 1 << 12 /* DLOAD_HANDLER_VER */ | MG_BIT(1) /* DL_BEGIN */, |
| 20738 | .type = 2, |
| 20739 | .crc = 0}; |
| 20740 | while (sent < len) { |
| 20741 | unsigned int bytes = len - sent; |
| 20742 | if (bytes > 1024) bytes = 1024; |
| 20743 | if (sent + bytes >= len) hdr.flag |= MG_BIT(2); // DL_END; |
| 20744 | hdr.len = bytes; |
| 20745 | if (!cyw_ioctl_iovar_set2_(0, "clmload", (void *) &hdr, sizeof(hdr), (uint8_t *) data + offset, bytes)) |
| 20746 | break; |
| 20747 | sent += bytes; |
| 20748 | offset += bytes; |
| 20749 | hdr.flag &= ~MG_BIT(1); // DL_BEGIN |
| 20750 | } |
| 20751 | return sent >= len; |
| 20752 | } |
| 20753 | // clang-format on |
| 20754 | |
| 20755 | static bool cyw_load_clm(struct mg_tcpip_driver_cyw_firmware *fw) { |
| 20756 | return cyw_load_clmll((void *) fw->clm_addr, fw->clm_len); |
| 20757 | } |
| 20758 | |
| 20759 | static void cyw_update_hash_table(void) { |
| 20760 | // TODO(): read database, rebuild hash table |
| 20761 | uint32_t val = 0; |
| 20762 | val = 1; cyw_ioctl_iovar_set2_(0, "mcast_list", (uint8_t *)&val, sizeof(val), (uint8_t *)mcast_addr, sizeof(mcast_addr)); |
| 20763 | mg_delayms(50); |
| 20764 | } |
| 20765 | |
| 20766 | // CYW43 chip backplane specifics. All values read and written are in little |
| 20767 | // endian format |
| 20768 | |
| 20769 | // Access to chip backplane is done windowed in 32KB banks |
| 20770 | // - addr = area base address + register offset |
| 20771 | // - set the window address to addr & ~ADDRMSK |
| 20772 | // - access addr & ADDRMSK for non-32-bit quantities |
| 20773 | // - if accesing 32-bit quantities, do it on (addr & ADDRMSK) | ACCSS4B |
| 20774 | #define CYW_CHIP_CHIPCOMMON 0x18000000 |
| 20775 | #define CYW_CHIP_BCKPLN_WINSZ 0x8000 |
| 20776 | #define CYW_CHIP_BCKPLN_ADDRMSK 0x7fff |
| 20777 | #define CYW_CHIP_BCKPLN_ACCSS4B MG_BIT(15) |
| 20778 | #define CYW_CHIP_BCKPLN_WRAPPOFF 0x100000 |
| 20779 | #define CYW_CHIP_BCKPLN_SPIMAX 64 |
| 20780 | #define CYW_CHIP_BCKPLN_SDIOMAX 1536 |
| 20781 | |
| 20782 | // CHIP DEPENDENCY |
| 20783 | #define CYW_CHIP_ARMCORE_BASE (CYW_CHIP_CHIPCOMMON + 0x3000) |
| 20784 | #define CYW_CHIP_SOCSRAM_BASE (CYW_CHIP_CHIPCOMMON + 0x4000) |
| 20785 | #define CYW_CHIP_ARMCORE (CYW_CHIP_ARMCORE_BASE + CYW_CHIP_BCKPLN_WRAPPOFF) |
| 20786 | #define CYW_CHIP_SOCSRAM (CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_BCKPLN_WRAPPOFF) |
| 20787 | #define CYW_CHIP_ATCMRAM_BASE 0 |
| 20788 | #define CYW_CHIP_RAM_SIZE 0x80000 |
| 20789 | // |
| 20790 | |
| 20791 | #define CYW_CHIP_ADDRLOW 0x1000a |
| 20792 | #define CYW_CHIP_ADDRMID 0x1000b |
| 20793 | #define CYW_CHIP_ADDRHIGH 0x1000c |
| 20794 | #define CYW_CHIP_SPIFRCTRL 0x1000d |
| 20795 | #define CYW_CHIP_CLOCKCSR 0x1000e |
| 20796 | #define CYW_CHIP_PULLUP 0x1000f |
| 20797 | #define CYW_CHIP_WAKEUPCTL 0x1001e |
| 20798 | #define CYW_CHIP_SLEEPCSR 0x1001f |
| 20799 | |
| 20800 | #define CYW_CHIP_SOCSRAM_BANKXIDX 0x010 |
| 20801 | #define CYW_CHIP_SOCSRAM_BANKXPDA 0x044 |
| 20802 | #define CYW_CHIP_AI_IOCTRL 0x408 |
| 20803 | #define CYW_CHIP_AI_RESETCTRL 0x800 |
| 20804 | |
| 20805 | static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data, |
| 20806 | uint16_t len); |
| 20807 | static void cyw_spi_read(unsigned int f, uint32_t addr, void *data, |
| 20808 | uint16_t len); |
| 20809 | |
| 20810 | // clang-format off |
| 20811 | // set backplane window to requested area. |
| 20812 | static void cyw_set_backplane_window(uint32_t addr) { |
| 20813 | uint32_t val; |
| 20814 | addr &= ~CYW_CHIP_BCKPLN_ADDRMSK; |
| 20815 | val = (addr >> 24) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRHIGH, &val, 1); |
| 20816 | val = (addr >> 16) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRMID, &val, 1); |
| 20817 | val = (addr >> 8) & 0xff; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_ADDRLOW, &val, 1); |
| 20818 | } |
| 20819 | |
| 20820 | static bool cyw_core_reset(uint32_t core_base, bool check) { |
| 20821 | uint32_t val = 0; |
| 20822 | // core disabled after chip reset |
| 20823 | cyw_set_backplane_window(core_base); // set backplane window for requested area; we do know offsets fall within that window |
| 20824 | // possible CHIP DEPENDENCY: AI_RESETSTATUS check and wait (instead of these cool reads) to ensure backplane operations end |
| 20825 | cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end |
| 20826 | val = MG_BIT(1) | MG_BIT(0) /* SICF_FGC | SICF_CLOCK_EN */; cyw_spi_write(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // reset |
| 20827 | cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end |
| 20828 | val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // release reset |
| 20829 | mg_delayms(1); |
| 20830 | val = MG_BIT(0) /* SICF_CLOCK_EN */; cyw_spi_write(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); |
| 20831 | cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); // ensure backplane operations end |
| 20832 | mg_delayms(1); |
| 20833 | |
| 20834 | if (check) { |
| 20835 | // Verify only clock is enabled |
| 20836 | cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_IOCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); |
| 20837 | if ((val & (MG_BIT(1) | MG_BIT(0)) /* SICF_FGC | SICF_CLOCK_EN) */) != MG_BIT(0)) return false; |
| 20838 | // Verify it is not in reset state |
| 20839 | cyw_spi_read(CYW_SD_FUNC_CHIP, (core_base + CYW_CHIP_AI_RESETCTRL) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 1); |
| 20840 | if (val & MG_BIT(0)) return false; // AIRC_RESET |
| 20841 | } |
| 20842 | return true; |
| 20843 | } |
| 20844 | |
| 20845 | static void cyw_socram_init(void) { |
| 20846 | uint32_t val; |
| 20847 | // CHIP DEPENDENCY: disable remap for SRAM_3 |
| 20848 | cyw_set_backplane_window(CYW_CHIP_SOCSRAM_BASE); // set backplane window for requested area; we do know offsets fall within that window |
| 20849 | val = 0x03; cyw_spi_write(CYW_SD_FUNC_CHIP, ((CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_SOCSRAM_BANKXIDX) & CYW_CHIP_BCKPLN_ADDRMSK) | CYW_CHIP_BCKPLN_ACCSS4B, &val, sizeof(val)); |
| 20850 | val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, ((CYW_CHIP_SOCSRAM_BASE + CYW_CHIP_SOCSRAM_BANKXPDA) & CYW_CHIP_BCKPLN_ADDRMSK) | CYW_CHIP_BCKPLN_ACCSS4B, &val, sizeof(val)); |
| 20851 | } |
| 20852 | |
| 20853 | // transfer is fractioned in bus-to-backplane-size units within backplane windows |
| 20854 | static void cyw_load_data(uint32_t dest, void *data, size_t len) { |
| 20855 | size_t sent = 0, offset = 0; |
| 20856 | uint32_t last_addr = ~0; |
| 20857 | while (sent < len) { |
| 20858 | size_t bytes = len - sent, avail; |
| 20859 | uint32_t addr = dest + offset; |
| 20860 | if (addr - last_addr >= CYW_CHIP_BCKPLN_WINSZ || last_addr == ~0) { |
| 20861 | cyw_set_backplane_window(addr); // set backplane window for requested area |
| 20862 | last_addr = addr & ~CYW_CHIP_BCKPLN_ADDRMSK; |
| 20863 | } |
| 20864 | addr &= CYW_CHIP_BCKPLN_ADDRMSK; |
| 20865 | avail = CYW_CHIP_BCKPLN_WINSZ - (unsigned int) addr; |
| 20866 | if (bytes > avail) bytes = avail; |
| 20867 | // BUS DEPENDENCY: max bus to backplane transfer size |
| 20868 | if (bytes > CYW_CHIP_BCKPLN_SPIMAX) bytes = CYW_CHIP_BCKPLN_SPIMAX; |
| 20869 | cyw_spi_write(CYW_SD_FUNC_CHIP, addr | CYW_CHIP_BCKPLN_ACCSS4B, (uint8_t *)data + offset, bytes); |
| 20870 | sent += bytes; |
| 20871 | offset += bytes; |
| 20872 | } |
| 20873 | } |
| 20874 | |
| 20875 | // CHIP DEPENDENCY: no SOCSRAM base address; start address in fwdata image (Cortex-R4 chips) |
| 20876 | static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nvramlen) { |
| 20877 | uint32_t val = ((~(nvramlen / 4) & 0xffff) << 16) | (nvramlen / 4); // ~len len in 32-bit words |
| 20878 | cyw_core_reset(CYW_CHIP_SOCSRAM, false); // cores were disabled at chip reset |
| 20879 | cyw_socram_init(); |
| 20880 | cyw_load_data(CYW_CHIP_ATCMRAM_BASE, fwdata, fwlen); |
| 20881 | mg_delayms(5); // ************ CHECK IF THIS IS ACTUALLY NEEDED |
| 20882 | // Load NVRAM and place 'length ~length' at the end; end of chip RAM |
| 20883 | { |
| 20884 | const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen; |
| 20885 | cyw_load_data(start, nvramdata, nvramlen); // nvramlen must be a multiple of 4 |
| 20886 | // RAM_SIZE is a multiple of WINSZ, so the place for len ~len will be at the end of the window |
| 20887 | cyw_spi_write(CYW_SD_FUNC_CHIP, (CYW_CHIP_BCKPLN_WINSZ - 4) | CYW_CHIP_BCKPLN_ACCSS4B, &val, sizeof(val)); |
| 20888 | } |
| 20889 | // Reset ARM core and check it starts |
| 20890 | if (!cyw_core_reset(CYW_CHIP_ARMCORE, true)) return false; |
| 20891 | return true; |
| 20892 | } |
| 20893 | // clang-format on |
| 20894 | |
| 20895 | // CYW43 SPI bus specifics |
| 20896 | |
| 20897 | #define CYW_BUS_SPI_BUSCTRL 0x00 // 4 regs, 0 to 3 |
| 20898 | #define CYW_BUS_SPI_INT 0x04 // 2 regs, 4 to 5 |
| 20899 | #define CYW_BUS_SPI_INTEN 0x06 // 16-bit register |
| 20900 | #define CYW_BUS_SPI_STATUS 0x08 // 32-bit register |
| 20901 | #define CYW_BUS_SPI_TEST 0x14 // 32-bit register |
| 20902 | #define CYW_BUS_SPI_RESPDLY_F1 0x1d // 8-bit register, F1: chip |
| 20903 | |
| 20904 | #define CYW_BUS_STS_LEN(x) ((x >> 9) & 0x7ff) |
| 20905 | |
| 20906 | // clang-format off |
| 20907 | static size_t cyw_spi_poll(uint8_t *response) { |
| 20908 | size_t len; |
| 20909 | uint32_t res; |
| 20910 | // SPI poll |
| 20911 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &res, sizeof(res)); |
| 20912 | if (res == ~0 || !(res & MG_BIT(8) /* packet available */ )) return 0; |
| 20913 | len = CYW_BUS_STS_LEN(res); |
| 20914 | if (len == 0) { // just ack IRQ |
| 20915 | uint16_t val = 1; |
| 20916 | cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_SPIFRCTRL, &val, 1); |
| 20917 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val)); |
| 20918 | cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INT, &val, sizeof(val)); |
| 20919 | return 0; |
| 20920 | } |
| 20921 | cyw_spi_read(CYW_SD_FUNC_WLAN, 0, response, len); |
| 20922 | return len; |
| 20923 | } |
| 20924 | |
| 20925 | // BUS DEPENDENCY: name is generic but function is bus dependent |
| 20926 | static size_t cyw_bus_tx(uint32_t *data, uint16_t len) { |
| 20927 | while (len & 3) data[len++] = 0; // SPI 32-bit padding (SDIO->64-byte) |
| 20928 | return cyw_spi_write(CYW_SD_FUNC_WLAN, 0, data, len) ? len: 0; |
| 20929 | } |
| 20930 | |
| 20931 | // this can be integrated in lowest level SPI read/write _driver_ functions |
| 20932 | // (those calling hal SPI transaction functions), though is only used at start |
| 20933 | uint32_t sw16_2(uint32_t data) { |
| 20934 | return ((uint32_t)mg_htons((uint16_t)(data >> 16)) << 16) + mg_htons((uint16_t)data); |
| 20935 | } |
| 20936 | |
| 20937 | // DS 4.2.2 Table 6: signal we're working in 16-bit mode |
| 20938 | #define CYW_SD_16bMODE MG_BIT(2) // arbitrary bit out of the FUNC space |
| 20939 | |
| 20940 | static bool cyw_spi_init() { |
| 20941 | struct mg_tcpip_driver_cyw_data *d = |
| 20942 | (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data; |
| 20943 | uint32_t val = 0; |
| 20944 | // DS 4.2.3 Boot-Up Sequence; WHD: other chips might require more effort |
| 20945 | unsigned int times = 51; |
| 20946 | while (times--) { |
| 20947 | cyw_spi_read(CYW_SD_FUNC_BUS | CYW_SD_16bMODE, CYW_BUS_SPI_TEST, &val, sizeof(val)); |
| 20948 | if (sw16_2(val) == 0xFEEDBEAD) break; |
| 20949 | mg_delayms(1); |
| 20950 | } |
| 20951 | if (times == ~0) return false; |
| 20952 | // DS 4.2.3 Table 6. Chip starts in 16-bit little-endian mode. |
| 20953 | // Configure SPI and switch to 32-bit big-endian mode: |
| 20954 | // - High-speed mode: d->hs true |
| 20955 | // - IRQ POLARITY high |
| 20956 | // - SPI RESPONSE DELAY 4 bytes time [not in DS] TODO(scaprile): logic ana |
| 20957 | // - Status not sent after command, IRQ with status |
| 20958 | val = sw16_2(0x000204a3 | (d->hs ? MG_BIT(4) : 0)); // 4 reg content |
| 20959 | cyw_spi_write(CYW_SD_FUNC_BUS | CYW_SD_16bMODE, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val)); |
| 20960 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_DRIVER, NULL); |
| 20961 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_TEST, &val, sizeof(val)); |
| 20962 | if (val != 0xFEEDBEAD) return false; |
| 20963 | val = 4; cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_RESPDLY_F1, &val, 1); |
| 20964 | val = 0x99; // clear error bits DATA_UNAVAILABLE, COMMAND_ERROR, DATA_ERROR, F1_OVERFLOW |
| 20965 | cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INT, &val, 1); |
| 20966 | val = 0x00be; // Enable IRQs F2_F3_FIFO_RD_UNDERFLOW, F2_F3_FIFO_WR_OVERFLOW, COMMAND_ERROR, DATA_ERROR, F2_PACKET_AVAILABLE, F1_OVERFLOW |
| 20967 | // BT-ENABLED DEPENDENCY: add F1_INTR (bit 13) |
| 20968 | cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t)); |
| 20969 | |
| 20970 | // chip backplane is ready, initialize it |
| 20971 | // request ALP (Active Low Power) clock |
| 20972 | val = MG_BIT(3) /* ALP_REQ */; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); |
| 20973 | // BT-ENABLED DEPENDENCY |
| 20974 | times = 10; |
| 20975 | while (times--) { |
| 20976 | cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); |
| 20977 | if (val & MG_BIT(6)) break; // ALP_AVAIL |
| 20978 | mg_delayms(1); |
| 20979 | } |
| 20980 | if (times == ~0) return false; |
| 20981 | // clear request |
| 20982 | val = 0; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); |
| 20983 | cyw_set_backplane_window(CYW_CHIP_CHIPCOMMON); // set backplane window to start of CHIPCOMMON area |
| 20984 | cyw_spi_read(CYW_SD_FUNC_CHIP, (CYW_CHIP_CHIPCOMMON + 0x00) & CYW_CHIP_BCKPLN_ADDRMSK, &val, 2); |
| 20985 | MG_INFO(("WLAN chip is CYW%u", *((uint16_t *)&val))); |
| 20986 | |
| 20987 | // Load firmware (code and NVRAM) |
| 20988 | if (!cyw_load_firmware(d->fw)) return false; |
| 20989 | |
| 20990 | // Wait for High Throughput (HT) clock ready |
| 20991 | times = 50; |
| 20992 | while (times--) { |
| 20993 | cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); |
| 20994 | if (val & MG_BIT(7)) break; // HT_AVAIL |
| 20995 | mg_delayms(1); |
| 20996 | } |
| 20997 | if (times == ~0) return false; |
| 20998 | // Wait for backplane ready |
| 20999 | times = 1000; |
| 21000 | while (times--) { |
| 21001 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &val, sizeof(val)); |
| 21002 | if (val & MG_BIT(5)) break; // F2_RX_READY |
| 21003 | mg_delayms(1); |
| 21004 | } |
| 21005 | if (times == ~0) return false; |
| 21006 | |
| 21007 | // CHIP DEPENDENCY |
| 21008 | // Enable save / restore |
| 21009 | // Configure WakeupCtrl, set HT_AVAIL in CLOCK_CSR |
| 21010 | cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1); |
| 21011 | val |= MG_BIT(1) /* WAKE_TILL_HT_AVAIL */; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_WAKEUPCTL, &val, 1); |
| 21012 | #if 0 |
| 21013 | // Set BRCM_CARDCAP to CMD_NODEC. NOTE(): This is probably only necessary for SDIO, not SPI |
| 21014 | val = MG_BIT(3); cyw_spi_write(CYW_SD_FUNC_BUS, 0xf0 /* SDIOD_CCCR_BRCM_CARDCAP */, &val, 1); |
| 21015 | #endif |
| 21016 | // Force HT request to chip backplane |
| 21017 | val = MG_BIT(1) /* FORCE_HT */; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_CLOCKCSR, &val, 1); |
| 21018 | // Enable Keep SDIO On (KSO) |
| 21019 | cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1); |
| 21020 | if (!(val & MG_BIT(0))) { |
| 21021 | val |= MG_BIT(0); cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_SLEEPCSR, &val, 1); |
| 21022 | } |
| 21023 | // The SPI bus can be configured for sleep (KSO controls wlan block sleep) |
| 21024 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val)); |
| 21025 | val &= ~MG_BIT(7) /* WAKE_UP */; cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_BUSCTRL, &val, sizeof(val)); |
| 21026 | // Set SPI bus sleep |
| 21027 | val = 0x0f; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1); |
| 21028 | |
| 21029 | // Clear pullups. NOTE(): ? |
| 21030 | val = 0x00; cyw_spi_write(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1); |
| 21031 | cyw_spi_read(CYW_SD_FUNC_CHIP, CYW_CHIP_PULLUP, &val, 1); |
| 21032 | // Clear possible data unavailable error |
| 21033 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t)); |
| 21034 | if (val & MG_BIT(0)) cyw_spi_write(CYW_SD_FUNC_BUS, CYW_BUS_SPI_INTEN, &val, sizeof(uint16_t)); |
| 21035 | |
| 21036 | // Load CLM blob |
| 21037 | if (!cyw_load_clm(d->fw)) return false; |
| 21038 | |
| 21039 | return true; |
| 21040 | } |
| 21041 | // clang-format on |
| 21042 | |
| 21043 | // gSPI, DS 4.2.1 Fig.12 |
| 21044 | #define CYW_SD_LEN(x) ((x) &0x7FF) // bits 0-10 |
| 21045 | #define CYW_SD_ADDR(x) (((x) &0x1FFFF) << 11) // bits 11-27, |
| 21046 | #define CYW_SD_FUNC(x) (((x) &3) << 28) // bits 28-29 |
| 21047 | #define CYW_SD_INC MG_BIT(30) |
| 21048 | #define CYW_SD_WR MG_BIT(31) |
| 21049 | |
| 21050 | static bool cyw_spi_write(unsigned int f, uint32_t addr, void *data, |
| 21051 | uint16_t len) { |
| 21052 | struct mg_tcpip_driver_cyw_data *d = |
| 21053 | (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data; |
| 21054 | struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi; |
| 21055 | uint32_t hdr = CYW_SD_WR | CYW_SD_INC | CYW_SD_FUNC(f) | CYW_SD_ADDR(addr) | |
| 21056 | CYW_SD_LEN(len); // gSPI header |
| 21057 | // TODO(scaprile): check spin in between and timeout values, return false |
| 21058 | if (f == CYW_SD_FUNC_WLAN) { |
| 21059 | uint32_t val = 0; |
| 21060 | while ((val & MG_BIT(5)) != MG_BIT(5)) // F2 rx ready (FIFO ready) |
| 21061 | cyw_spi_read(CYW_SD_FUNC_BUS, CYW_BUS_SPI_STATUS, &val, sizeof(val)); |
| 21062 | } |
| 21063 | if (f & CYW_SD_16bMODE) |
| 21064 | hdr = sw16_2(hdr); // swap half-words in 16-bit little-endian mode |
| 21065 | |
| 21066 | s->begin(NULL); |
| 21067 | s->txn(NULL, (uint8_t *) &hdr, NULL, sizeof(hdr)); |
| 21068 | if (len <= 4) { |
| 21069 | uint32_t pad = 0; |
| 21070 | memcpy(&pad, data, len); |
| 21071 | s->txn(NULL, (uint8_t *) &pad, NULL, sizeof(pad)); |
| 21072 | } else { |
| 21073 | s->txn(NULL, (uint8_t *) data, NULL, len); |
| 21074 | } |
| 21075 | s->end(NULL); |
| 21076 | return true; |
| 21077 | } |
| 21078 | |
| 21079 | // will write 32-bit aligned quantities to data if f == CYW_SD_FUNC_WLAN |
| 21080 | static void cyw_spi_read(unsigned int f, uint32_t addr, void *data, |
| 21081 | uint16_t len) { |
| 21082 | struct mg_tcpip_driver_cyw_data *d = |
| 21083 | (struct mg_tcpip_driver_cyw_data *) s_ifp->driver_data; |
| 21084 | struct mg_tcpip_spi_ *s = (struct mg_tcpip_spi_ *) d->spi; |
| 21085 | uint32_t padding = |
| 21086 | f == CYW_SD_FUNC_CHIP |
| 21087 | ? 4 |
| 21088 | : 0; // add padding to chip backplane reads as a response delay |
| 21089 | uint32_t hdr = CYW_SD_INC | CYW_SD_FUNC(f) | CYW_SD_ADDR(addr) | |
| 21090 | CYW_SD_LEN(len + padding); // gSPI header |
| 21091 | if (f == CYW_SD_FUNC_WLAN && (len & 3)) |
| 21092 | len = (len + 4) & ~3; // align WLAN transfers to 32-bit |
| 21093 | if (f & CYW_SD_16bMODE) |
| 21094 | hdr = sw16_2(hdr); // swap half-words in 16-bit little-endian mode |
| 21095 | |
| 21096 | s->begin(NULL); |
| 21097 | s->txn(NULL, (uint8_t *) &hdr, NULL, sizeof(hdr)); |
| 21098 | if (f == CYW_SD_FUNC_CHIP) { |
| 21099 | uint32_t pad; |
| 21100 | s->txn(NULL, NULL, (uint8_t *) &pad, 4); // read padding back and discard |
| 21101 | } |
| 21102 | s->txn(NULL, NULL, (uint8_t *) data, len); |
| 21103 | s->end(NULL); |
| 21104 | } |
| 21105 | |
| 21106 | // Mongoose Wi-Fi API functions |
| 21107 | |
| 21108 | bool mg_wifi_scan(void) { |
| 21109 | return cyw_wifi_scan(); |
| 21110 | } |
| 21111 | |
| 21112 | bool mg_wifi_connect(char *ssid, char *pass) { |
| 21113 | return cyw_wifi_connect(ssid, pass); |
| 21114 | } |
| 21115 | |
| 21116 | bool mg_wifi_disconnect(void) { |
| 21117 | return cyw_wifi_disconnect(); |
| 21118 | } |
| 21119 | |
| 21120 | bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { |
| 21121 | return cyw_wifi_ap_start(ssid, pass, channel); |
| 21122 | } |
| 21123 | |
| 21124 | bool mg_wifi_ap_stop(void) { |
| 21125 | return cyw_wifi_ap_stop(); |
| 21126 | } |
| 21127 | |
| 21128 | #endif |
| 21129 | |
| 21130 | #ifdef MG_ENABLE_LINES |
| 21131 | #line 1 "src/drivers/imxrt.c" |
| 21132 | #endif |
| 21133 | |
| 21134 | |
| 21135 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT |
| 21136 | struct imxrt_enet { |
| 21137 | volatile uint32_t RESERVED0, EIR, EIMR, RESERVED1, RDAR, TDAR, RESERVED2[3], |
| 21138 | ECR, RESERVED3[6], MMFR, MSCR, RESERVED4[7], MIBC, RESERVED5[7], RCR, |
| 21139 | RESERVED6[15], TCR, RESERVED7[7], PALR, PAUR, OPD, TXIC0, TXIC1, TXIC2, |
| 21140 | RESERVED8, RXIC0, RXIC1, RXIC2, RESERVED9[3], IAUR, IALR, GAUR, GALR, |
| 21141 | RESERVED10[7], TFWR, RESERVED11[14], RDSR, TDSR, MRBR[2], RSFL, RSEM, |
| 21142 | RAEM, RAFL, TSEM, TAEM, TAFL, TIPG, FTRL, RESERVED12[3], TACC, RACC, |
| 21143 | RESERVED13[15], RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, |
| 21144 | RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, |
| 21145 | RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, |
| 21146 | RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2048, RMON_T_GTE2048, |
| 21147 | RMON_T_OCTETS, IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, |
| 21148 | IEEE_T_DEF, IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, |
| 21149 | IEEE_T_SQE, IEEE_T_FDXFC, IEEE_T_OCTETS_OK, RESERVED14[3], RMON_R_PACKETS, |
| 21150 | RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, RMON_R_UNDERSIZE, |
| 21151 | RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, RESERVED15, RMON_R_P64, |
| 21152 | RMON_R_P65TO127, RMON_R_P128TO255, RMON_R_P256TO511, RMON_R_P512TO1023, |
| 21153 | RMON_R_P1024TO2047, RMON_R_GTE2048, RMON_R_OCTETS, IEEE_R_DROP, |
| 21154 | IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR, IEEE_R_FDXFC, |
| 21155 | IEEE_R_OCTETS_OK, RESERVED16[71], ATCR, ATVR, ATOFF, ATPER, ATCOR, ATINC, |
| 21156 | ATSTMP, RESERVED17[122], TGSR, TCSR0, TCCR0, TCSR1, TCCR1, TCSR2, TCCR2, |
| 21157 | TCSR3; |
| 21158 | }; |
| 21159 | |
| 21160 | #undef ENET |
| 21161 | #if defined(MG_DRIVER_IMXRT_RT11) && MG_DRIVER_IMXRT_RT11 |
| 21162 | #define ENET ((struct imxrt_enet *) (uintptr_t) 0x40424000U) |
| 21163 | #define ETH_DESC_CNT 5 // Descriptors count |
| 21164 | #else |
| 21165 | #define ENET ((struct imxrt_enet *) (uintptr_t) 0x402D8000U) |
| 21166 | #define ETH_DESC_CNT 4 // Descriptors count |
| 21167 | #endif |
| 21168 | |
| 21169 | #define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned |
| 21170 | |
| 21171 | struct enet_desc { |
| 21172 | uint16_t length; // Data length |
| 21173 | uint16_t control; // Control and status |
| 21174 | uint32_t *buffer; // Data ptr |
| 21175 | }; |
| 21176 | |
| 21177 | // TODO(): handle these in a portable compiler-independent CMSIS-friendly way |
| 21178 | #define MG_64BYTE_ALIGNED __attribute__((aligned((64U)))) |
| 21179 | |
| 21180 | // Descriptors: in non-cached area (TODO(scaprile)), (37.5.1.22.2 37.5.1.23.2) |
| 21181 | // Buffers: 64-byte aligned (37.3.14) |
| 21182 | static volatile struct enet_desc s_rxdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED; |
| 21183 | static volatile struct enet_desc s_txdesc[ETH_DESC_CNT] MG_64BYTE_ALIGNED; |
| 21184 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED; |
| 21185 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED; |
| 21186 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 21187 | |
| 21188 | static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) { |
| 21189 | ENET->EIR |= MG_BIT(23); // MII interrupt clear |
| 21190 | ENET->MMFR = (1 << 30) | (2 << 28) | (addr << 23) | (reg << 18) | (2 << 16); |
| 21191 | while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; |
| 21192 | return ENET->MMFR & 0xffff; |
| 21193 | } |
| 21194 | |
| 21195 | static void enet_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 21196 | ENET->EIR |= MG_BIT(23); // MII interrupt clear |
| 21197 | ENET->MMFR = |
| 21198 | (1 << 30) | (1 << 28) | (addr << 23) | (reg << 18) | (2 << 16) | val; |
| 21199 | while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; |
| 21200 | } |
| 21201 | |
| 21202 | // MDC clock is generated from IPS Bus clock (ipg_clk); as per 802.3, |
| 21203 | // it must not exceed 2.5MHz |
| 21204 | // The PHY receives the PLL6-generated 50MHz clock |
| 21205 | static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) { |
| 21206 | struct mg_tcpip_driver_imxrt_data *d = |
| 21207 | (struct mg_tcpip_driver_imxrt_data *) ifp->driver_data; |
| 21208 | s_ifp = ifp; |
| 21209 | |
| 21210 | // Init RX descriptors |
| 21211 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 21212 | s_rxdesc[i].control = MG_BIT(15); // Own (E) |
| 21213 | s_rxdesc[i].buffer = (uint32_t *) s_rxbuf[i]; // Point to data buffer |
| 21214 | } |
| 21215 | s_rxdesc[ETH_DESC_CNT - 1].control |= MG_BIT(13); // Wrap last descriptor |
| 21216 | |
| 21217 | // Init TX descriptors |
| 21218 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 21219 | // s_txdesc[i].control = MG_BIT(10); // Own (TC) |
| 21220 | s_txdesc[i].buffer = (uint32_t *) s_txbuf[i]; |
| 21221 | } |
| 21222 | s_txdesc[ETH_DESC_CNT - 1].control |= MG_BIT(13); // Wrap last descriptor |
| 21223 | |
| 21224 | ENET->ECR = MG_BIT(0); // Software reset, disable |
| 21225 | while ((ENET->ECR & MG_BIT(0))) (void) 0; // Wait until done |
| 21226 | |
| 21227 | // Set MDC clock divider. If user told us the value, use it. |
| 21228 | // TODO(): Otherwise, guess (currently assuming max freq) |
| 21229 | int cr = (d == NULL || d->mdc_cr < 0) ? 24 : d->mdc_cr; |
| 21230 | ENET->MSCR = (1 << 8) | ((cr & 0x3f) << 1); // HOLDTIME 2 clks |
| 21231 | struct mg_phy phy = {enet_read_phy, enet_write_phy}; |
| 21232 | mg_phy_init(&phy, d->phy_addr, MG_PHY_LEDS_ACTIVE_HIGH); // MAC clocks PHY |
| 21233 | // Select RMII mode, 100M, keep CRC, set max rx length, disable loop |
| 21234 | ENET->RCR = (1518 << 16) | MG_BIT(8) | MG_BIT(2); |
| 21235 | // ENET->RCR |= MG_BIT(3); // Receive all |
| 21236 | ENET->TCR = MG_BIT(2); // Full-duplex |
| 21237 | ENET->RDSR = (uint32_t) (uintptr_t) s_rxdesc; |
| 21238 | ENET->TDSR = (uint32_t) (uintptr_t) s_txdesc; |
| 21239 | ENET->MRBR[0] = ETH_PKT_SIZE; // Same size for RX/TX buffers |
| 21240 | // MAC address filtering (bytes in reversed order) |
| 21241 | ENET->PAUR = ((uint32_t) ifp->mac[4] << 24U) | (uint32_t) ifp->mac[5] << 16U; |
| 21242 | ENET->PALR = (uint32_t) (ifp->mac[0] << 24U) | |
| 21243 | ((uint32_t) ifp->mac[1] << 16U) | |
| 21244 | ((uint32_t) ifp->mac[2] << 8U) | ifp->mac[3]; |
| 21245 | ENET->ECR = MG_BIT(8) | MG_BIT(1); // Little-endian CPU, Enable |
| 21246 | ENET->EIMR = MG_BIT(25); // Set interrupt mask |
| 21247 | ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed |
| 21248 | ENET->TDAR = MG_BIT(24); // Transmit Descriptors have changed |
| 21249 | // ENET->OPD = 0x10014; |
| 21250 | ENET->IAUR = 0; |
| 21251 | ENET->IALR = 0; |
| 21252 | ENET->GAUR = 0; |
| 21253 | ENET->GALR = 0; |
| 21254 | return true; |
| 21255 | } |
| 21256 | |
| 21257 | |
| 21258 | // Transmit frame |
| 21259 | static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len, |
| 21260 | struct mg_tcpip_if *ifp) { |
| 21261 | static int s_txno; // Current descriptor index |
| 21262 | if (len > sizeof(s_txbuf[ETH_DESC_CNT])) { |
| 21263 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 21264 | len = (size_t) -1; // fail |
| 21265 | } else if ((s_txdesc[s_txno].control & MG_BIT(15))) { |
| 21266 | ifp->nerr++; |
| 21267 | MG_ERROR(("No descriptors available")); |
| 21268 | len = 0; // retry later |
| 21269 | } else { |
| 21270 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 21271 | s_txdesc[s_txno].length = (uint16_t) len; // Set data len |
| 21272 | // Table 37-34, R, L, TC (Ready, last, transmit CRC after frame |
| 21273 | s_txdesc[s_txno].control |= |
| 21274 | (uint16_t) (MG_BIT(15) | MG_BIT(11) | MG_BIT(10)); |
| 21275 | ENET->TDAR = MG_BIT(24); // Descriptor ring updated |
| 21276 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 21277 | } |
| 21278 | (void) ifp; |
| 21279 | return len; |
| 21280 | } |
| 21281 | |
| 21282 | static void mg_tcpip_driver_imxrt_update_hash_table(struct mg_tcpip_if *ifp) { |
| 21283 | // TODO(): read database, rebuild hash table |
| 21284 | // RM 37.3.4.3.2 |
| 21285 | uint32_t hash_table[2] = {0, 0}; |
| 21286 | // uint8_t hash64 = ((~mg_crc32(0, mcast_addr, 6)) >> 26) & 0x3f; |
| 21287 | // hash_table[((uint8_t)hash64) >> 5] |= (1 << (hash64 & 0x1f)); |
| 21288 | hash_table[1] = MG_BIT(1); // above reduces to this for mDNS addr |
| 21289 | ENET->GAUR = hash_table[1]; |
| 21290 | ENET->GALR = hash_table[0]; |
| 21291 | (void) ifp; |
| 21292 | } |
| 21293 | |
| 21294 | static bool mg_tcpip_driver_imxrt_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 21295 | if (ifp->update_mac_hash_table) { |
| 21296 | mg_tcpip_driver_imxrt_update_hash_table(ifp); |
| 21297 | ifp->update_mac_hash_table = false; |
| 21298 | } |
| 21299 | if (!s1) return false; |
| 21300 | struct mg_tcpip_driver_imxrt_data *d = |
| 21301 | (struct mg_tcpip_driver_imxrt_data *) ifp->driver_data; |
| 21302 | uint8_t speed = MG_PHY_SPEED_10M; |
| 21303 | bool up = false, full_duplex = false; |
| 21304 | struct mg_phy phy = {enet_read_phy, enet_write_phy}; |
| 21305 | up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); |
| 21306 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 21307 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 21308 | // if(link is slow or half) set flags otherwise |
| 21309 | // reg = tmp |
| 21310 | uint32_t tcr = ENET->TCR | MG_BIT(2); // Full-duplex |
| 21311 | uint32_t rcr = ENET->RCR & ~MG_BIT(9); // 100M |
| 21312 | if (speed == MG_PHY_SPEED_10M) rcr |= MG_BIT(9); // 10M |
| 21313 | if (full_duplex == false) tcr &= ~MG_BIT(2); // Half-duplex |
| 21314 | ENET->TCR = tcr; // IRQ handler does not fiddle with these registers |
| 21315 | ENET->RCR = rcr; |
| 21316 | MG_DEBUG(("Link is %uM %s-duplex", rcr & MG_BIT(9) ? 10 : 100, |
| 21317 | tcr & MG_BIT(2) ? "full" : "half")); |
| 21318 | } |
| 21319 | return up; |
| 21320 | } |
| 21321 | |
| 21322 | void ENET_IRQHandler(void); |
| 21323 | static uint32_t s_rxno; |
| 21324 | void ENET_IRQHandler(void) { |
| 21325 | ENET->EIR = MG_BIT(25); // Ack IRQ |
| 21326 | // Frame received, loop |
| 21327 | for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever |
| 21328 | uint32_t r = s_rxdesc[s_rxno].control; |
| 21329 | if (r & MG_BIT(15)) break; // exit when done |
| 21330 | // skip partial/errored frames (Table 37-32) |
| 21331 | if ((r & MG_BIT(11)) && |
| 21332 | !(r & (MG_BIT(5) | MG_BIT(4) | MG_BIT(2) | MG_BIT(1) | MG_BIT(0)))) { |
| 21333 | size_t len = s_rxdesc[s_rxno].length; |
| 21334 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); |
| 21335 | } |
| 21336 | s_rxdesc[s_rxno].control |= MG_BIT(15); |
| 21337 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 21338 | } |
| 21339 | ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed |
| 21340 | // If b24 == 0, descriptors were exhausted and probably frames were dropped |
| 21341 | } |
| 21342 | |
| 21343 | struct mg_tcpip_driver mg_tcpip_driver_imxrt = {mg_tcpip_driver_imxrt_init, |
| 21344 | mg_tcpip_driver_imxrt_tx, NULL, |
| 21345 | mg_tcpip_driver_imxrt_poll}; |
| 21346 | |
| 21347 | #endif |
| 21348 | |
| 21349 | #ifdef MG_ENABLE_LINES |
| 21350 | #line 1 "src/drivers/phy.c" |
| 21351 | #endif |
| 21352 | |
| 21353 | |
| 21354 | enum { // ID1 ID2 |
| 21355 | MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB |
| 21356 | MG_PHY_DP83x = 0x2000, |
| 21357 | MG_PHY_DP83867 = 0xa231, // 2000 a231 - TI DP83867I |
| 21358 | MG_PHY_DP83825 = 0xa140, // 2000 a140 - TI DP83825I |
| 21359 | MG_PHY_DP83848 = 0x5ca2, // 2000 5ca2 - TI DP83848I |
| 21360 | MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720 |
| 21361 | MG_PHY_RTL8201 = 0x1C // 001c c816 - RTL8201 |
| 21362 | }; |
| 21363 | |
| 21364 | enum { |
| 21365 | MG_PHY_REG_BCR = 0, |
| 21366 | MG_PHY_REG_BSR = 1, |
| 21367 | MG_PHY_REG_ID1 = 2, |
| 21368 | MG_PHY_REG_ID2 = 3, |
| 21369 | MG_PHY_DP83x_REG_PHYSTS = 16, |
| 21370 | MG_PHY_DP83867_REG_PHYSTS = 17, |
| 21371 | MG_PHY_DP83x_REG_RCSR = 23, |
| 21372 | MG_PHY_DP83x_REG_LEDCR = 24, |
| 21373 | MG_PHY_KSZ8x_REG_PC1R = 30, |
| 21374 | MG_PHY_KSZ8x_REG_PC2R = 31, |
| 21375 | MG_PHY_LAN87x_REG_SCSR = 31, |
| 21376 | MG_PHY_RTL8201_REG_RMSR = 16, // in page 7 |
| 21377 | MG_PHY_RTL8201_REG_PAGESEL = 31 |
| 21378 | }; |
| 21379 | |
| 21380 | static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) { |
| 21381 | switch (id1) { |
| 21382 | case MG_PHY_DP83x: |
| 21383 | switch (id2) { |
| 21384 | case MG_PHY_DP83867: |
| 21385 | return "DP83867"; |
| 21386 | case MG_PHY_DP83848: |
| 21387 | return "DP83848"; |
| 21388 | case MG_PHY_DP83825: |
| 21389 | return "DP83825"; |
| 21390 | default: |
| 21391 | return "DP83x"; |
| 21392 | } |
| 21393 | case MG_PHY_KSZ8x: |
| 21394 | return "KSZ8x"; |
| 21395 | case MG_PHY_LAN87x: |
| 21396 | return "LAN87x"; |
| 21397 | case MG_PHY_RTL8201: |
| 21398 | return "RTL8201"; |
| 21399 | default: |
| 21400 | return "unknown"; |
| 21401 | } |
| 21402 | (void) id2; |
| 21403 | } |
| 21404 | |
| 21405 | void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) { |
| 21406 | uint16_t id1, id2; |
| 21407 | phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(15)); // Reset PHY |
| 21408 | while (phy->read_reg(phy_addr, MG_PHY_REG_BCR) & MG_BIT(15)) (void) 0; |
| 21409 | // MG_PHY_REG_BCR[12]: Autonegotiation is default unless hw says otherwise |
| 21410 | |
| 21411 | id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1); |
| 21412 | id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2); |
| 21413 | MG_INFO(("PHY ID: %#04x %#04x (%s)", id1, id2, mg_phy_id_to_str(id1, id2))); |
| 21414 | |
| 21415 | if (id1 == MG_PHY_DP83x && id2 == MG_PHY_DP83867) { |
| 21416 | phy->write_reg(phy_addr, 0x0d, 0x1f); // write 0x10d to IO_MUX_CFG (0x0170) |
| 21417 | phy->write_reg(phy_addr, 0x0e, 0x170); |
| 21418 | phy->write_reg(phy_addr, 0x0d, 0x401f); |
| 21419 | phy->write_reg(phy_addr, 0x0e, 0x10d); |
| 21420 | } |
| 21421 | |
| 21422 | if (config & MG_PHY_CLOCKS_MAC) { |
| 21423 | // Use PHY crystal oscillator (preserve defaults) |
| 21424 | // nothing to do |
| 21425 | } else { // MAC clocks PHY, PHY has no xtal |
| 21426 | // Enable 50 MHz external ref clock at XI (preserve defaults) |
| 21427 | if (id1 == MG_PHY_DP83x && id2 != MG_PHY_DP83867 && id2 != MG_PHY_DP83848) { |
| 21428 | phy->write_reg(phy_addr, MG_PHY_DP83x_REG_RCSR, MG_BIT(7) | MG_BIT(0)); |
| 21429 | } else if (id1 == MG_PHY_KSZ8x) { |
| 21430 | // Disable isolation (override hw, it doesn't make sense at this point) |
| 21431 | phy->write_reg( // #2848, some NXP boards set ISO, even though |
| 21432 | phy_addr, MG_PHY_REG_BCR, // docs say they don't |
| 21433 | phy->read_reg(phy_addr, MG_PHY_REG_BCR) & (uint16_t) ~MG_BIT(10)); |
| 21434 | phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R, // now do clock stuff |
| 21435 | MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); |
| 21436 | } else if (id1 == MG_PHY_LAN87x) { |
| 21437 | // nothing to do |
| 21438 | } else if (id1 == MG_PHY_RTL8201) { |
| 21439 | // assume PHY has been hardware strapped properly |
| 21440 | #if 0 |
| 21441 | phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 7); // Select page 7 |
| 21442 | phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x1ffa); |
| 21443 | phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 0); // Select page 0 |
| 21444 | #endif |
| 21445 | } |
| 21446 | } |
| 21447 | |
| 21448 | if (config & MG_PHY_LEDS_ACTIVE_HIGH && id1 == MG_PHY_DP83x) { |
| 21449 | phy->write_reg(phy_addr, MG_PHY_DP83x_REG_LEDCR, |
| 21450 | MG_BIT(9) | MG_BIT(7)); // LED status, active high |
| 21451 | } // Other PHYs do not support this feature |
| 21452 | } |
| 21453 | |
| 21454 | bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex, |
| 21455 | uint8_t *speed) { |
| 21456 | bool up = false; |
| 21457 | uint16_t bsr = phy->read_reg(phy_addr, MG_PHY_REG_BSR); |
| 21458 | if ((bsr & MG_BIT(5)) && !(bsr & MG_BIT(2))) // some PHYs latch down events |
| 21459 | bsr = phy->read_reg(phy_addr, MG_PHY_REG_BSR); // read again |
| 21460 | up = bsr & MG_BIT(2); |
| 21461 | if (up && full_duplex != NULL && speed != NULL) { |
| 21462 | uint16_t id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1); |
| 21463 | if (id1 == MG_PHY_DP83x) { |
| 21464 | uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2); |
| 21465 | if (id2 == MG_PHY_DP83867) { |
| 21466 | uint16_t physts = phy->read_reg(phy_addr, MG_PHY_DP83867_REG_PHYSTS); |
| 21467 | *full_duplex = physts & MG_BIT(13); |
| 21468 | *speed = (physts & MG_BIT(15)) ? MG_PHY_SPEED_1000M |
| 21469 | : (physts & MG_BIT(14)) ? MG_PHY_SPEED_100M |
| 21470 | : MG_PHY_SPEED_10M; |
| 21471 | } else { |
| 21472 | uint16_t physts = phy->read_reg(phy_addr, MG_PHY_DP83x_REG_PHYSTS); |
| 21473 | *full_duplex = physts & MG_BIT(2); |
| 21474 | *speed = (physts & MG_BIT(1)) ? MG_PHY_SPEED_10M : MG_PHY_SPEED_100M; |
| 21475 | } |
| 21476 | } else if (id1 == MG_PHY_KSZ8x) { |
| 21477 | uint16_t pc1r = phy->read_reg(phy_addr, MG_PHY_KSZ8x_REG_PC1R); |
| 21478 | *full_duplex = pc1r & MG_BIT(2); |
| 21479 | *speed = (pc1r & 3) == 1 ? MG_PHY_SPEED_10M : MG_PHY_SPEED_100M; |
| 21480 | } else if (id1 == MG_PHY_LAN87x) { |
| 21481 | uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR); |
| 21482 | *full_duplex = scsr & MG_BIT(4); |
| 21483 | *speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; |
| 21484 | } else if (id1 == MG_PHY_RTL8201) { |
| 21485 | uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR); |
| 21486 | *full_duplex = bcr & MG_BIT(8); |
| 21487 | *speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; |
| 21488 | } |
| 21489 | } |
| 21490 | return up; |
| 21491 | } |
| 21492 | |
| 21493 | #ifdef MG_ENABLE_LINES |
| 21494 | #line 1 "src/drivers/pico-w.c" |
| 21495 | #endif |
| 21496 | #if MG_ENABLE_TCPIP && MG_ARCH == MG_ARCH_PICOSDK && \ |
| 21497 | defined(MG_ENABLE_DRIVER_PICO_W) && MG_ENABLE_DRIVER_PICO_W |
| 21498 | |
| 21499 | |
| 21500 | |
| 21501 | |
| 21502 | |
| 21503 | static struct mg_tcpip_if *s_ifp; |
| 21504 | |
| 21505 | static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) { |
| 21506 | struct mg_tcpip_driver_pico_w_data *d = |
| 21507 | (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; |
| 21508 | s_ifp = ifp; |
| 21509 | if (cyw43_arch_init() != 0) |
| 21510 | return false; // initialize async_context and WiFi chip |
| 21511 | if (d->apmode && d->apssid != NULL) { |
| 21512 | MG_DEBUG(("Starting AP '%s' (%u)", d->apssid, d->apchannel)); |
| 21513 | if (!mg_wifi_ap_start(d->apssid, d->appass, d->apchannel)) return false; |
| 21514 | cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); // same MAC |
| 21515 | } else { |
| 21516 | cyw43_arch_enable_sta_mode(); |
| 21517 | cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac); |
| 21518 | if (d->ssid != NULL) { |
| 21519 | MG_DEBUG(("Connecting to '%s'", d->ssid)); |
| 21520 | return mg_wifi_connect(d->ssid, d->pass); |
| 21521 | } else { |
| 21522 | cyw43_arch_disable_sta_mode(); |
| 21523 | } |
| 21524 | } |
| 21525 | return true; |
| 21526 | } |
| 21527 | |
| 21528 | static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len, |
| 21529 | struct mg_tcpip_if *ifp) { |
| 21530 | struct mg_tcpip_driver_pico_w_data *d = |
| 21531 | (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; |
| 21532 | return cyw43_send_ethernet(&cyw43_state, |
| 21533 | d->apmode ? CYW43_ITF_AP : CYW43_ITF_STA, len, buf, |
| 21534 | false) == 0 |
| 21535 | ? len |
| 21536 | : 0; |
| 21537 | } |
| 21538 | |
| 21539 | static bool s_aplink = false, s_scanning = false; |
| 21540 | static bool s_stalink = false, s_connecting = false; |
| 21541 | |
| 21542 | static bool mg_tcpip_driver_pico_w_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 21543 | cyw43_arch_poll(); // not necessary, except when IRQs are disabled (OTA) |
| 21544 | if (s_scanning && !cyw43_wifi_scan_active(&cyw43_state)) { |
| 21545 | MG_VERBOSE(("scan complete")); |
| 21546 | s_scanning = 0; |
| 21547 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL); |
| 21548 | } |
| 21549 | if (ifp->update_mac_hash_table) { |
| 21550 | // first call to _poll() is after _init(), so this is safe |
| 21551 | cyw43_wifi_update_multicast_filter(&cyw43_state, (uint8_t *)mcast_addr, true); |
| 21552 | ifp->update_mac_hash_table = false; |
| 21553 | } |
| 21554 | if (!s1) return false; |
| 21555 | struct mg_tcpip_driver_pico_w_data *d = |
| 21556 | (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data; |
| 21557 | if (d->apmode) return s_aplink; |
| 21558 | int sdkstate = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA); |
| 21559 | MG_VERBOSE(("conn: %c state: %d", s_connecting ? '1' : '0', sdkstate)); |
| 21560 | if (sdkstate < 0 && s_connecting) { |
| 21561 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, &sdkstate); |
| 21562 | s_connecting = false; |
| 21563 | } |
| 21564 | return s_stalink; |
| 21565 | } |
| 21566 | |
| 21567 | struct mg_tcpip_driver mg_tcpip_driver_pico_w = { |
| 21568 | mg_tcpip_driver_pico_w_init, |
| 21569 | mg_tcpip_driver_pico_w_tx, |
| 21570 | NULL, |
| 21571 | mg_tcpip_driver_pico_w_poll, |
| 21572 | }; |
| 21573 | |
| 21574 | // Called once per outstanding frame by async_context |
| 21575 | void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, |
| 21576 | const uint8_t *buf) { |
| 21577 | mg_tcpip_qwrite((void *) buf, len, s_ifp); |
| 21578 | (void) cb_data; |
| 21579 | } |
| 21580 | |
| 21581 | // Called by async_context |
| 21582 | void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) { |
| 21583 | if (itf == CYW43_ITF_AP) { |
| 21584 | s_aplink = true; |
| 21585 | } else { |
| 21586 | s_stalink = true; |
| 21587 | s_connecting = false; |
| 21588 | } |
| 21589 | } |
| 21590 | void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) { |
| 21591 | if (itf == CYW43_ITF_AP) { |
| 21592 | s_aplink = false; |
| 21593 | } else { |
| 21594 | s_stalink = false; |
| 21595 | // SDK calls this before we check status, don't clear s_connecting here |
| 21596 | } |
| 21597 | } |
| 21598 | |
| 21599 | // there's life beyond lwIP |
| 21600 | void pbuf_copy_partial(void) { |
| 21601 | (void) 0; |
| 21602 | } |
| 21603 | |
| 21604 | static int result_cb(void *arg, const cyw43_ev_scan_result_t *data) { |
| 21605 | struct mg_wifi_scan_bss_data bss; |
| 21606 | bss.SSID = mg_str_n(data->ssid, data->ssid_len); |
| 21607 | bss.BSSID = (char *) data->bssid; |
| 21608 | bss.RSSI = (int8_t) data->rssi; |
| 21609 | bss.has_n = 0; // SDK ignores this |
| 21610 | bss.channel = (uint8_t) data->channel; |
| 21611 | bss.band = MG_WIFI_BAND_2G; |
| 21612 | // SDK-internal dependency, 2.1.0 |
| 21613 | bss.security = data->auth_mode & MG_BIT(0) ? MG_WIFI_SECURITY_WEP |
| 21614 | : MG_WIFI_SECURITY_OPEN; |
| 21615 | if (data->auth_mode & MG_BIT(1)) bss.security |= MG_WIFI_SECURITY_WPA; |
| 21616 | if (data->auth_mode & MG_BIT(2)) bss.security |= MG_WIFI_SECURITY_WPA2; |
| 21617 | MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, |
| 21618 | bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, |
| 21619 | bss.security)); |
| 21620 | mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss); |
| 21621 | return 0; |
| 21622 | } |
| 21623 | |
| 21624 | bool mg_wifi_scan(void) { |
| 21625 | cyw43_wifi_scan_options_t opts; |
| 21626 | memset(&opts, 0, sizeof(opts)); |
| 21627 | bool res = (cyw43_wifi_scan(&cyw43_state, &opts, NULL, result_cb) == 0); |
| 21628 | if (res) s_scanning = true; |
| 21629 | return res; |
| 21630 | } |
| 21631 | |
| 21632 | bool mg_wifi_connect(char *ssid, char *pass) { |
| 21633 | cyw43_arch_enable_sta_mode(); |
| 21634 | int res = cyw43_arch_wifi_connect_async(ssid, pass, CYW43_AUTH_WPA2_AES_PSK); |
| 21635 | MG_VERBOSE(("res: %d", res)); |
| 21636 | if (res == 0) s_connecting = true; |
| 21637 | return (res == 0); |
| 21638 | } |
| 21639 | |
| 21640 | bool mg_wifi_disconnect(void) { |
| 21641 | cyw43_arch_disable_sta_mode(); |
| 21642 | s_connecting = false; |
| 21643 | return true; |
| 21644 | } |
| 21645 | |
| 21646 | bool mg_wifi_ap_start(char *ssid, char *pass, unsigned int channel) { |
| 21647 | cyw43_wifi_ap_set_channel(&cyw43_state, channel); |
| 21648 | cyw43_arch_enable_ap_mode(ssid, pass, CYW43_AUTH_WPA2_AES_PSK); |
| 21649 | return true; |
| 21650 | } |
| 21651 | |
| 21652 | bool mg_wifi_ap_stop(void) { |
| 21653 | cyw43_arch_disable_ap_mode(); |
| 21654 | return true; |
| 21655 | } |
| 21656 | |
| 21657 | #endif |
| 21658 | |
| 21659 | #ifdef MG_ENABLE_LINES |
| 21660 | #line 1 "src/drivers/ppp.c" |
| 21661 | #endif |
| 21662 | |
| 21663 | |
| 21664 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_PPP) && MG_ENABLE_DRIVER_PPP |
| 21665 | |
| 21666 | #define MG_PPP_FLAG 0x7e // PPP frame delimiter |
| 21667 | #define MG_PPP_ESC 0x7d // PPP escape byte for special characters |
| 21668 | #define MG_PPP_ADDR 0xff |
| 21669 | #define MG_PPP_CTRL 0x03 |
| 21670 | |
| 21671 | #define MG_PPP_PROTO_IP 0x0021 |
| 21672 | #define MG_PPP_PROTO_LCP 0xc021 |
| 21673 | #define MG_PPP_PROTO_IPCP 0x8021 |
| 21674 | |
| 21675 | #define MG_PPP_IPCP_REQ 1 |
| 21676 | #define MG_PPP_IPCP_ACK 2 |
| 21677 | #define MG_PPP_IPCP_NACK 3 |
| 21678 | #define MG_PPP_IPCP_IPADDR 3 |
| 21679 | |
| 21680 | #define MG_PPP_LCP_CFG_REQ 1 |
| 21681 | #define MG_PPP_LCP_CFG_ACK 2 |
| 21682 | #define MG_PPP_LCP_CFG_NACK 3 |
| 21683 | #define MG_PPP_LCP_CFG_REJECT 4 |
| 21684 | #define MG_PPP_LCP_CFG_TERM_REQ 5 |
| 21685 | #define MG_PPP_LCP_CFG_TERM_ACK 6 |
| 21686 | |
| 21687 | #define MG_PPP_AT_TIMEOUT 2000 |
| 21688 | |
| 21689 | static size_t print_atcmd(void (*out)(char, void *), void *arg, va_list *ap) { |
| 21690 | struct mg_str s = va_arg(*ap, struct mg_str); |
| 21691 | for (size_t i = 0; i < s.len; i++) out(s.buf[i] < 0x20 ? '.' : s.buf[i], arg); |
| 21692 | return s.len; |
| 21693 | } |
| 21694 | |
| 21695 | static void mg_ppp_reset(struct mg_tcpip_driver_ppp_data *dd) { |
| 21696 | dd->script_index = 0; |
| 21697 | dd->deadline = 0; |
| 21698 | if (dd->reset) dd->reset(dd->uart); |
| 21699 | } |
| 21700 | |
| 21701 | static bool mg_ppp_atcmd_handle(struct mg_tcpip_if *ifp) { |
| 21702 | struct mg_tcpip_driver_ppp_data *dd = |
| 21703 | (struct mg_tcpip_driver_ppp_data *) ifp->driver_data; |
| 21704 | if (dd->script == NULL || dd->script_index < 0) return true; |
| 21705 | if (dd->deadline == 0) dd->deadline = mg_millis() + MG_PPP_AT_TIMEOUT; |
| 21706 | for (;;) { |
| 21707 | if (dd->script_index % 2 == 0) { // send AT command |
| 21708 | const char *cmd = dd->script[dd->script_index]; |
| 21709 | MG_DEBUG(("send AT[%d]: %M", dd->script_index, print_atcmd, mg_str(cmd))); |
| 21710 | while (*cmd) dd->tx(dd->uart, *cmd++); |
| 21711 | dd->script_index++; |
| 21712 | ifp->recv_queue.head = 0; |
| 21713 | } else { // check AT command response |
| 21714 | const char *expect = dd->script[dd->script_index]; |
| 21715 | struct mg_queue *q = &ifp->recv_queue; |
| 21716 | for (;;) { |
| 21717 | int c; |
| 21718 | int is_timeout = dd->deadline > 0 && mg_millis() > dd->deadline; |
| 21719 | int is_overflow = q->head >= q->size - 1; |
| 21720 | if (is_timeout || is_overflow) { |
| 21721 | MG_ERROR(("AT error: %s, retrying...", |
| 21722 | is_timeout ? "timeout" : "overflow")); |
| 21723 | mg_ppp_reset(dd); |
| 21724 | return false; // FAIL: timeout |
| 21725 | } |
| 21726 | if ((c = dd->rx(dd->uart)) < 0) return false; // no data |
| 21727 | q->buf[q->head++] = c; |
| 21728 | if (mg_match(mg_str_n(q->buf, q->head), mg_str(expect), NULL)) { |
| 21729 | MG_DEBUG(("recv AT[%d]: %M", dd->script_index, print_atcmd, |
| 21730 | mg_str_n(q->buf, q->head))); |
| 21731 | dd->script_index++; |
| 21732 | q->head = 0; |
| 21733 | break; |
| 21734 | } |
| 21735 | } |
| 21736 | } |
| 21737 | if (dd->script[dd->script_index] == NULL) { |
| 21738 | MG_DEBUG(("finished AT script")); |
| 21739 | dd->script_index = -1; |
| 21740 | return true; |
| 21741 | } |
| 21742 | } |
| 21743 | } |
| 21744 | |
| 21745 | static bool mg_ppp_init(struct mg_tcpip_if *ifp) { |
| 21746 | ifp->recv_queue.size = 3000; // MTU=1500, worst case escaping = 2x |
| 21747 | return true; |
| 21748 | } |
| 21749 | |
| 21750 | // Calculate FCS/CRC for PPP frames. Could be implemented faster using lookup |
| 21751 | // tables. |
| 21752 | static uint32_t fcs_do(uint32_t fcs, uint8_t x) { |
| 21753 | for (int i = 0; i < 8; i++) { |
| 21754 | fcs = ((fcs ^ x) & 1) ? (fcs >> 1) ^ 0x8408 : fcs >> 1; |
| 21755 | x >>= 1; |
| 21756 | } |
| 21757 | return fcs; |
| 21758 | } |
| 21759 | |
| 21760 | static bool mg_ppp_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 21761 | (void) s1; |
| 21762 | return ifp->driver_data != NULL; |
| 21763 | } |
| 21764 | |
| 21765 | // Transmit a single byte as part of the PPP frame (escaped, if needed) |
| 21766 | static void mg_ppp_tx_byte(struct mg_tcpip_driver_ppp_data *dd, uint8_t b) { |
| 21767 | if ((b < 0x20) || (b == MG_PPP_ESC) || (b == MG_PPP_FLAG)) { |
| 21768 | dd->tx(dd->uart, MG_PPP_ESC); |
| 21769 | dd->tx(dd->uart, b ^ 0x20); |
| 21770 | } else { |
| 21771 | dd->tx(dd->uart, b); |
| 21772 | } |
| 21773 | } |
| 21774 | |
| 21775 | // Transmit a single PPP frame for the given protocol |
| 21776 | static void mg_ppp_tx_frame(struct mg_tcpip_driver_ppp_data *dd, uint16_t proto, |
| 21777 | uint8_t *data, size_t datasz) { |
| 21778 | uint16_t crc; |
| 21779 | uint32_t fcs = 0xffff; |
| 21780 | |
| 21781 | dd->tx(dd->uart, MG_PPP_FLAG); |
| 21782 | mg_ppp_tx_byte(dd, MG_PPP_ADDR); |
| 21783 | mg_ppp_tx_byte(dd, MG_PPP_CTRL); |
| 21784 | mg_ppp_tx_byte(dd, proto >> 8); |
| 21785 | mg_ppp_tx_byte(dd, proto & 0xff); |
| 21786 | fcs = fcs_do(fcs, MG_PPP_ADDR); |
| 21787 | fcs = fcs_do(fcs, MG_PPP_CTRL); |
| 21788 | fcs = fcs_do(fcs, proto >> 8); |
| 21789 | fcs = fcs_do(fcs, proto & 0xff); |
| 21790 | for (unsigned int i = 0; i < datasz; i++) { |
| 21791 | mg_ppp_tx_byte(dd, data[i]); |
| 21792 | fcs = fcs_do(fcs, data[i]); |
| 21793 | } |
| 21794 | crc = fcs & 0xffff; |
| 21795 | mg_ppp_tx_byte(dd, ~crc); // send CRC, note the byte order |
| 21796 | mg_ppp_tx_byte(dd, ~crc >> 8); |
| 21797 | dd->tx(dd->uart, MG_PPP_FLAG); // end of frame |
| 21798 | } |
| 21799 | |
| 21800 | // Send Ethernet frame as PPP frame |
| 21801 | static size_t mg_ppp_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) { |
| 21802 | struct mg_tcpip_driver_ppp_data *dd = |
| 21803 | (struct mg_tcpip_driver_ppp_data *) ifp->driver_data; |
| 21804 | if (ifp->state != MG_TCPIP_STATE_READY) return 0; |
| 21805 | // XXX: what if not an IP protocol? |
| 21806 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_IP, (uint8_t *) buf + 14, len - 14); |
| 21807 | return len; |
| 21808 | } |
| 21809 | |
| 21810 | // Given a full PPP frame, unescape it in place and verify FCS, returns actual |
| 21811 | // data size on success or 0 on error. |
| 21812 | static size_t mg_ppp_verify_frame(uint8_t *buf, size_t bufsz) { |
| 21813 | int unpack = 0; |
| 21814 | uint16_t crc; |
| 21815 | size_t pktsz = 0; |
| 21816 | uint32_t fcs = 0xffff; |
| 21817 | for (unsigned int i = 0; i < bufsz; i++) { |
| 21818 | if (unpack == 0) { |
| 21819 | if (buf[i] == 0x7d) { |
| 21820 | unpack = 1; |
| 21821 | } else { |
| 21822 | buf[pktsz] = buf[i]; |
| 21823 | fcs = fcs_do(fcs, buf[pktsz]); |
| 21824 | pktsz++; |
| 21825 | } |
| 21826 | } else { |
| 21827 | unpack = 0; |
| 21828 | buf[pktsz] = buf[i] ^ 0x20; |
| 21829 | fcs = fcs_do(fcs, buf[pktsz]); |
| 21830 | pktsz++; |
| 21831 | } |
| 21832 | } |
| 21833 | crc = fcs & 0xffff; |
| 21834 | if (crc != 0xf0b8) { |
| 21835 | MG_DEBUG(("bad crc: %04x", crc)); |
| 21836 | return 0; |
| 21837 | } |
| 21838 | if (pktsz < 6 || buf[0] != MG_PPP_ADDR || buf[1] != MG_PPP_CTRL) { |
| 21839 | return 0; |
| 21840 | } |
| 21841 | return pktsz - 2; // strip FCS |
| 21842 | } |
| 21843 | |
| 21844 | // fetch as much data as we can, until a single PPP frame is received |
| 21845 | static size_t mg_ppp_rx_frame(struct mg_tcpip_driver_ppp_data *dd, |
| 21846 | struct mg_queue *q) { |
| 21847 | while (q->head < q->size) { |
| 21848 | int c; |
| 21849 | if ((c = dd->rx(dd->uart)) < 0) { |
| 21850 | return 0; |
| 21851 | } |
| 21852 | if (c == MG_PPP_FLAG) { |
| 21853 | if (q->head > 0) { |
| 21854 | break; |
| 21855 | } else { |
| 21856 | continue; |
| 21857 | } |
| 21858 | } |
| 21859 | q->buf[q->head++] = c; |
| 21860 | } |
| 21861 | |
| 21862 | size_t n = mg_ppp_verify_frame((uint8_t *) q->buf, q->head); |
| 21863 | if (n == 0) { |
| 21864 | MG_DEBUG(("invalid PPP frame of %d bytes", q->head)); |
| 21865 | q->head = 0; |
| 21866 | return 0; |
| 21867 | } |
| 21868 | q->head = n; |
| 21869 | return q->head; |
| 21870 | } |
| 21871 | |
| 21872 | static void mg_ppp_handle_lcp(struct mg_tcpip_if *ifp, uint8_t *lcp, |
| 21873 | size_t lcpsz) { |
| 21874 | uint8_t id; |
| 21875 | uint16_t len; |
| 21876 | struct mg_tcpip_driver_ppp_data *dd = |
| 21877 | (struct mg_tcpip_driver_ppp_data *) ifp->driver_data; |
| 21878 | if (lcpsz < 4) return; |
| 21879 | id = lcp[1]; |
| 21880 | len = (((uint16_t) lcp[2]) << 8) | (lcp[3]); |
| 21881 | switch (lcp[0]) { |
| 21882 | case MG_PPP_LCP_CFG_REQ: { |
| 21883 | if (len == 4) { |
| 21884 | MG_DEBUG(("LCP config request of %d bytes, acknowledging...", len)); |
| 21885 | lcp[0] = MG_PPP_LCP_CFG_ACK; |
| 21886 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_LCP, lcp, len); |
| 21887 | lcp[0] = MG_PPP_LCP_CFG_REQ; |
| 21888 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_LCP, lcp, len); |
| 21889 | } else { |
| 21890 | MG_DEBUG(("LCP config request of %d bytes, rejecting...", len)); |
| 21891 | lcp[0] = MG_PPP_LCP_CFG_REJECT; |
| 21892 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_LCP, lcp, len); |
| 21893 | } |
| 21894 | } break; |
| 21895 | case MG_PPP_LCP_CFG_TERM_REQ: { |
| 21896 | uint8_t ack[4] = {MG_PPP_LCP_CFG_TERM_ACK, id, 0, 4}; |
| 21897 | MG_DEBUG(("LCP termination request, acknowledging...")); |
| 21898 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_LCP, ack, sizeof(ack)); |
| 21899 | mg_ppp_reset(dd); |
| 21900 | ifp->state = MG_TCPIP_STATE_UP; |
| 21901 | if (dd->reset) dd->reset(dd->uart); |
| 21902 | } break; |
| 21903 | } |
| 21904 | } |
| 21905 | |
| 21906 | static void mg_ppp_handle_ipcp(struct mg_tcpip_if *ifp, uint8_t *ipcp, |
| 21907 | size_t ipcpsz) { |
| 21908 | struct mg_tcpip_driver_ppp_data *dd = |
| 21909 | (struct mg_tcpip_driver_ppp_data *) ifp->driver_data; |
| 21910 | uint16_t len; |
| 21911 | uint8_t id; |
| 21912 | uint8_t req[] = { |
| 21913 | MG_PPP_IPCP_REQ, 0, 0, 10, MG_PPP_IPCP_IPADDR, 6, 0, 0, 0, 0}; |
| 21914 | if (ipcpsz < 4) return; |
| 21915 | id = ipcp[1]; |
| 21916 | len = (((uint16_t) ipcp[2]) << 8) | (ipcp[3]); |
| 21917 | switch (ipcp[0]) { |
| 21918 | case MG_PPP_IPCP_REQ: |
| 21919 | MG_DEBUG(("got IPCP config request, acknowledging...")); |
| 21920 | if (len >= 10 && ipcp[4] == MG_PPP_IPCP_IPADDR) { |
| 21921 | uint8_t *ip = ipcp + 6; |
| 21922 | MG_DEBUG(("host ip: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])); |
| 21923 | } |
| 21924 | ipcp[0] = MG_PPP_IPCP_ACK; |
| 21925 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_IPCP, ipcp, len); |
| 21926 | req[1] = id; |
| 21927 | // Request IP address 0.0.0.0 |
| 21928 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_IPCP, req, sizeof(req)); |
| 21929 | break; |
| 21930 | case MG_PPP_IPCP_ACK: |
| 21931 | // This usually does not happen, as our "preferred" IP address is invalid |
| 21932 | MG_DEBUG(("got IPCP config ack, link is online now")); |
| 21933 | ifp->state = MG_TCPIP_STATE_READY; |
| 21934 | break; |
| 21935 | case MG_PPP_IPCP_NACK: |
| 21936 | MG_DEBUG(("got IPCP config nack")); |
| 21937 | // NACK contains our "suggested" IP address, use it |
| 21938 | if (len >= 10 && ipcp[4] == MG_PPP_IPCP_IPADDR) { |
| 21939 | uint8_t *ip = ipcp + 6; |
| 21940 | MG_DEBUG(("ipcp ack, ip: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])); |
| 21941 | ipcp[0] = MG_PPP_IPCP_REQ; |
| 21942 | mg_ppp_tx_frame(dd, MG_PPP_PROTO_IPCP, ipcp, len); |
| 21943 | ifp->ip = ifp->mask = MG_IPV4(ip[0], ip[1], ip[2], ip[3]); |
| 21944 | ifp->state = MG_TCPIP_STATE_READY; |
| 21945 | } |
| 21946 | break; |
| 21947 | } |
| 21948 | } |
| 21949 | |
| 21950 | static size_t mg_ppp_rx(void *ethbuf, size_t ethlen, struct mg_tcpip_if *ifp) { |
| 21951 | uint8_t *eth = ethbuf; |
| 21952 | size_t ethsz = 0; |
| 21953 | struct mg_tcpip_driver_ppp_data *dd = |
| 21954 | (struct mg_tcpip_driver_ppp_data *) ifp->driver_data; |
| 21955 | uint8_t *buf = (uint8_t *) ifp->recv_queue.buf; |
| 21956 | |
| 21957 | if (!mg_ppp_atcmd_handle(ifp)) return 0; |
| 21958 | |
| 21959 | size_t bufsz = mg_ppp_rx_frame(dd, &ifp->recv_queue); |
| 21960 | if (!bufsz) return 0; |
| 21961 | uint16_t proto = (((uint16_t) buf[2]) << 8) | (uint16_t) buf[3]; |
| 21962 | switch (proto) { |
| 21963 | case MG_PPP_PROTO_LCP: mg_ppp_handle_lcp(ifp, buf + 4, bufsz - 4); break; |
| 21964 | case MG_PPP_PROTO_IPCP: mg_ppp_handle_ipcp(ifp, buf + 4, bufsz - 4); break; |
| 21965 | case MG_PPP_PROTO_IP: |
| 21966 | MG_VERBOSE(("got IP packet of %d bytes", bufsz - 4)); |
| 21967 | memmove(eth + 14, buf + 4, bufsz - 4); |
| 21968 | memmove(eth, ifp->mac, 6); |
| 21969 | memmove(eth + 6, "\xff\xff\xff\xff\xff\xff", 6); |
| 21970 | eth[12] = 0x08; |
| 21971 | eth[13] = 0x00; |
| 21972 | ethsz = bufsz - 4 + 14; |
| 21973 | ifp->recv_queue.head = 0; |
| 21974 | return ethsz; |
| 21975 | #if 0 |
| 21976 | default: |
| 21977 | MG_DEBUG(("unknown PPP frame:")); |
| 21978 | mg_hexdump(ppp->buf, ppp->bufsz); |
| 21979 | #endif |
| 21980 | } |
| 21981 | ifp->recv_queue.head = 0; |
| 21982 | return 0; |
| 21983 | (void) ethlen; |
| 21984 | } |
| 21985 | |
| 21986 | struct mg_tcpip_driver mg_tcpip_driver_ppp = {mg_ppp_init, mg_ppp_tx, mg_ppp_rx, |
| 21987 | mg_ppp_up}; |
| 21988 | |
| 21989 | #endif |
| 21990 | |
| 21991 | #ifdef MG_ENABLE_LINES |
| 21992 | #line 1 "src/drivers/ra.c" |
| 21993 | #endif |
| 21994 | |
| 21995 | |
| 21996 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA |
| 21997 | struct ra_etherc { |
| 21998 | volatile uint32_t ECMR, RESERVED, RFLR, RESERVED1, ECSR, RESERVED2, ECSIPR, |
| 21999 | RESERVED3, PIR, RESERVED4, PSR, RESERVED5[5], RDMLR, RESERVED6[3], IPGR, |
| 22000 | APR, MPR, RESERVED7, RFCF, TPAUSER, TPAUSECR, BCFRR, RESERVED8[20], MAHR, |
| 22001 | RESERVED9, MALR, RESERVED10, TROCR, CDCR, LCCR, CNDCR, RESERVED11, CEFCR, |
| 22002 | FRECR, TSFRCR, TLFRCR, RFCR, MAFCR; |
| 22003 | }; |
| 22004 | |
| 22005 | struct ra_edmac { |
| 22006 | volatile uint32_t EDMR, RESERVED, EDTRR, RESERVED1, EDRRR, RESERVED2, TDLAR, |
| 22007 | RESERVED3, RDLAR, RESERVED4, EESR, RESERVED5, EESIPR, RESERVED6, TRSCER, |
| 22008 | RESERVED7, RMFCR, RESERVED8, TFTR, RESERVED9, FDR, RESERVED10, RMCR, |
| 22009 | RESERVED11[2], TFUCR, RFOCR, IOSR, FCFTR, RESERVED12, RPADIR, TRIMD, |
| 22010 | RESERVED13[18], RBWAR, RDFAR, RESERVED14, TBRAR, TDFAR; |
| 22011 | }; |
| 22012 | |
| 22013 | #undef ETHERC |
| 22014 | #define ETHERC ((struct ra_etherc *) (uintptr_t) 0x40114100U) |
| 22015 | #undef EDMAC |
| 22016 | #define EDMAC ((struct ra_edmac *) (uintptr_t) 0x40114000U) |
| 22017 | #undef RASYSC |
| 22018 | #define RASYSC ((uint32_t *) (uintptr_t) 0x4001E000U) |
| 22019 | #undef ICU_IELSR |
| 22020 | #define ICU_IELSR ((uint32_t *) (uintptr_t) 0x40006300U) |
| 22021 | |
| 22022 | #define ETH_PKT_SIZE 1536 // Max frame size, multiple of 32 |
| 22023 | #define ETH_DESC_CNT 4 // Descriptors count |
| 22024 | |
| 22025 | // TODO(): handle these in a portable compiler-independent CMSIS-friendly way |
| 22026 | #define MG_16BYTE_ALIGNED __attribute__((aligned((16U)))) |
| 22027 | #define MG_32BYTE_ALIGNED __attribute__((aligned((32U)))) |
| 22028 | |
| 22029 | // Descriptors: 16-byte aligned |
| 22030 | // Buffers: 32-byte aligned (27.3.1) |
| 22031 | static volatile uint32_t s_rxdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED; |
| 22032 | static volatile uint32_t s_txdesc[ETH_DESC_CNT][4] MG_16BYTE_ALIGNED; |
| 22033 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED; |
| 22034 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED; |
| 22035 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 22036 | |
| 22037 | // fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent |
| 22038 | static inline void raspin(volatile uint32_t count) { |
| 22039 | while (count--) (void) 0; |
| 22040 | } |
| 22041 | // count to get the 200ns SMC semi-cycle period (2.5MHz) calling raspin(): |
| 22042 | // SYS_FREQUENCY * 200ns / 3 = SYS_FREQUENCY / 15000000 |
| 22043 | static uint32_t s_smispin; |
| 22044 | |
| 22045 | // Bit-banged SMI |
| 22046 | static void smi_preamble(void) { |
| 22047 | unsigned int i = 32; |
| 22048 | uint32_t pir = MG_BIT(1) | MG_BIT(2); // write, mdio = 1, mdc = 0 |
| 22049 | ETHERC->PIR = pir; |
| 22050 | while (i--) { |
| 22051 | pir &= ~MG_BIT(0); // mdc = 0 |
| 22052 | ETHERC->PIR = pir; |
| 22053 | raspin(s_smispin); |
| 22054 | pir |= MG_BIT(0); // mdc = 1 |
| 22055 | ETHERC->PIR = pir; |
| 22056 | raspin(s_smispin); |
| 22057 | } |
| 22058 | } |
| 22059 | static void smi_wr(uint16_t header, uint16_t data) { |
| 22060 | uint32_t word = (header << 16) | data; |
| 22061 | smi_preamble(); |
| 22062 | unsigned int i = 32; |
| 22063 | while (i--) { |
| 22064 | uint32_t pir = MG_BIT(1) | |
| 22065 | (word & 0x80000000 ? MG_BIT(2) : 0); // write, mdc = 0, data |
| 22066 | ETHERC->PIR = pir; |
| 22067 | raspin(s_smispin); |
| 22068 | pir |= MG_BIT(0); // mdc = 1 |
| 22069 | ETHERC->PIR = pir; |
| 22070 | raspin(s_smispin); |
| 22071 | word <<= 1; |
| 22072 | } |
| 22073 | } |
| 22074 | static uint16_t smi_rd(uint16_t header) { |
| 22075 | smi_preamble(); |
| 22076 | unsigned int i = 16; // 2 LSb as turnaround |
| 22077 | uint32_t pir; |
| 22078 | while (i--) { |
| 22079 | pir = (i > 1 ? MG_BIT(1) : 0) | |
| 22080 | (header & 0x8000 |
| 22081 | ? MG_BIT(2) |
| 22082 | : 0); // mdc = 0, header, set read direction at turnaround |
| 22083 | ETHERC->PIR = pir; |
| 22084 | raspin(s_smispin); |
| 22085 | pir |= MG_BIT(0); // mdc = 1 |
| 22086 | ETHERC->PIR = pir; |
| 22087 | raspin(s_smispin); |
| 22088 | header <<= 1; |
| 22089 | } |
| 22090 | i = 16; |
| 22091 | uint16_t data = 0; |
| 22092 | while (i--) { |
| 22093 | data <<= 1; |
| 22094 | pir = 0; // read, mdc = 0 |
| 22095 | ETHERC->PIR = pir; |
| 22096 | raspin(s_smispin / 2); // 1/4 clock period, 300ns max access time |
| 22097 | data |= (uint16_t) (ETHERC->PIR & MG_BIT(3) ? 1 : 0); // read mdio |
| 22098 | raspin(s_smispin / 2); // 1/4 clock period |
| 22099 | pir |= MG_BIT(0); // mdc = 1 |
| 22100 | ETHERC->PIR = pir; |
| 22101 | raspin(s_smispin); |
| 22102 | } |
| 22103 | return data; |
| 22104 | } |
| 22105 | |
| 22106 | static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) { |
| 22107 | return smi_rd( |
| 22108 | (uint16_t) ((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0))); |
| 22109 | } |
| 22110 | |
| 22111 | static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 22112 | smi_wr( |
| 22113 | (uint16_t) ((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0)), |
| 22114 | val); |
| 22115 | } |
| 22116 | |
| 22117 | // MDC clock is generated manually; as per 802.3, it must not exceed 2.5MHz |
| 22118 | static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) { |
| 22119 | struct mg_tcpip_driver_ra_data *d = |
| 22120 | (struct mg_tcpip_driver_ra_data *) ifp->driver_data; |
| 22121 | s_ifp = ifp; |
| 22122 | |
| 22123 | // Init SMI clock timing. If user told us the clock value, use it. |
| 22124 | // TODO(): Otherwise, guess |
| 22125 | s_smispin = d->clock / 15000000; |
| 22126 | |
| 22127 | // Init RX descriptors |
| 22128 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 22129 | s_rxdesc[i][0] = MG_BIT(31); // RACT |
| 22130 | s_rxdesc[i][1] = ETH_PKT_SIZE << 16; // RBL |
| 22131 | s_rxdesc[i][2] = (uint32_t) s_rxbuf[i]; // Point to data buffer |
| 22132 | } |
| 22133 | s_rxdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(30); // Wrap last descriptor |
| 22134 | |
| 22135 | // Init TX descriptors |
| 22136 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 22137 | // TACT = 0 |
| 22138 | s_txdesc[i][2] = (uint32_t) s_txbuf[i]; |
| 22139 | } |
| 22140 | s_txdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(30); // Wrap last descriptor |
| 22141 | |
| 22142 | EDMAC->EDMR = MG_BIT(0); // Software reset, wait 64 PCLKA clocks (27.2.1) |
| 22143 | uint32_t sckdivcr = RASYSC[8]; // get divisors from SCKDIVCR (8.2.2) |
| 22144 | uint32_t ick = 1 << ((sckdivcr >> 24) & 7); // sys_clock div |
| 22145 | uint32_t pcka = 1 << ((sckdivcr >> 12) & 7); // pclka div |
| 22146 | raspin((64U * pcka) / (3U * ick)); |
| 22147 | EDMAC->EDMR = MG_BIT(6); // Initialize, little-endian (27.2.1) |
| 22148 | |
| 22149 | MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin)); |
| 22150 | struct mg_phy phy = {raeth_read_phy, raeth_write_phy}; |
| 22151 | mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY |
| 22152 | |
| 22153 | // Select RMII mode, |
| 22154 | ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC |
| 22155 | // ETHERC->ECMR |= MG_BIT(0); // Receive all |
| 22156 | ETHERC->RFLR = 1518; // Set max rx length |
| 22157 | |
| 22158 | EDMAC->RDLAR = (uint32_t) (uintptr_t) s_rxdesc; |
| 22159 | EDMAC->TDLAR = (uint32_t) (uintptr_t) s_txdesc; |
| 22160 | // MAC address filtering (bytes in reversed order) |
| 22161 | ETHERC->MAHR = (uint32_t) (ifp->mac[0] << 24U) | |
| 22162 | ((uint32_t) ifp->mac[1] << 16U) | |
| 22163 | ((uint32_t) ifp->mac[2] << 8U) | ifp->mac[3]; |
| 22164 | ETHERC->MALR = ((uint32_t) ifp->mac[4] << 8U) | ifp->mac[5]; |
| 22165 | |
| 22166 | EDMAC->TFTR = 0; // Store and forward (27.2.10) |
| 22167 | EDMAC->FDR = 0x070f; // (27.2.11) |
| 22168 | EDMAC->RMCR = MG_BIT(0); // (27.2.12) |
| 22169 | ETHERC->ECMR |= MG_BIT(6) | MG_BIT(5); // TE RE |
| 22170 | EDMAC->EESIPR = MG_BIT(18); // FR: Enable Rx (frame) IRQ |
| 22171 | EDMAC->EDRRR = MG_BIT(0); // Receive Descriptors have changed |
| 22172 | EDMAC->EDTRR = MG_BIT(0); // Transmit Descriptors have changed |
| 22173 | return true; |
| 22174 | } |
| 22175 | |
| 22176 | // Transmit frame |
| 22177 | static size_t mg_tcpip_driver_ra_tx(const void *buf, size_t len, |
| 22178 | struct mg_tcpip_if *ifp) { |
| 22179 | static int s_txno; // Current descriptor index |
| 22180 | if (len > sizeof(s_txbuf[ETH_DESC_CNT])) { |
| 22181 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 22182 | len = (size_t) -1; // fail |
| 22183 | } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { |
| 22184 | ifp->nerr++; |
| 22185 | MG_ERROR(("No descriptors available")); |
| 22186 | len = 0; // retry later |
| 22187 | } else { |
| 22188 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 22189 | s_txdesc[s_txno][1] = len << 16; // Set data len |
| 22190 | s_txdesc[s_txno][0] |= MG_BIT(31) | 3 << 28; // (27.3.1.1) mark valid |
| 22191 | EDMAC->EDTRR = MG_BIT(0); // Transmit request |
| 22192 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 22193 | } |
| 22194 | return len; |
| 22195 | } |
| 22196 | |
| 22197 | static bool mg_tcpip_driver_ra_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 22198 | if (ifp->update_mac_hash_table) { |
| 22199 | EDMAC->EESIPR = MG_BIT(18) | MG_BIT(7); // FR, RMAF: Frame and mcast IRQ |
| 22200 | ifp->update_mac_hash_table = false; |
| 22201 | } |
| 22202 | if (!s1) return false; |
| 22203 | struct mg_tcpip_driver_ra_data *d = |
| 22204 | (struct mg_tcpip_driver_ra_data *) ifp->driver_data; |
| 22205 | uint8_t speed = MG_PHY_SPEED_10M; |
| 22206 | bool up = false, full_duplex = false; |
| 22207 | struct mg_phy phy = {raeth_read_phy, raeth_write_phy}; |
| 22208 | up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); |
| 22209 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 22210 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 22211 | // if(link is slow or half) set flags otherwise |
| 22212 | // reg = tmp |
| 22213 | uint32_t ecmr = ETHERC->ECMR | MG_BIT(2) | MG_BIT(1); // 100M Full-duplex |
| 22214 | if (speed == MG_PHY_SPEED_10M) ecmr &= ~MG_BIT(2); // 10M |
| 22215 | if (full_duplex == false) ecmr &= ~MG_BIT(1); // Half-duplex |
| 22216 | ETHERC->ECMR = ecmr; // IRQ handler does not fiddle with these registers |
| 22217 | MG_DEBUG(("Link is %uM %s-duplex", ecmr & MG_BIT(2) ? 100 : 10, |
| 22218 | ecmr & MG_BIT(1) ? "full" : "half")); |
| 22219 | } |
| 22220 | return up; |
| 22221 | } |
| 22222 | |
| 22223 | void EDMAC_IRQHandler(void); |
| 22224 | static uint32_t s_rxno; |
| 22225 | void EDMAC_IRQHandler(void) { |
| 22226 | struct mg_tcpip_driver_ra_data *d = |
| 22227 | (struct mg_tcpip_driver_ra_data *) s_ifp->driver_data; |
| 22228 | EDMAC->EESR = MG_BIT(18) | MG_BIT(7); // Ack IRQ in EDMAC 1st |
| 22229 | ICU_IELSR[d->irqno] &= ~MG_BIT(16); // Ack IRQ in ICU last |
| 22230 | // Frame received, loop |
| 22231 | for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever |
| 22232 | uint32_t r = s_rxdesc[s_rxno][0]; |
| 22233 | if (r & MG_BIT(31)) break; // exit when done |
| 22234 | // skip partial/errored frames (27.3.1.2) |
| 22235 | if ((r & (MG_BIT(29) | MG_BIT(28)) && !(r & MG_BIT(27)))) { |
| 22236 | size_t len = s_rxdesc[s_rxno][1] & 0xffff; |
| 22237 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); // CRC already stripped |
| 22238 | } |
| 22239 | s_rxdesc[s_rxno][0] |= MG_BIT(31); |
| 22240 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 22241 | } |
| 22242 | EDMAC->EDRRR = MG_BIT(0); // Receive Descriptors have changed |
| 22243 | // If b0 == 0, descriptors were exhausted and probably frames were dropped, |
| 22244 | // (27.2.9 RMFCR counts them) |
| 22245 | } |
| 22246 | |
| 22247 | struct mg_tcpip_driver mg_tcpip_driver_ra = {mg_tcpip_driver_ra_init, |
| 22248 | mg_tcpip_driver_ra_tx, NULL, |
| 22249 | mg_tcpip_driver_ra_poll}; |
| 22250 | |
| 22251 | #endif |
| 22252 | |
| 22253 | #ifdef MG_ENABLE_LINES |
| 22254 | #line 1 "src/drivers/rw612.c" |
| 22255 | #endif |
| 22256 | |
| 22257 | |
| 22258 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612) && MG_ENABLE_DRIVER_RW612 |
| 22259 | |
| 22260 | struct ENET_Type { |
| 22261 | volatile uint32_t RESERVED_0[1], EIR, EIMR, RESERVED_1[1], RDAR, TDAR, |
| 22262 | RESERVED_2[3], ECR, RESERVED_3[6], MMFR, MSCR, RESERVED_4[7], MIBC, |
| 22263 | RESERVED_5[7], RCR, RESERVED_6[15], TCR, RESERVED_7[7], PALR, PAUR, OPD, |
| 22264 | TXIC[1], RESERVED_8[3], RXIC[1], RESERVED_9[5], IAUR, IALR, GAUR, GALR, |
| 22265 | RESERVED_10[7], TFWR, RESERVED_11[14], RDSR, TDSR, MRBR, RESERVED_12[1], |
| 22266 | RSFL, RSEM, RAEM, RAFL, TSEM, TAEM, TAFL, TIPG, FTRL, RESERVED_13[3], |
| 22267 | TACC, RACC, RESERVED_14[15], RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, |
| 22268 | RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, |
| 22269 | RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, |
| 22270 | RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047, RMON_T_P_GTE2048, |
| 22271 | RMON_T_OCTETS, IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, |
| 22272 | IEEE_T_DEF, IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, |
| 22273 | IEEE_T_SQE, IEEE_T_FDXFC, IEEE_T_OCTETS_OK, RESERVED_15[3], |
| 22274 | RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, |
| 22275 | RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, |
| 22276 | RESERVED_16[1], RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255, |
| 22277 | RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047, RMON_R_P_GTE2048, |
| 22278 | RMON_R_OCTETS, IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, |
| 22279 | IEEE_R_MACERR, IEEE_R_FDXFC, IEEE_R_OCTETS_OK, RESERVED_17[71], ATCR, |
| 22280 | ATVR, ATOFF, ATPER, ATCOR, ATINC, ATSTMP, RESERVED_18[122], TGSR, |
| 22281 | CHANNEL_TCSR[4], CHANNEL_TCCR[4]; |
| 22282 | }; |
| 22283 | |
| 22284 | #define ENET ((struct ENET_Type *) 0x40138000) |
| 22285 | |
| 22286 | #define ETH_PKT_SIZE 1536 // Max frame size |
| 22287 | #define ETH_DESC_CNT 4 // Descriptors count |
| 22288 | #define ETH_DS 2 // Descriptor size (words) |
| 22289 | |
| 22290 | #define MG_8BYTE_ALIGNED __attribute__((aligned((8U)))) |
| 22291 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; |
| 22292 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; |
| 22293 | static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; |
| 22294 | static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; |
| 22295 | static uint8_t s_txno; // Current TX descriptor |
| 22296 | static uint8_t s_rxno; // Current RX descriptor |
| 22297 | |
| 22298 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 22299 | |
| 22300 | static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { |
| 22301 | ENET->MMFR = MG_BIT(30) | // Start of frame delimiter |
| 22302 | MG_BIT(29) | // Opcode |
| 22303 | ((addr & 0x1f) << 23) | ((reg & 0x1f) << 18) | MG_BIT(17); |
| 22304 | while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; |
| 22305 | ENET->EIR |= MG_BIT(23); |
| 22306 | return ENET->MMFR & 0xffff; |
| 22307 | } |
| 22308 | |
| 22309 | static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 22310 | ENET->MMFR = MG_BIT(30) | // Start of frame delimiter |
| 22311 | MG_BIT(28) | // Opcode |
| 22312 | ((addr & 0x1f) << 23) | ((reg & 0x1f) << 18) | MG_BIT(17) | val; |
| 22313 | while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; |
| 22314 | ENET->EIR |= MG_BIT(23); |
| 22315 | } |
| 22316 | |
| 22317 | static bool mg_tcpip_driver_rw612_init(struct mg_tcpip_if *ifp) { |
| 22318 | struct mg_tcpip_driver_rw612_data *d = |
| 22319 | (struct mg_tcpip_driver_rw612_data *) ifp->driver_data; |
| 22320 | s_ifp = ifp; |
| 22321 | ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); |
| 22322 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 22323 | mg_phy_init(&phy, d->phy_addr, 0); |
| 22324 | ENET->ECR |= MG_BIT(0); // reset ETH |
| 22325 | |
| 22326 | // initialize descriptors |
| 22327 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 22328 | s_rxdesc[i][1] = (uint32_t) s_rxbuf[i]; |
| 22329 | s_rxdesc[i][0] = MG_BIT(31); // OWN |
| 22330 | if (i == ETH_DESC_CNT - 1) { |
| 22331 | s_rxdesc[i][0] |= MG_BIT(29); // mark last descriptor |
| 22332 | } |
| 22333 | s_txdesc[i][1] = (uint32_t) s_txbuf[i]; |
| 22334 | if (i == ETH_DESC_CNT - 1) { |
| 22335 | s_txdesc[i][0] |= MG_BIT(29); // mark last descriptor |
| 22336 | } |
| 22337 | } |
| 22338 | |
| 22339 | ENET->RCR = (ENET->RCR & (0xffff << 16)) | MG_BIT(14) | MG_BIT(8) | MG_BIT(2); |
| 22340 | ENET->TCR = MG_BIT(2); // full duplex |
| 22341 | ENET->TDSR = (uint32_t) &s_txdesc[0][0]; |
| 22342 | ENET->RDSR = (uint32_t) &s_rxdesc[0][0]; |
| 22343 | ENET->MRBR = ETH_PKT_SIZE; |
| 22344 | ENET->PALR = |
| 22345 | ifp->mac[0] << 24 | ifp->mac[1] << 16 | ifp->mac[2] << 8 | ifp->mac[3]; |
| 22346 | ENET->PAUR |= (ifp->mac[4] << 24 | ifp->mac[5] << 16); |
| 22347 | ENET->IALR = 0; |
| 22348 | ENET->IAUR = 0; |
| 22349 | ENET->GALR = 0; |
| 22350 | ENET->GAUR = 0; |
| 22351 | ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); |
| 22352 | ENET->EIMR = MG_BIT(25); // Enable RX interrupt |
| 22353 | ENET->ECR |= MG_BIT(8) | MG_BIT(1); // DBSWP, Enable |
| 22354 | ENET->RDAR = 0; // activate RX descriptors ring |
| 22355 | return true; |
| 22356 | } |
| 22357 | |
| 22358 | static size_t mg_tcpip_driver_rw612_tx(const void *buf, size_t len, |
| 22359 | struct mg_tcpip_if *ifp) { |
| 22360 | if (len > sizeof(s_txbuf[s_txno])) { |
| 22361 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 22362 | len = 0; // Frame is too big |
| 22363 | } else if (((s_txdesc[s_txno][0] & MG_BIT(31)) != 0)) { |
| 22364 | ifp->nerr++; |
| 22365 | MG_ERROR(("No free descriptors")); |
| 22366 | len = 0; // All descriptors are busy, fail |
| 22367 | } else { |
| 22368 | memcpy(s_txbuf[s_txno], buf, len); |
| 22369 | s_txdesc[s_txno][0] = len | MG_BIT(27) | MG_BIT(26); // last buffer, crc |
| 22370 | if (s_txno == ETH_DESC_CNT - 1) { |
| 22371 | s_txdesc[s_txno][0] |= MG_BIT(29); // wrap |
| 22372 | } |
| 22373 | s_txdesc[s_txno][0] |= MG_BIT(31); // release ownership |
| 22374 | MG_DSB(); |
| 22375 | ENET->TDAR = 0; |
| 22376 | // MG_INFO(("s_txdesc[%d][0]: 0x%x", s_txno, s_txdesc[s_txno][0])); |
| 22377 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 22378 | } |
| 22379 | |
| 22380 | return len; |
| 22381 | } |
| 22382 | |
| 22383 | |
| 22384 | static void mg_tcpip_driver_rw612_update_hash_table(struct mg_tcpip_if *ifp) { |
| 22385 | // TODO(): read database, rebuild hash table |
| 22386 | ENET->GAUR = MG_BIT(1); // see imxrt, it reduces to this for mDNS |
| 22387 | (void) ifp; |
| 22388 | } |
| 22389 | |
| 22390 | static bool mg_tcpip_driver_rw612_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 22391 | if (ifp->update_mac_hash_table) { |
| 22392 | mg_tcpip_driver_rw612_update_hash_table(ifp); |
| 22393 | ifp->update_mac_hash_table = false; |
| 22394 | } |
| 22395 | if (!s1) return false; |
| 22396 | struct mg_tcpip_driver_rw612_data *d = |
| 22397 | (struct mg_tcpip_driver_rw612_data *) ifp->driver_data; |
| 22398 | uint8_t speed = MG_PHY_SPEED_10M; |
| 22399 | bool up = false, full_duplex = false; |
| 22400 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 22401 | up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); |
| 22402 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 22403 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 22404 | // if(link is slow or half) set flags otherwise |
| 22405 | // reg = tmp |
| 22406 | if (speed == MG_PHY_SPEED_100M && (ENET->RCR & MG_BIT(9))) { |
| 22407 | ENET->RCR &= ~MG_BIT(9); |
| 22408 | } else if (speed == MG_PHY_SPEED_10M && (ENET->RCR & MG_BIT(9)) == 0) { |
| 22409 | ENET->RCR |= MG_BIT(9); |
| 22410 | } |
| 22411 | if (full_duplex && (ENET->TCR & MG_BIT(2)) == 0) { |
| 22412 | ENET->ECR &= ~MG_BIT(1); |
| 22413 | ENET->TCR |= MG_BIT(2); |
| 22414 | ENET->ECR |= MG_BIT(1); |
| 22415 | } else if (!full_duplex && (ENET->TCR & MG_BIT(2))) { |
| 22416 | ENET->ECR &= ~MG_BIT(1); |
| 22417 | ENET->TCR &= ~MG_BIT(2); |
| 22418 | ENET->ECR |= MG_BIT(1); |
| 22419 | } |
| 22420 | MG_INFO(("Link is %uM %s-duplex", |
| 22421 | speed == MG_PHY_SPEED_10M |
| 22422 | ? 10 |
| 22423 | : (speed == MG_PHY_SPEED_100M ? 100 : 1000), |
| 22424 | full_duplex ? "full" : "half")); |
| 22425 | } |
| 22426 | return up; |
| 22427 | } |
| 22428 | |
| 22429 | void ENET_IRQHandler(void) { |
| 22430 | if (ENET->EIR & MG_BIT(25)) { |
| 22431 | ENET->EIR = MG_BIT(25); // Ack RX |
| 22432 | for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever |
| 22433 | if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) != 0) break; // exit when done |
| 22434 | // skip partial/errored frames |
| 22435 | if ((s_rxdesc[s_rxno][0] & MG_BIT(27)) && |
| 22436 | !(s_rxdesc[s_rxno][0] & |
| 22437 | (MG_BIT(21) | MG_BIT(20) | MG_BIT(18) | MG_BIT(17) | MG_BIT(16)))) { |
| 22438 | size_t len = s_rxdesc[s_rxno][0] & 0xffff; |
| 22439 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); |
| 22440 | s_rxdesc[s_rxno][0] |= MG_BIT(31); // OWN bit: handle control to DMA |
| 22441 | MG_DSB(); |
| 22442 | ENET->RDAR = 0; |
| 22443 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 22444 | } |
| 22445 | } |
| 22446 | } |
| 22447 | } |
| 22448 | |
| 22449 | struct mg_tcpip_driver mg_tcpip_driver_rw612 = {mg_tcpip_driver_rw612_init, |
| 22450 | mg_tcpip_driver_rw612_tx, NULL, |
| 22451 | mg_tcpip_driver_rw612_poll}; |
| 22452 | #endif |
| 22453 | |
| 22454 | #ifdef MG_ENABLE_LINES |
| 22455 | #line 1 "src/drivers/same54.c" |
| 22456 | #endif |
| 22457 | |
| 22458 | |
| 22459 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \ |
| 22460 | MG_ENABLE_DRIVER_SAME54 |
| 22461 | |
| 22462 | #include <sam.h> |
| 22463 | |
| 22464 | #define ETH_PKT_SIZE 1536 // Max frame size |
| 22465 | #define ETH_DESC_CNT 4 // Descriptors count |
| 22466 | #define ETH_DS 2 // Descriptor size (words) |
| 22467 | |
| 22468 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; |
| 22469 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; |
| 22470 | static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors |
| 22471 | static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors |
| 22472 | static uint8_t s_txno; // Current TX descriptor |
| 22473 | static uint8_t s_rxno; // Current RX descriptor |
| 22474 | |
| 22475 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 22476 | enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; |
| 22477 | |
| 22478 | #define MG_PHYREGBIT_BCR_DUPLEX_MODE MG_BIT(8) |
| 22479 | #define MG_PHYREGBIT_BCR_SPEED MG_BIT(13) |
| 22480 | #define MG_PHYREGBIT_BSR_LINK_STATUS MG_BIT(2) |
| 22481 | |
| 22482 | static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { |
| 22483 | GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | |
| 22484 | GMAC_MAN_OP(2) | // Setting the read operation |
| 22485 | GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address |
| 22486 | GMAC_MAN_REGA(reg); // Setting the register |
| 22487 | while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)) (void) 0; |
| 22488 | return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value |
| 22489 | } |
| 22490 | |
| 22491 | #if 0 |
| 22492 | static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 22493 | GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation |
| 22494 | GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address |
| 22495 | GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register |
| 22496 | while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete |
| 22497 | } |
| 22498 | #endif |
| 22499 | |
| 22500 | int get_clock_rate(struct mg_tcpip_driver_same54_data *d) { |
| 22501 | if (d && d->mdc_cr >= 0 && d->mdc_cr <= 5) { |
| 22502 | return d->mdc_cr; |
| 22503 | } else { |
| 22504 | // get MCLK from GCLK_GENERATOR 0 |
| 22505 | uint32_t div = 512; |
| 22506 | uint32_t mclk; |
| 22507 | if (!(GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_DIVSEL_Msk)) { |
| 22508 | div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16); |
| 22509 | if (div == 0) div = 1; |
| 22510 | } |
| 22511 | switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) { |
| 22512 | case GCLK_GENCTRL_SRC_XOSC0_Val: |
| 22513 | mclk = 32000000UL; /* 32MHz */ |
| 22514 | break; |
| 22515 | case GCLK_GENCTRL_SRC_XOSC1_Val: |
| 22516 | mclk = 32000000UL; /* 32MHz */ |
| 22517 | break; |
| 22518 | case GCLK_GENCTRL_SRC_OSCULP32K_Val: |
| 22519 | mclk = 32000UL; |
| 22520 | break; |
| 22521 | case GCLK_GENCTRL_SRC_XOSC32K_Val: |
| 22522 | mclk = 32000UL; |
| 22523 | break; |
| 22524 | case GCLK_GENCTRL_SRC_DFLL_Val: |
| 22525 | mclk = 48000000UL; /* 48MHz */ |
| 22526 | break; |
| 22527 | case GCLK_GENCTRL_SRC_DPLL0_Val: |
| 22528 | mclk = 200000000UL; /* 200MHz */ |
| 22529 | break; |
| 22530 | case GCLK_GENCTRL_SRC_DPLL1_Val: |
| 22531 | mclk = 200000000UL; /* 200MHz */ |
| 22532 | break; |
| 22533 | default: |
| 22534 | mclk = 200000000UL; /* 200MHz */ |
| 22535 | } |
| 22536 | |
| 22537 | mclk /= div; |
| 22538 | uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values |
| 22539 | uint8_t dividers[] = {8, 16, 32, 48, 64, 96}; // Respective CLK dividers |
| 22540 | for (int i = 0; i < 6; i++) { |
| 22541 | if (mclk / dividers[i] <= 2375000UL /* 2.5MHz - 5% */) { |
| 22542 | return crs[i]; |
| 22543 | } |
| 22544 | } |
| 22545 | |
| 22546 | return 5; |
| 22547 | } |
| 22548 | } |
| 22549 | |
| 22550 | static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) { |
| 22551 | struct mg_tcpip_driver_same54_data *d = |
| 22552 | (struct mg_tcpip_driver_same54_data *) ifp->driver_data; |
| 22553 | s_ifp = ifp; |
| 22554 | |
| 22555 | MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC_Msk; |
| 22556 | MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC_Msk; |
| 22557 | GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(get_clock_rate(d)); // Set MDC divider |
| 22558 | GMAC_REGS->GMAC_NCR = 0; // Disable RX & TX |
| 22559 | GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; // Enable MDC & MDIO |
| 22560 | |
| 22561 | for (int i = 0; i < ETH_DESC_CNT; i++) { // Init TX descriptors |
| 22562 | s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer |
| 22563 | s_txdesc[i][1] = MG_BIT(31); // OWN bit |
| 22564 | } |
| 22565 | s_txdesc[ETH_DESC_CNT - 1][1] |= MG_BIT(30); // Last tx descriptor - wrap |
| 22566 | |
| 22567 | GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18) // DMA recv buf 1536 |
| 22568 | | GMAC_DCFGR_RXBMS(GMAC_DCFGR_RXBMS_FULL_Val) | |
| 22569 | GMAC_DCFGR_TXPBMS(1); // See #2487 |
| 22570 | for (int i = 0; i < ETH_DESC_CNT; i++) { // Init RX descriptors |
| 22571 | s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; // Address of the data buffer |
| 22572 | s_rxdesc[i][1] = 0; // Clear status |
| 22573 | } |
| 22574 | s_rxdesc[ETH_DESC_CNT - 1][0] |= MG_BIT(1); // Last rx descriptor - wrap |
| 22575 | |
| 22576 | GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc; // about the descriptor addresses |
| 22577 | GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc; // Let the controller know |
| 22578 | |
| 22579 | GMAC_REGS->SA[0].GMAC_SAB = |
| 22580 | MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]); |
| 22581 | GMAC_REGS->SA[0].GMAC_SAT = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]); |
| 22582 | |
| 22583 | GMAC_REGS->GMAC_UR &= ~GMAC_UR_MII_Msk; // Disable MII, use RMII |
| 22584 | GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_MAXFS_Msk | GMAC_NCFGR_MTIHEN_Msk | |
| 22585 | GMAC_NCFGR_EFRHD_Msk | GMAC_NCFGR_CAF_Msk; |
| 22586 | GMAC_REGS->GMAC_TSR = GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | |
| 22587 | GMAC_TSR_TXCOMP_Msk | GMAC_TSR_TFC_Msk | |
| 22588 | GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk | |
| 22589 | GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk; |
| 22590 | GMAC_REGS->GMAC_RSR = GMAC_RSR_HNO_Msk | GMAC_RSR_RXOVR_Msk | |
| 22591 | GMAC_RSR_REC_Msk | GMAC_RSR_BNA_Msk; |
| 22592 | GMAC_REGS->GMAC_IDR = ~0U; // Disable interrupts, then enable required |
| 22593 | GMAC_REGS->GMAC_IER = GMAC_IER_HRESP_Msk | GMAC_IER_ROVR_Msk | |
| 22594 | GMAC_IER_TCOMP_Msk | GMAC_IER_TFC_Msk | |
| 22595 | GMAC_IER_RLEX_Msk | GMAC_IER_TUR_Msk | |
| 22596 | GMAC_IER_RXUBR_Msk | GMAC_IER_RCOMP_Msk; |
| 22597 | GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk | GMAC_NCR_RXEN_Msk; |
| 22598 | NVIC_EnableIRQ(GMAC_IRQn); |
| 22599 | |
| 22600 | return true; |
| 22601 | } |
| 22602 | |
| 22603 | static size_t mg_tcpip_driver_same54_tx(const void *buf, size_t len, |
| 22604 | struct mg_tcpip_if *ifp) { |
| 22605 | if (len > sizeof(s_txbuf[s_txno])) { |
| 22606 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 22607 | len = 0; // Frame is too big |
| 22608 | } else if ((s_txdesc[s_txno][1] & MG_BIT(31)) == 0) { |
| 22609 | ifp->nerr++; |
| 22610 | MG_ERROR(("No free descriptors")); |
| 22611 | len = 0; // All descriptors are busy, fail |
| 22612 | } else { |
| 22613 | uint32_t status = len | MG_BIT(15); // Frame length, last chunk |
| 22614 | if (s_txno == ETH_DESC_CNT - 1) status |= MG_BIT(30); // wrap |
| 22615 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 22616 | s_txdesc[s_txno][1] = status; |
| 22617 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 22618 | } |
| 22619 | __DSB(); // Ensure descriptors have been written |
| 22620 | GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission |
| 22621 | return len; |
| 22622 | } |
| 22623 | |
| 22624 | static void mg_tcpip_driver_same54_update_hash_table(struct mg_tcpip_if *ifp) { |
| 22625 | // TODO(): read database, rebuild hash table |
| 22626 | // Setting Hash Index for 01:00:5e:00:00:fb (multicast) |
| 22627 | // 24.6.9 Hash addressing |
| 22628 | // computed hash is 55, which means bit 23 (55 - 32) in |
| 22629 | // HRT register must be set |
| 22630 | GMAC_REGS->GMAC_HRT = MG_BIT(23); |
| 22631 | GMAC_REGS->GMAC_NCFGR |= MG_BIT(6); // enable multicast hash filtering |
| 22632 | (void) ifp; |
| 22633 | } |
| 22634 | |
| 22635 | static bool mg_tcpip_driver_same54_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 22636 | if (ifp->update_mac_hash_table) { |
| 22637 | mg_tcpip_driver_same54_update_hash_table(ifp); |
| 22638 | ifp->update_mac_hash_table = false; |
| 22639 | } |
| 22640 | if (s1) { |
| 22641 | uint16_t bsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BSR); |
| 22642 | bool up = bsr & MG_PHYREGBIT_BSR_LINK_STATUS ? 1 : 0; |
| 22643 | |
| 22644 | // If PHY is ready, update NCFGR accordingly |
| 22645 | if (ifp->state == MG_TCPIP_STATE_DOWN && up) { |
| 22646 | uint16_t bcr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BCR); |
| 22647 | bool fd = bcr & MG_PHYREGBIT_BCR_DUPLEX_MODE ? 1 : 0; |
| 22648 | bool spd = bcr & MG_PHYREGBIT_BCR_SPEED ? 1 : 0; |
| 22649 | GMAC_REGS->GMAC_NCFGR = (GMAC_REGS->GMAC_NCFGR & |
| 22650 | ~(GMAC_NCFGR_SPD_Msk | MG_PHYREGBIT_BCR_SPEED)) | |
| 22651 | GMAC_NCFGR_SPD(spd) | GMAC_NCFGR_FD(fd); |
| 22652 | } |
| 22653 | } |
| 22654 | return false; |
| 22655 | } |
| 22656 | |
| 22657 | void GMAC_Handler(void); |
| 22658 | void GMAC_Handler(void) { |
| 22659 | uint32_t isr = GMAC_REGS->GMAC_ISR; |
| 22660 | uint32_t rsr = GMAC_REGS->GMAC_RSR; |
| 22661 | uint32_t tsr = GMAC_REGS->GMAC_TSR; |
| 22662 | if (isr & GMAC_ISR_RCOMP_Msk) { |
| 22663 | if (rsr & GMAC_ISR_RCOMP_Msk) { |
| 22664 | for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { |
| 22665 | if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break; |
| 22666 | size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1); |
| 22667 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); |
| 22668 | s_rxdesc[s_rxno][0] &= ~MG_BIT(0); // Disown |
| 22669 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 22670 | } |
| 22671 | } |
| 22672 | } |
| 22673 | |
| 22674 | if ((tsr & (GMAC_TSR_HRESP_Msk | GMAC_TSR_UND_Msk | GMAC_TSR_TXCOMP_Msk | |
| 22675 | GMAC_TSR_TFC_Msk | GMAC_TSR_TXGO_Msk | GMAC_TSR_RLE_Msk | |
| 22676 | GMAC_TSR_COL_Msk | GMAC_TSR_UBR_Msk)) != 0) { |
| 22677 | // MG_INFO((" --> %#x %#x", s_txdesc[s_txno][1], tsr)); |
| 22678 | if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31); |
| 22679 | } |
| 22680 | |
| 22681 | GMAC_REGS->GMAC_RSR = rsr; |
| 22682 | GMAC_REGS->GMAC_TSR = tsr; |
| 22683 | } |
| 22684 | |
| 22685 | struct mg_tcpip_driver mg_tcpip_driver_same54 = { |
| 22686 | mg_tcpip_driver_same54_init, mg_tcpip_driver_same54_tx, NULL, |
| 22687 | mg_tcpip_driver_same54_poll}; |
| 22688 | #endif |
| 22689 | |
| 22690 | #ifdef MG_ENABLE_LINES |
| 22691 | #line 1 "src/drivers/stm32f.c" |
| 22692 | #endif |
| 22693 | |
| 22694 | |
| 22695 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \ |
| 22696 | MG_ENABLE_DRIVER_STM32F |
| 22697 | struct stm32f_eth { |
| 22698 | volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR, |
| 22699 | MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR, |
| 22700 | MACIMR, MACA0HR, MACA0LR, MACA1HR, MACA1LR, MACA2HR, MACA2LR, MACA3HR, |
| 22701 | MACA3LR, RESERVED2[40], MMCCR, MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, |
| 22702 | RESERVED3[14], MMCTGFSCCR, MMCTGFMSCCR, RESERVED4[5], MMCTGFCR, |
| 22703 | RESERVED5[10], MMCRFCECR, MMCRFAECR, RESERVED6[10], MMCRGUFCR, |
| 22704 | RESERVED7[334], PTPTSCR, PTPSSIR, PTPTSHR, PTPTSLR, PTPTSHUR, PTPTSLUR, |
| 22705 | PTPTSAR, PTPTTHR, PTPTTLR, RESERVED8, PTPTSSR, PTPPPSCR, RESERVED9[564], |
| 22706 | DMABMR, DMATPDR, DMARPDR, DMARDLAR, DMATDLAR, DMASR, DMAOMR, DMAIER, |
| 22707 | DMAMFBOCR, DMARSWTR, RESERVED10[8], DMACHTDR, DMACHRDR, DMACHTBAR, |
| 22708 | DMACHRBAR; |
| 22709 | }; |
| 22710 | #undef ETH |
| 22711 | #define ETH ((struct stm32f_eth *) (uintptr_t) 0x40028000) |
| 22712 | |
| 22713 | #define ETH_PKT_SIZE 1540 // Max frame size |
| 22714 | #define ETH_DESC_CNT 4 // Descriptors count |
| 22715 | #define ETH_DS 4 // Descriptor size (words) |
| 22716 | |
| 22717 | static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors |
| 22718 | static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors |
| 22719 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers |
| 22720 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers |
| 22721 | static uint8_t s_txno; // Current TX descriptor |
| 22722 | static uint8_t s_rxno; // Current RX descriptor |
| 22723 | |
| 22724 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 22725 | |
| 22726 | static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { |
| 22727 | ETH->MACMIIAR &= (7 << 2); |
| 22728 | ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6); |
| 22729 | ETH->MACMIIAR |= MG_BIT(0); |
| 22730 | while (ETH->MACMIIAR & MG_BIT(0)) (void) 0; |
| 22731 | return ETH->MACMIIDR & 0xffff; |
| 22732 | } |
| 22733 | |
| 22734 | static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 22735 | ETH->MACMIIDR = val; |
| 22736 | ETH->MACMIIAR &= (7 << 2); |
| 22737 | ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1); |
| 22738 | ETH->MACMIIAR |= MG_BIT(0); |
| 22739 | while (ETH->MACMIIAR & MG_BIT(0)) (void) 0; |
| 22740 | } |
| 22741 | |
| 22742 | static uint32_t get_hclk(void) { |
| 22743 | struct rcc { |
| 22744 | volatile uint32_t CR, PLLCFGR, CFGR; |
| 22745 | } *rcc = (struct rcc *) 0x40023800; |
| 22746 | uint32_t clk = 0, hsi = 16000000 /* 16 MHz */, hse = 8000000 /* 8MHz */; |
| 22747 | |
| 22748 | if (rcc->CFGR & (1 << 2)) { |
| 22749 | clk = hse; |
| 22750 | } else if (rcc->CFGR & (1 << 3)) { |
| 22751 | uint32_t vco, m, n, p; |
| 22752 | m = (rcc->PLLCFGR & (0x3f << 0)) >> 0; |
| 22753 | n = (rcc->PLLCFGR & (0x1ff << 6)) >> 6; |
| 22754 | p = (((rcc->PLLCFGR & (3 << 16)) >> 16) + 1) * 2; |
| 22755 | clk = (rcc->PLLCFGR & (1 << 22)) ? hse : hsi; |
| 22756 | vco = (uint32_t) ((uint64_t) clk * n / m); |
| 22757 | clk = vco / p; |
| 22758 | } else { |
| 22759 | clk = hsi; |
| 22760 | } |
| 22761 | uint32_t hpre = (rcc->CFGR & (15 << 4)) >> 4; |
| 22762 | if (hpre < 8) return clk; |
| 22763 | |
| 22764 | uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) |
| 22765 | return ((uint32_t) clk) >> ahbptab[hpre - 8]; |
| 22766 | } |
| 22767 | |
| 22768 | // Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3, |
| 22769 | // it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived |
| 22770 | // from the HSI (internal RC), and it can go above specs, the datasheets |
| 22771 | // specify a range of frequencies and activate one of a series of dividers to |
| 22772 | // keep the MDC clock safely below 2.5MHz. We guess a divider setting based on |
| 22773 | // HCLK with a +5% drift. If the user uses a different clock from our |
| 22774 | // defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx |
| 22775 | // (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift) |
| 22776 | static int guess_mdc_cr(void) { |
| 22777 | uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMIIAR::CR values |
| 22778 | uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers |
| 22779 | uint32_t hclk = get_hclk(); // Guess system HCLK |
| 22780 | int result = -1; // Invalid CR value |
| 22781 | if (hclk < 25000000) { |
| 22782 | MG_ERROR(("HCLK too low")); |
| 22783 | } else { |
| 22784 | for (int i = 0; i < 6; i++) { |
| 22785 | if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { |
| 22786 | result = crs[i]; |
| 22787 | break; |
| 22788 | } |
| 22789 | } |
| 22790 | if (result < 0) MG_ERROR(("HCLK too high")); |
| 22791 | } |
| 22792 | MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); |
| 22793 | return result; |
| 22794 | } |
| 22795 | |
| 22796 | static bool mg_tcpip_driver_stm32f_init(struct mg_tcpip_if *ifp) { |
| 22797 | struct mg_tcpip_driver_stm32f_data *d = |
| 22798 | (struct mg_tcpip_driver_stm32f_data *) ifp->driver_data; |
| 22799 | uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; |
| 22800 | s_ifp = ifp; |
| 22801 | |
| 22802 | // Init RX descriptors |
| 22803 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 22804 | s_rxdesc[i][0] = MG_BIT(31); // Own |
| 22805 | s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained |
| 22806 | s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer |
| 22807 | s_rxdesc[i][3] = |
| 22808 | (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain |
| 22809 | } |
| 22810 | |
| 22811 | // Init TX descriptors |
| 22812 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 22813 | s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer |
| 22814 | s_txdesc[i][3] = |
| 22815 | (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain |
| 22816 | } |
| 22817 | |
| 22818 | ETH->DMABMR |= MG_BIT(0); // Software reset |
| 22819 | while ((ETH->DMABMR & MG_BIT(0)) != 0) (void) 0; // Wait until done |
| 22820 | |
| 22821 | // Set MDC clock divider. If user told us the value, use it. Otherwise, guess |
| 22822 | int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; |
| 22823 | ETH->MACMIIAR = ((uint32_t) cr & 7) << 2; |
| 22824 | |
| 22825 | // NOTE(cpq): we do not use extended descriptor bit 7, and do not use |
| 22826 | // hardware checksum. Therefore, descriptor size is 4, not 8 |
| 22827 | // ETH->DMABMR = MG_BIT(13) | MG_BIT(16) | MG_BIT(22) | MG_BIT(23) | |
| 22828 | // MG_BIT(25); |
| 22829 | ETH->MACIMR = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT |
| 22830 | ETH->MACFCR = MG_BIT(7); // Disable zero quarta pause |
| 22831 | ETH->MACFFR = MG_BIT(10); // Perfect filtering |
| 22832 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 22833 | mg_phy_init(&phy, phy_addr, MG_PHY_CLOCKS_MAC); |
| 22834 | ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors |
| 22835 | ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors |
| 22836 | ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE |
| 22837 | ETH->MACCR = |
| 22838 | MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast |
| 22839 | ETH->DMAOMR = |
| 22840 | MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF |
| 22841 | |
| 22842 | // MAC address filtering |
| 22843 | ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; |
| 22844 | ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) | |
| 22845 | ((uint32_t) ifp->mac[2] << 16) | |
| 22846 | ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; |
| 22847 | return true; |
| 22848 | } |
| 22849 | |
| 22850 | static size_t mg_tcpip_driver_stm32f_tx(const void *buf, size_t len, |
| 22851 | struct mg_tcpip_if *ifp) { |
| 22852 | if (len > sizeof(s_txbuf[s_txno])) { |
| 22853 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 22854 | len = 0; // Frame is too big |
| 22855 | } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { |
| 22856 | ifp->nerr++; |
| 22857 | MG_ERROR(("No free descriptors")); |
| 22858 | // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR); |
| 22859 | len = 0; // All descriptors are busy, fail |
| 22860 | } else { |
| 22861 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 22862 | s_txdesc[s_txno][1] = (uint32_t) len; // Set data len |
| 22863 | s_txdesc[s_txno][0] = MG_BIT(20) | MG_BIT(28) | MG_BIT(29); // Chain,FS,LS |
| 22864 | s_txdesc[s_txno][0] |= MG_BIT(31); // Set OWN bit - let DMA take over |
| 22865 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 22866 | } |
| 22867 | MG_DSB(); // ensure descriptors have been written |
| 22868 | ETH->DMASR = MG_BIT(2) | MG_BIT(5); // Clear any prior TBUS/TUS |
| 22869 | ETH->DMATPDR = 0; // and resume |
| 22870 | return len; |
| 22871 | } |
| 22872 | |
| 22873 | static void mg_tcpip_driver_stm32f_update_hash_table(struct mg_tcpip_if *ifp) { |
| 22874 | // TODO(): read database, rebuild hash table |
| 22875 | ETH->MACA1LR = (uint32_t) mcast_addr[3] << 24 | |
| 22876 | (uint32_t) mcast_addr[2] << 16 | |
| 22877 | (uint32_t) mcast_addr[1] << 8 | (uint32_t) mcast_addr[0]; |
| 22878 | ETH->MACA1HR = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4]; |
| 22879 | ETH->MACA1HR |= MG_BIT(31); // AE |
| 22880 | (void) ifp; |
| 22881 | } |
| 22882 | |
| 22883 | static bool mg_tcpip_driver_stm32f_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 22884 | if (ifp->update_mac_hash_table) { |
| 22885 | mg_tcpip_driver_stm32f_update_hash_table(ifp); |
| 22886 | ifp->update_mac_hash_table = false; |
| 22887 | } |
| 22888 | if (!s1) return false; |
| 22889 | struct mg_tcpip_driver_stm32f_data *d = |
| 22890 | (struct mg_tcpip_driver_stm32f_data *) ifp->driver_data; |
| 22891 | uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; |
| 22892 | uint8_t speed = MG_PHY_SPEED_10M; |
| 22893 | bool up = false, full_duplex = false; |
| 22894 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 22895 | up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed); |
| 22896 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 22897 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 22898 | // if(link is slow or half) set flags otherwise |
| 22899 | // reg = tmp |
| 22900 | uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex |
| 22901 | if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M |
| 22902 | if (full_duplex == false) maccr &= ~MG_BIT(11); // Half-duplex |
| 22903 | ETH->MACCR = maccr; // IRQ handler does not fiddle with this register |
| 22904 | MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, |
| 22905 | maccr & MG_BIT(11) ? "full" : "half")); |
| 22906 | } |
| 22907 | return up; |
| 22908 | } |
| 22909 | |
| 22910 | #ifdef __riscv |
| 22911 | __attribute__((interrupt())) // For RISCV CH32V307, which share the same MAC |
| 22912 | #endif |
| 22913 | void ETH_IRQHandler(void); |
| 22914 | void ETH_IRQHandler(void) { |
| 22915 | if (ETH->DMASR & MG_BIT(6)) { // Frame received, loop |
| 22916 | ETH->DMASR = MG_BIT(16) | MG_BIT(6); // Clear flag |
| 22917 | for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever |
| 22918 | if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done |
| 22919 | if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == |
| 22920 | (MG_BIT(8) | MG_BIT(9))) && |
| 22921 | !(s_rxdesc[s_rxno][0] & MG_BIT(15))) { // skip partial/errored frames |
| 22922 | uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (MG_BIT(14) - 1)); |
| 22923 | // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0], |
| 22924 | // ETH->DMASR); |
| 22925 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); |
| 22926 | } |
| 22927 | s_rxdesc[s_rxno][0] = MG_BIT(31); |
| 22928 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 22929 | } |
| 22930 | } |
| 22931 | // Cleanup flags |
| 22932 | ETH->DMASR = MG_BIT(16) // NIS, normal interrupt summary |
| 22933 | | MG_BIT(7); // Clear possible RBUS while processing |
| 22934 | ETH->DMARPDR = 0; // and resume RX |
| 22935 | } |
| 22936 | |
| 22937 | struct mg_tcpip_driver mg_tcpip_driver_stm32f = { |
| 22938 | mg_tcpip_driver_stm32f_init, mg_tcpip_driver_stm32f_tx, NULL, |
| 22939 | mg_tcpip_driver_stm32f_poll}; |
| 22940 | #endif |
| 22941 | |
| 22942 | #ifdef MG_ENABLE_LINES |
| 22943 | #line 1 "src/drivers/stm32h.c" |
| 22944 | #endif |
| 22945 | |
| 22946 | |
| 22947 | #if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN) |
| 22948 | // STM32H: vendor modded single-queue Synopsys v4.2 |
| 22949 | // MCXNx4x: dual-queue Synopsys v5.2 with no hash table option |
| 22950 | // RT1170 ENET_QOS: quad-queue Synopsys v5.1 |
| 22951 | struct synopsys_enet_qos { |
| 22952 | volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, |
| 22953 | RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, |
| 22954 | RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR, |
| 22955 | MACIER, MACRXTXSR, RESERVED7, MACPCSR, MACRWKPFR, RESERVED8[2], MACLCSR, |
| 22956 | MACLTCR, MACLETR, MAC1USTCR, RESERVED9[12], MACVR, MACDR, RESERVED10, |
| 22957 | MACHWF0R, MACHWF1R, MACHWF2R, RESERVED11[54], MACMDIOAR, MACMDIODR, |
| 22958 | RESERVED12[2], MACARPAR, RESERVED13[59], MACA0HR, MACA0LR, MACA1HR, |
| 22959 | MACA1LR, MACA2HR, MACA2LR, MACA3HR, MACA3LR, RESERVED14[248], MMCCR, |
| 22960 | MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, RESERVED15[14], MMCTSCGPR, MMCTMCGPR, |
| 22961 | RESERVED16[5], MMCTPCGR, RESERVED17[10], MMCRCRCEPR, MMCRAEPR, |
| 22962 | RESERVED18[10], MMCRUPGR, RESERVED19[9], MMCTLPIMSTR, MMCTLPITCR, |
| 22963 | MMCRLPIMSTR, MMCRLPITCR, RESERVED20[65], MACL3L4C0R, MACL4A0R, |
| 22964 | RESERVED21[2], MACL3A0R0R, MACL3A1R0R, MACL3A2R0R, MACL3A3R0R, |
| 22965 | RESERVED22[4], MACL3L4C1R, MACL4A1R, RESERVED23[2], MACL3A0R1R, |
| 22966 | MACL3A1R1R, MACL3A2R1R, MACL3A3R1R, RESERVED24[108], MACTSCR, MACSSIR, |
| 22967 | MACSTSR, MACSTNR, MACSTSUR, MACSTNUR, MACTSAR, RESERVED25, MACTSSR, |
| 22968 | RESERVED26[3], MACTTSSNR, MACTTSSSR, RESERVED27[2], MACACR, RESERVED28, |
| 22969 | MACATSNR, MACATSSR, MACTSIACR, MACTSEACR, MACTSICNR, MACTSECNR, |
| 22970 | RESERVED29[4], MACPPSCR, RESERVED30[3], MACPPSTTSR, MACPPSTTNR, MACPPSIR, |
| 22971 | MACPPSWR, RESERVED31[12], MACPOCR, MACSPI0R, MACSPI1R, MACSPI2R, MACLMIR, |
| 22972 | RESERVED32[11], MTLOMR, RESERVED33[7], MTLISR, RESERVED34[55], MTLTQOMR, |
| 22973 | MTLTQUR, MTLTQDR, RESERVED35[8], MTLQICSR, MTLRQOMR, MTLRQMPOCR, MTLRQDR, |
| 22974 | RESERVED36[177], DMAMR, DMASBMR, DMAISR, DMADSR, RESERVED37[60], DMACCR, |
| 22975 | DMACTCR, DMACRCR, RESERVED38[2], DMACTDLAR, RESERVED39, DMACRDLAR, |
| 22976 | DMACTDTPR, RESERVED40, DMACRDTPR, DMACTDRLR, DMACRDRLR, DMACIER, |
| 22977 | DMACRIWTR, DMACSFCSR, RESERVED41, DMACCATDR, RESERVED42, DMACCARDR, |
| 22978 | RESERVED43, DMACCATBR, RESERVED44, DMACCARBR, DMACSR, RESERVED45[2], |
| 22979 | DMACMFCR; |
| 22980 | }; |
| 22981 | #undef ETH |
| 22982 | #if MG_ENABLE_DRIVER_STM32H |
| 22983 | #define ETH \ |
| 22984 | ((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \ |
| 22985 | 0x8000UL)) |
| 22986 | #elif MG_ENABLE_DRIVER_MCXN |
| 22987 | #define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) |
| 22988 | #endif |
| 22989 | |
| 22990 | #define ETH_PKT_SIZE 1540 // Max frame size |
| 22991 | #define ETH_DESC_CNT 4 // Descriptors count |
| 22992 | #define ETH_DS 4 // Descriptor size (words) |
| 22993 | |
| 22994 | static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors |
| 22995 | static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors |
| 22996 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers |
| 22997 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers |
| 22998 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 22999 | |
| 23000 | static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { |
| 23001 | ETH->MACMDIOAR &= (0xF << 8); |
| 23002 | ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2; |
| 23003 | ETH->MACMDIOAR |= MG_BIT(0); |
| 23004 | while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; |
| 23005 | return (uint16_t) ETH->MACMDIODR; |
| 23006 | } |
| 23007 | |
| 23008 | static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 23009 | ETH->MACMDIODR = val; |
| 23010 | ETH->MACMDIOAR &= (0xF << 8); |
| 23011 | ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2; |
| 23012 | ETH->MACMDIOAR |= MG_BIT(0); |
| 23013 | while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; |
| 23014 | } |
| 23015 | |
| 23016 | static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { |
| 23017 | struct mg_tcpip_driver_stm32h_data *d = |
| 23018 | (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data; |
| 23019 | s_ifp = ifp; |
| 23020 | uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; |
| 23021 | uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf; |
| 23022 | |
| 23023 | // Init RX descriptors |
| 23024 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 23025 | s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer |
| 23026 | s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V |
| 23027 | } |
| 23028 | |
| 23029 | // Init TX descriptors |
| 23030 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 23031 | s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer |
| 23032 | } |
| 23033 | |
| 23034 | ETH->DMAMR |= MG_BIT(0); // Software reset |
| 23035 | for (int i = 0; i < 4; i++) |
| 23036 | (void) 0; // wait at least 4 clocks before reading |
| 23037 | while ((ETH->DMAMR & MG_BIT(0)) != 0) (void) 0; // Wait until done |
| 23038 | |
| 23039 | // Set MDC clock divider. Get user value, else, assume max freq |
| 23040 | int cr = (d == NULL || d->mdc_cr < 0) ? 7 : d->mdc_cr; |
| 23041 | ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8; |
| 23042 | |
| 23043 | // NOTE(scaprile): We do not use timing facilities so the DMA engine does not |
| 23044 | // re-write buffer address |
| 23045 | ETH->DMAMR = 0 << 16; // use interrupt mode 0 (58.8.1) (reset value) |
| 23046 | ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed |
| 23047 | ETH->MACIER = 0; // Do not enable additional irq sources (reset value) |
| 23048 | ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause |
| 23049 | #if !MG_ENABLE_DRIVER_MCXN |
| 23050 | ETH->MACPFR = MG_BIT(10); // Perfect filtering |
| 23051 | #endif |
| 23052 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 23053 | mg_phy_init(&phy, phy_addr, phy_conf); |
| 23054 | ETH->DMACRDLAR = |
| 23055 | (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address |
| 23056 | ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length |
| 23057 | ETH->DMACRDTPR = |
| 23058 | (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - |
| 23059 | 1]; // last valid descriptor address |
| 23060 | ETH->DMACTDLAR = |
| 23061 | (uint32_t) (uintptr_t) s_txdesc; // TX descriptors start address |
| 23062 | ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length |
| 23063 | ETH->DMACTDTPR = |
| 23064 | (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address |
| 23065 | ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) |
| 23066 | #if !MG_ENABLE_DRIVER_STM32H |
| 23067 | MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16)); |
| 23068 | MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16)); |
| 23069 | #endif |
| 23070 | ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE |
| 23071 | ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | |
| 23072 | MG_BIT(15); // RE, TE, Duplex, Fast, Reserved |
| 23073 | #if MG_ENABLE_DRIVER_STM32H |
| 23074 | ETH->MTLTQOMR |= MG_BIT(1); // TSF |
| 23075 | ETH->MTLRQOMR |= MG_BIT(5); // RSF |
| 23076 | #else |
| 23077 | ETH->MTLTQOMR |= (7 << 16) | MG_BIT(3) | MG_BIT(1); // 2KB Q0, TSF |
| 23078 | ETH->MTLRQOMR |= (7 << 20) | MG_BIT(5); // 2KB Q, RSF |
| 23079 | MG_SET_BITS(ETH->RESERVED6[3], 3, 2); // Enable RxQ0 (MAC_RXQ_CTRL0) |
| 23080 | #endif |
| 23081 | ETH->DMACTCR |= MG_BIT(0); // ST |
| 23082 | ETH->DMACRCR |= MG_BIT(0); // SR |
| 23083 | |
| 23084 | // MAC address filtering |
| 23085 | ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; |
| 23086 | ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) | |
| 23087 | ((uint32_t) ifp->mac[2] << 16) | |
| 23088 | ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; |
| 23089 | return true; |
| 23090 | } |
| 23091 | |
| 23092 | static uint32_t s_txno; |
| 23093 | static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, |
| 23094 | struct mg_tcpip_if *ifp) { |
| 23095 | if (len > sizeof(s_txbuf[s_txno])) { |
| 23096 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 23097 | len = 0; // Frame is too big |
| 23098 | } else if ((s_txdesc[s_txno][3] & MG_BIT(31))) { |
| 23099 | ifp->nerr++; |
| 23100 | MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno, |
| 23101 | s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR)); |
| 23102 | for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3])); |
| 23103 | len = 0; // All descriptors are busy, fail |
| 23104 | } else { |
| 23105 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 23106 | s_txdesc[s_txno][2] = (uint32_t) len; // Set data len |
| 23107 | s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD |
| 23108 | s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over |
| 23109 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 23110 | } |
| 23111 | ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS |
| 23112 | ETH->DMACTDTPR = (uint32_t) (uintptr_t) &s_txdesc[s_txno]; // and resume |
| 23113 | return len; |
| 23114 | (void) ifp; |
| 23115 | } |
| 23116 | |
| 23117 | static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) { |
| 23118 | #if MG_ENABLE_DRIVER_MCXN |
| 23119 | ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames) |
| 23120 | #else |
| 23121 | // TODO(): read database, rebuild hash table |
| 23122 | // add mDNS / DNS-SD multicast address |
| 23123 | ETH->MACA1LR = (uint32_t) mcast_addr[3] << 24 | |
| 23124 | (uint32_t) mcast_addr[2] << 16 | |
| 23125 | (uint32_t) mcast_addr[1] << 8 | (uint32_t) mcast_addr[0]; |
| 23126 | ETH->MACA1HR = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4]; |
| 23127 | ETH->MACA1HR |= MG_BIT(31); // AE |
| 23128 | #endif |
| 23129 | (void) ifp; |
| 23130 | } |
| 23131 | |
| 23132 | static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 23133 | if (ifp->update_mac_hash_table) { |
| 23134 | mg_tcpip_driver_stm32h_update_hash_table(ifp); |
| 23135 | ifp->update_mac_hash_table = false; |
| 23136 | } |
| 23137 | if (!s1) return false; |
| 23138 | struct mg_tcpip_driver_stm32h_data *d = |
| 23139 | (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data; |
| 23140 | uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; |
| 23141 | uint8_t speed = MG_PHY_SPEED_10M; |
| 23142 | bool up = false, full_duplex = false; |
| 23143 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 23144 | up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed); |
| 23145 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 23146 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 23147 | // if(link is slow or half) set flags otherwise |
| 23148 | // reg = tmp |
| 23149 | uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex |
| 23150 | if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M |
| 23151 | if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex |
| 23152 | ETH->MACCR = maccr; // IRQ handler does not fiddle with this register |
| 23153 | MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, |
| 23154 | maccr & MG_BIT(13) ? "full" : "half")); |
| 23155 | } |
| 23156 | return up; |
| 23157 | } |
| 23158 | |
| 23159 | static uint32_t s_rxno; |
| 23160 | #if MG_ENABLE_DRIVER_MCXN |
| 23161 | void ETHERNET_IRQHandler(void); |
| 23162 | void ETHERNET_IRQHandler(void) { |
| 23163 | #else |
| 23164 | void ETH_IRQHandler(void); |
| 23165 | void ETH_IRQHandler(void) { |
| 23166 | #endif |
| 23167 | if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop |
| 23168 | ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag |
| 23169 | for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever |
| 23170 | if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done |
| 23171 | if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) == |
| 23172 | (MG_BIT(28) | MG_BIT(29))) && |
| 23173 | !(s_rxdesc[s_rxno][3] & MG_BIT(15))) { // skip partial/errored frames |
| 23174 | uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1); |
| 23175 | // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3], |
| 23176 | // ETH->DMACSR)); |
| 23177 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); |
| 23178 | } |
| 23179 | s_rxdesc[s_rxno][3] = |
| 23180 | MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V |
| 23181 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 23182 | } |
| 23183 | } |
| 23184 | ETH->DMACSR = |
| 23185 | MG_BIT(7) | MG_BIT(8); // Clear possible RBU RPS while processing |
| 23186 | ETH->DMACRDTPR = |
| 23187 | (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX |
| 23188 | } |
| 23189 | |
| 23190 | struct mg_tcpip_driver mg_tcpip_driver_stm32h = { |
| 23191 | mg_tcpip_driver_stm32h_init, mg_tcpip_driver_stm32h_tx, NULL, |
| 23192 | mg_tcpip_driver_stm32h_poll}; |
| 23193 | #endif |
| 23194 | |
| 23195 | #ifdef MG_ENABLE_LINES |
| 23196 | #line 1 "src/drivers/tm4c.c" |
| 23197 | #endif |
| 23198 | |
| 23199 | |
| 23200 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C |
| 23201 | struct tm4c_emac { |
| 23202 | volatile uint32_t EMACCFG, EMACFRAMEFLTR, EMACHASHTBLH, EMACHASHTBLL, |
| 23203 | EMACMIIADDR, EMACMIIDATA, EMACFLOWCTL, EMACVLANTG, RESERVED0, EMACSTATUS, |
| 23204 | EMACRWUFF, EMACPMTCTLSTAT, RESERVED1[2], EMACRIS, EMACIM, EMACADDR0H, |
| 23205 | EMACADDR0L, EMACADDR1H, EMACADDR1L, EMACADDR2H, EMACADDR2L, EMACADDR3H, |
| 23206 | EMACADDR3L, RESERVED2[31], EMACWDOGTO, RESERVED3[8], EMACMMCCTRL, |
| 23207 | EMACMMCRXRIS, EMACMMCTXRIS, EMACMMCRXIM, EMACMMCTXIM, RESERVED4, |
| 23208 | EMACTXCNTGB, RESERVED5[12], EMACTXCNTSCOL, EMACTXCNTMCOL, RESERVED6[4], |
| 23209 | EMACTXOCTCNTG, RESERVED7[6], EMACRXCNTGB, RESERVED8[4], EMACRXCNTCRCERR, |
| 23210 | EMACRXCNTALGNERR, RESERVED9[10], EMACRXCNTGUNI, RESERVED10[239], |
| 23211 | EMACVLNINCREP, EMACVLANHASH, RESERVED11[93], EMACTIMSTCTRL, EMACSUBSECINC, |
| 23212 | EMACTIMSEC, EMACTIMNANO, EMACTIMSECU, EMACTIMNANOU, EMACTIMADD, |
| 23213 | EMACTARGSEC, EMACTARGNANO, EMACHWORDSEC, EMACTIMSTAT, EMACPPSCTRL, |
| 23214 | RESERVED12[12], EMACPPS0INTVL, EMACPPS0WIDTH, RESERVED13[294], |
| 23215 | EMACDMABUSMOD, EMACTXPOLLD, EMACRXPOLLD, EMACRXDLADDR, EMACTXDLADDR, |
| 23216 | EMACDMARIS, EMACDMAOPMODE, EMACDMAIM, EMACMFBOC, EMACRXINTWDT, |
| 23217 | RESERVED14[8], EMACHOSTXDESC, EMACHOSRXDESC, EMACHOSTXBA, EMACHOSRXBA, |
| 23218 | RESERVED15[218], EMACPP, EMACPC, EMACCC, RESERVED16, EMACEPHYRIS, |
| 23219 | EMACEPHYIM, EMACEPHYIMSC; |
| 23220 | }; |
| 23221 | #undef EMAC |
| 23222 | #define EMAC ((struct tm4c_emac *) (uintptr_t) 0x400EC000) |
| 23223 | |
| 23224 | #define ETH_PKT_SIZE 1540 // Max frame size |
| 23225 | #define ETH_DESC_CNT 4 // Descriptors count |
| 23226 | #define ETH_DS 4 // Descriptor size (words) |
| 23227 | |
| 23228 | static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors |
| 23229 | static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors |
| 23230 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers |
| 23231 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers |
| 23232 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 23233 | enum { |
| 23234 | EPHY_ADDR = 0, |
| 23235 | EPHYBMCR = 0, |
| 23236 | EPHYBMSR = 1, |
| 23237 | EPHYSTS = 16 |
| 23238 | }; // PHY constants |
| 23239 | |
| 23240 | static inline void tm4cspin(volatile uint32_t count) { |
| 23241 | while (count--) (void) 0; |
| 23242 | } |
| 23243 | |
| 23244 | static uint32_t emac_read_phy(uint8_t addr, uint8_t reg) { |
| 23245 | EMAC->EMACMIIADDR &= (0xf << 2); |
| 23246 | EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6); |
| 23247 | EMAC->EMACMIIADDR |= MG_BIT(0); |
| 23248 | while (EMAC->EMACMIIADDR & MG_BIT(0)) tm4cspin(1); |
| 23249 | return EMAC->EMACMIIDATA; |
| 23250 | } |
| 23251 | |
| 23252 | static void emac_write_phy(uint8_t addr, uint8_t reg, uint32_t val) { |
| 23253 | EMAC->EMACMIIDATA = val; |
| 23254 | EMAC->EMACMIIADDR &= (0xf << 2); |
| 23255 | EMAC->EMACMIIADDR |= |
| 23256 | ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1); |
| 23257 | EMAC->EMACMIIADDR |= MG_BIT(0); |
| 23258 | while (EMAC->EMACMIIADDR & MG_BIT(0)) tm4cspin(1); |
| 23259 | } |
| 23260 | |
| 23261 | static uint32_t get_sysclk(void) { |
| 23262 | struct sysctl { |
| 23263 | volatile uint32_t DONTCARE0[44], RSCLKCFG, DONTCARE1[43], PLLFREQ0, |
| 23264 | PLLFREQ1; |
| 23265 | } *sysctl = (struct sysctl *) 0x400FE000; |
| 23266 | uint32_t clk = 0, piosc = 16000000 /* 16 MHz */, mosc = 25000000 /* 25MHz */; |
| 23267 | if (sysctl->RSCLKCFG & (1 << 28)) { // USEPLL |
| 23268 | uint32_t fin, vco, mdiv, n, q, psysdiv; |
| 23269 | uint32_t pllsrc = (sysctl->RSCLKCFG & (0xf << 24)) >> 24; |
| 23270 | if (pllsrc == 0) { |
| 23271 | clk = piosc; |
| 23272 | } else if (pllsrc == 3) { |
| 23273 | clk = mosc; |
| 23274 | } else { |
| 23275 | MG_ERROR(("Unsupported clock source")); |
| 23276 | } |
| 23277 | q = (sysctl->PLLFREQ1 & (0x1f << 8)) >> 8; |
| 23278 | n = (sysctl->PLLFREQ1 & (0x1f << 0)) >> 0; |
| 23279 | fin = clk / ((q + 1) * (n + 1)); |
| 23280 | mdiv = (sysctl->PLLFREQ0 & (0x3ff << 0)) >> |
| 23281 | 0; // mint + (mfrac / 1024); MFRAC not supported |
| 23282 | psysdiv = (sysctl->RSCLKCFG & (0x3f << 0)) >> 0; |
| 23283 | vco = (uint32_t) ((uint64_t) fin * mdiv); |
| 23284 | return vco / (psysdiv + 1); |
| 23285 | } |
| 23286 | uint32_t oscsrc = (sysctl->RSCLKCFG & (0xf << 20)) >> 20; |
| 23287 | if (oscsrc == 0) { |
| 23288 | clk = piosc; |
| 23289 | } else if (oscsrc == 3) { |
| 23290 | clk = mosc; |
| 23291 | } else { |
| 23292 | MG_ERROR(("Unsupported clock source")); |
| 23293 | } |
| 23294 | uint32_t osysdiv = (sysctl->RSCLKCFG & (0xf << 16)) >> 16; |
| 23295 | return clk / (osysdiv + 1); |
| 23296 | } |
| 23297 | |
| 23298 | // Guess CR from SYSCLK. MDC clock is generated from SYSCLK (AHB); as per |
| 23299 | // 802.3, it must not exceed 2.5MHz (also 20.4.2.6) As the AHB clock can be |
| 23300 | // derived from the PIOSC (internal RC), and it can go above specs, the |
| 23301 | // datasheets specify a range of frequencies and activate one of a series of |
| 23302 | // dividers to keep the MDC clock safely below 2.5MHz. We guess a divider |
| 23303 | // setting based on SYSCLK with a +5% drift. If the user uses a different clock |
| 23304 | // from our defaults, needs to set the macros on top Valid for TM4C129x (20.7) |
| 23305 | // (4.5% worst case drift) |
| 23306 | // The PHY receives the main oscillator (MOSC) (20.3.1) |
| 23307 | static int guess_mdc_cr(void) { |
| 23308 | uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values |
| 23309 | uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers |
| 23310 | uint32_t sysclk = get_sysclk(); // Guess system SYSCLK |
| 23311 | int result = -1; // Invalid CR value |
| 23312 | if (sysclk < 25000000) { |
| 23313 | MG_ERROR(("SYSCLK too low")); |
| 23314 | } else { |
| 23315 | for (int i = 0; i < 4; i++) { |
| 23316 | if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { |
| 23317 | result = crs[i]; |
| 23318 | break; |
| 23319 | } |
| 23320 | } |
| 23321 | if (result < 0) MG_ERROR(("SYSCLK too high")); |
| 23322 | } |
| 23323 | MG_DEBUG(("SYSCLK: %u, CR: %d", sysclk, result)); |
| 23324 | return result; |
| 23325 | } |
| 23326 | |
| 23327 | static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) { |
| 23328 | struct mg_tcpip_driver_tm4c_data *d = |
| 23329 | (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data; |
| 23330 | s_ifp = ifp; |
| 23331 | |
| 23332 | // Init RX descriptors |
| 23333 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 23334 | s_rxdesc[i][0] = MG_BIT(31); // Own |
| 23335 | s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained |
| 23336 | s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer |
| 23337 | s_rxdesc[i][3] = |
| 23338 | (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain |
| 23339 | // MG_DEBUG(("%d %p", i, s_rxdesc[i])); |
| 23340 | } |
| 23341 | |
| 23342 | // Init TX descriptors |
| 23343 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 23344 | s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer |
| 23345 | s_txdesc[i][3] = |
| 23346 | (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain |
| 23347 | } |
| 23348 | |
| 23349 | EMAC->EMACDMABUSMOD |= MG_BIT(0); // Software reset |
| 23350 | while ((EMAC->EMACDMABUSMOD & MG_BIT(0)) != 0) |
| 23351 | tm4cspin(1); // Wait until done |
| 23352 | |
| 23353 | // Set MDC clock divider. If user told us the value, use it. Otherwise, guess |
| 23354 | int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; |
| 23355 | EMAC->EMACMIIADDR = ((uint32_t) cr & 0xf) << 2; |
| 23356 | |
| 23357 | // NOTE(cpq): we do not use extended descriptor bit 7, and do not use |
| 23358 | // hardware checksum. Therefore, descriptor size is 4, not 8 |
| 23359 | // EMAC->EMACDMABUSMOD = MG_BIT(13) | MG_BIT(16) | MG_BIT(22) | MG_BIT(23) | |
| 23360 | // MG_BIT(25); |
| 23361 | EMAC->EMACIM = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT |
| 23362 | EMAC->EMACFLOWCTL = MG_BIT(7); // Disable zero-quanta pause |
| 23363 | EMAC->EMACFRAMEFLTR = MG_BIT(10); // Perfect filtering |
| 23364 | // EMAC->EMACPC defaults to internal PHY (EPHY) in MMI mode |
| 23365 | emac_write_phy(EPHY_ADDR, EPHYBMCR, MG_BIT(15)); // Reset internal PHY (EPHY) |
| 23366 | emac_write_phy(EPHY_ADDR, EPHYBMCR, MG_BIT(12)); // Set autonegotiation |
| 23367 | EMAC->EMACRXDLADDR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors |
| 23368 | EMAC->EMACTXDLADDR = (uint32_t) (uintptr_t) s_txdesc; // TX descriptors |
| 23369 | EMAC->EMACDMAIM = MG_BIT(6) | MG_BIT(16); // RIE, NIE |
| 23370 | EMAC->EMACCFG = |
| 23371 | MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast |
| 23372 | EMAC->EMACDMAOPMODE = |
| 23373 | MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF |
| 23374 | EMAC->EMACADDR0H = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; |
| 23375 | EMAC->EMACADDR0L = (uint32_t) (ifp->mac[3] << 24) | |
| 23376 | ((uint32_t) ifp->mac[2] << 16) | |
| 23377 | ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; |
| 23378 | return true; |
| 23379 | } |
| 23380 | |
| 23381 | static uint32_t s_txno; |
| 23382 | static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len, |
| 23383 | struct mg_tcpip_if *ifp) { |
| 23384 | if (len > sizeof(s_txbuf[s_txno])) { |
| 23385 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 23386 | len = 0; // fail |
| 23387 | } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { |
| 23388 | ifp->nerr++; |
| 23389 | MG_ERROR(("No descriptors available")); |
| 23390 | // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) |
| 23391 | // EMAC->EMACDMARIS); |
| 23392 | len = 0; // fail |
| 23393 | } else { |
| 23394 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 23395 | s_txdesc[s_txno][1] = (uint32_t) len; // Set data len |
| 23396 | s_txdesc[s_txno][0] = |
| 23397 | MG_BIT(20) | MG_BIT(28) | MG_BIT(29) | MG_BIT(30); // Chain,FS,LS,IC |
| 23398 | s_txdesc[s_txno][0] |= MG_BIT(31); // Set OWN bit - let DMA take over |
| 23399 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 23400 | } |
| 23401 | EMAC->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF |
| 23402 | EMAC->EMACTXPOLLD = 0; // and resume |
| 23403 | return len; |
| 23404 | (void) ifp; |
| 23405 | } |
| 23406 | |
| 23407 | static void mg_tcpip_driver_tm4c_update_hash_table(struct mg_tcpip_if *ifp) { |
| 23408 | // TODO(): read database, rebuild hash table |
| 23409 | // add mDNS / DNS-SD multicast address |
| 23410 | EMAC->EMACADDR1L = (uint32_t) mcast_addr[3] << 24 | |
| 23411 | (uint32_t) mcast_addr[2] << 16 | |
| 23412 | (uint32_t) mcast_addr[1] << 8 | (uint32_t) mcast_addr[0]; |
| 23413 | EMAC->EMACADDR1H = (uint32_t) mcast_addr[5] << 8 | (uint32_t) mcast_addr[4]; |
| 23414 | EMAC->EMACADDR1H |= MG_BIT(31); // AE |
| 23415 | (void) ifp; |
| 23416 | } |
| 23417 | |
| 23418 | static bool mg_tcpip_driver_tm4c_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 23419 | if (ifp->update_mac_hash_table) { |
| 23420 | mg_tcpip_driver_tm4c_update_hash_table(ifp); |
| 23421 | ifp->update_mac_hash_table = false; |
| 23422 | } |
| 23423 | if (!s1) return false; |
| 23424 | uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR); |
| 23425 | bool up = (bmsr & MG_BIT(2)) ? 1 : 0; |
| 23426 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 23427 | uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS); |
| 23428 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 23429 | // if(link is slow or half) set flags otherwise |
| 23430 | // reg = tmp |
| 23431 | uint32_t emaccfg = |
| 23432 | EMAC->EMACCFG | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex |
| 23433 | if (sts & MG_BIT(1)) emaccfg &= ~MG_BIT(14); // 10M |
| 23434 | if ((sts & MG_BIT(2)) == 0) emaccfg &= ~MG_BIT(11); // Half-duplex |
| 23435 | EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register |
| 23436 | MG_DEBUG(("Link is %uM %s-duplex", emaccfg & MG_BIT(14) ? 100 : 10, |
| 23437 | emaccfg & MG_BIT(11) ? "full" : "half")); |
| 23438 | } |
| 23439 | return up; |
| 23440 | } |
| 23441 | |
| 23442 | void EMAC0_IRQHandler(void); |
| 23443 | static uint32_t s_rxno; |
| 23444 | void EMAC0_IRQHandler(void) { |
| 23445 | if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop |
| 23446 | EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag |
| 23447 | for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever |
| 23448 | if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done |
| 23449 | if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == |
| 23450 | (MG_BIT(8) | MG_BIT(9))) && |
| 23451 | !(s_rxdesc[s_rxno][0] & MG_BIT(15))) { // skip partial/errored frames |
| 23452 | uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (MG_BIT(14) - 1)); |
| 23453 | // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0], |
| 23454 | // EMAC->EMACDMARIS); |
| 23455 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); |
| 23456 | } |
| 23457 | s_rxdesc[s_rxno][0] = MG_BIT(31); |
| 23458 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 23459 | } |
| 23460 | } |
| 23461 | EMAC->EMACDMARIS = MG_BIT(7); // Clear possible RU while processing |
| 23462 | EMAC->EMACRXPOLLD = 0; // and resume RX |
| 23463 | } |
| 23464 | |
| 23465 | struct mg_tcpip_driver mg_tcpip_driver_tm4c = {mg_tcpip_driver_tm4c_init, |
| 23466 | mg_tcpip_driver_tm4c_tx, NULL, |
| 23467 | mg_tcpip_driver_tm4c_poll}; |
| 23468 | #endif |
| 23469 | |
| 23470 | #ifdef MG_ENABLE_LINES |
| 23471 | #line 1 "src/drivers/tms570.c" |
| 23472 | #endif |
| 23473 | |
| 23474 | |
| 23475 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TMS570) && MG_ENABLE_DRIVER_TMS570 |
| 23476 | struct tms570_emac_ctrl { |
| 23477 | volatile uint32_t REVID, SOFTRESET, RESERVED1[1], INTCONTROL, C0RXTHRESHEN, |
| 23478 | C0RXEN, C0TXEN, C0MISCEN, RESERVED2[8], |
| 23479 | C0RXTHRESHSTAT, C0RXSTAT, C0TXSTAT, C0MISCSTAT, |
| 23480 | RESERVED3[8], |
| 23481 | C0RXIMAX, C0TXIMAX; |
| 23482 | }; |
| 23483 | struct tms570_emac { |
| 23484 | volatile uint32_t TXREVID, TXCONTROL, TXTEARDOWN, RESERVED1[1], RXREVID, |
| 23485 | RXCONTROL, RXTEARDOWN, RESERVED2[25], TXINTSTATRAW,TXINTSTATMASKED, |
| 23486 | TXINTMASKSET, TXINTMASKCLEAR, MACINVECTOR, MACEOIVECTOR, RESERVED8[2], RXINTSTATRAW, |
| 23487 | RXINTSTATMASKED, RXINTMASKSET, RXINTMASKCLEAR, MACINTSTATRAW, MACINTSTATMASKED, |
| 23488 | MACINTMASKSET, MACINTMASKCLEAR, RESERVED3[16], RXMBPENABLE, RXUNICASTSET, |
| 23489 | RXUNICASTCLEAR, RXMAXLEN, RXBUFFEROFFSET, RXFILTERLOWTHRESH, RESERVED9[2], RXFLOWTHRESH[8], |
| 23490 | RXFREEBUFFER[8], MACCONTROL, MACSTATUS, EMCONTROL, FIFOCONTROL, MACCONFIG, |
| 23491 | SOFTRESET, RESERVED4[22], MACSRCADDRLO, MACSRCADDRHI, MACHASH1, MACHASH2, |
| 23492 | BOFFTEST, TPACETEST, RXPAUSE, TXPAUSE, RESERVED5[4], RXGOODFRAMES, RXBCASTFRAMES, |
| 23493 | RXMCASTFRAMES, RXPAUSEFRAMES, RXCRCERRORS, RXALIGNCODEERRORS, RXOVERSIZED, |
| 23494 | RXJABBER, RXUNDERSIZED, RXFRAGMENTS, RXFILTERED, RXQOSFILTERED, RXOCTETS, |
| 23495 | TXGOODFRAMES, TXBCASTFRAMES, TXMCASTFRAMES, TXPAUSEFRAMES, TXDEFERRED, |
| 23496 | TXCOLLISION, TXSINGLECOLL, TXMULTICOLL, TXEXCESSIVECOLL, TXLATECOLL, |
| 23497 | TXUNDERRUN, TXCARRIERSENSE, TXOCTETS, FRAME64, FRAME65T127, FRAME128T255, |
| 23498 | FRAME256T511, FRAME512T1023, FRAME1024TUP, NETOCTETS, RXSOFOVERRUNS, |
| 23499 | RXMOFOVERRUNS, RXDMAOVERRUNS, RESERVED6[156], MACADDRLO, MACADDRHI, |
| 23500 | MACINDEX, RESERVED7[61], TXHDP[8], RXHDP[8], TXCP[8], RXCP[8]; |
| 23501 | }; |
| 23502 | struct tms570_mdio { |
| 23503 | volatile uint32_t REVID, CONTROL, ALIVE, LINK, LINKINTRAW, LINKINTMASKED, |
| 23504 | RESERVED1[2], USERINTRAW, USERINTMASKED, USERINTMASKSET, USERINTMASKCLEAR, |
| 23505 | RESERVED2[20], USERACCESS0, USERPHYSEL0, USERACCESS1, USERPHYSEL1; |
| 23506 | }; |
| 23507 | #define SWAP32(x) ( (((x) & 0x000000FF) << 24) | \ |
| 23508 | (((x) & 0x0000FF00) << 8) | \ |
| 23509 | (((x) & 0x00FF0000) >> 8) | \ |
| 23510 | (((x) & 0xFF000000) >> 24) ) |
| 23511 | #undef EMAC |
| 23512 | #undef EMAC_CTRL |
| 23513 | #undef MDIO |
| 23514 | #define EMAC ((struct tms570_emac *) (uintptr_t) 0xFCF78000) |
| 23515 | #define EMAC_CTRL ((struct tms570_emac_ctrl *) (uintptr_t) 0xFCF78800) |
| 23516 | #define MDIO ((struct tms570_mdio *) (uintptr_t) 0xFCF78900) |
| 23517 | #define ETH_PKT_SIZE 1540 // Max frame size |
| 23518 | #define ETH_DESC_CNT 4 // Descriptors count |
| 23519 | #define ETH_DS 4 // Descriptor size (words) |
| 23520 | static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] |
| 23521 | __attribute__((section(".ETH_CPPI"), aligned(4))); // TX descriptors |
| 23522 | static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] |
| 23523 | __attribute__((section(".ETH_CPPI"), aligned(4))); // RX descriptors |
| 23524 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] |
| 23525 | __attribute__((aligned(4))); // RX ethernet buffers |
| 23526 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] |
| 23527 | __attribute__((aligned(4))); // TX ethernet buffers |
| 23528 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 23529 | static uint16_t emac_read_phy(uint8_t addr, uint8_t reg) { |
| 23530 | while(MDIO->USERACCESS0 & MG_BIT(31)) (void) 0; |
| 23531 | MDIO->USERACCESS0 = MG_BIT(31) | ((reg & 0x1f) << 21) | |
| 23532 | ((addr & 0x1f) << 16); |
| 23533 | while(MDIO->USERACCESS0 & MG_BIT(31)) (void) 0; |
| 23534 | return MDIO->USERACCESS0 & 0xffff; |
| 23535 | } |
| 23536 | static void emac_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 23537 | while(MDIO->USERACCESS0 & MG_BIT(31)) (void) 0; |
| 23538 | MDIO->USERACCESS0 = MG_BIT(31) | MG_BIT(30) | ((reg & 0x1f) << 21) | |
| 23539 | ((addr & 0x1f) << 16) | (val & 0xffff); |
| 23540 | while(MDIO->USERACCESS0 & MG_BIT(31)) (void) 0; |
| 23541 | } |
| 23542 | static bool mg_tcpip_driver_tms570_init(struct mg_tcpip_if *ifp) { |
| 23543 | struct mg_tcpip_driver_tms570_data *d = |
| 23544 | (struct mg_tcpip_driver_tms570_data *) ifp->driver_data; |
| 23545 | s_ifp = ifp; |
| 23546 | EMAC_CTRL->SOFTRESET = MG_BIT(0); // Reset the EMAC Control Module |
| 23547 | while(EMAC_CTRL->SOFTRESET & MG_BIT(0)) (void) 0; // wait |
| 23548 | EMAC->SOFTRESET = MG_BIT(0); // Reset the EMAC Module |
| 23549 | while(EMAC->SOFTRESET & MG_BIT(0)) (void) 0; |
| 23550 | EMAC->MACCONTROL = 0; |
| 23551 | EMAC->RXCONTROL = 0; |
| 23552 | EMAC->TXCONTROL = 0; |
| 23553 | // Initialize all the header descriptor pointer registers |
| 23554 | uint32_t i; |
| 23555 | for(i = 0; i < ETH_DESC_CNT; i++) { |
| 23556 | EMAC->RXHDP[i] = 0; |
| 23557 | EMAC->TXHDP[i] = 0; |
| 23558 | EMAC->RXCP[i] = 0; |
| 23559 | EMAC->TXCP[i] = 0; |
| 23560 | ///EMAC->RXFREEBUFFER[i] = 0xff; |
| 23561 | } |
| 23562 | // Clear the interrupt enable for all the channels |
| 23563 | EMAC->TXINTMASKCLEAR = 0xff; |
| 23564 | EMAC->RXINTMASKCLEAR = 0xff; |
| 23565 | EMAC->MACHASH1 = 0; |
| 23566 | EMAC->MACHASH2 = 0; |
| 23567 | EMAC->RXBUFFEROFFSET = 0; |
| 23568 | EMAC->RXUNICASTCLEAR = 0xff; |
| 23569 | EMAC->RXUNICASTSET = 0; |
| 23570 | EMAC->RXMBPENABLE = 0; |
| 23571 | // init MDIO |
| 23572 | // MDIO_CLK frequency = VCLK3/(CLKDIV + 1). (MDIO must be between 1.0 - 2.5Mhz) |
| 23573 | uint32_t clkdiv = 75; // VCLK is configured to 75Mhz |
| 23574 | // CLKDIV, ENABLE, PREAMBLE, FAULTENB |
| 23575 | MDIO->CONTROL = (clkdiv - 1) | MG_BIT(30) | MG_BIT(20) | MG_BIT(18); |
| 23576 | volatile int delay = 0xfff; |
| 23577 | while (delay-- != 0) (void) 0; |
| 23578 | struct mg_phy phy = {emac_read_phy, emac_write_phy}; |
| 23579 | mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); |
| 23580 | uint32_t channel; |
| 23581 | for (channel = 0; channel < 8; channel++) { |
| 23582 | EMAC->MACINDEX = channel; |
| 23583 | EMAC->MACADDRHI = ifp->mac[0] | (ifp->mac[1] << 8) | (ifp->mac[2] << 16) | |
| 23584 | (ifp->mac[3] << 24); |
| 23585 | EMAC->MACADDRLO = ifp->mac[4] | (ifp->mac[5] << 8) | MG_BIT(20) | |
| 23586 | MG_BIT(19) | (channel << 16); |
| 23587 | } |
| 23588 | EMAC->RXUNICASTSET = 1; // accept unicast frames; |
| 23589 | |
| 23590 | EMAC->RXMBPENABLE |= MG_BIT(30) | MG_BIT(13); // CRC, broadcast |
| 23591 | |
| 23592 | // Initialize the descriptors |
| 23593 | for (i = 0; i < ETH_DESC_CNT; i++) { |
| 23594 | if (i < ETH_DESC_CNT - 1) { |
| 23595 | s_txdesc[i][0] = 0; |
| 23596 | s_rxdesc[i][0] = SWAP32(((uint32_t) &s_rxdesc[i + 1][0])); |
| 23597 | } |
| 23598 | s_txdesc[i][1] = SWAP32(((uint32_t) s_txbuf[i])); |
| 23599 | s_rxdesc[i][1] = SWAP32(((uint32_t) s_rxbuf[i])); |
| 23600 | s_txdesc[i][2] = 0; |
| 23601 | s_rxdesc[i][2] = SWAP32(ETH_PKT_SIZE); |
| 23602 | s_txdesc[i][3] = 0; |
| 23603 | s_rxdesc[i][3] = SWAP32(MG_BIT(29)); // OWN |
| 23604 | } |
| 23605 | s_txdesc[ETH_DESC_CNT - 1][0] = 0; |
| 23606 | s_rxdesc[ETH_DESC_CNT - 1][0] = 0; |
| 23607 | |
| 23608 | EMAC->MACCONTROL = MG_BIT(5) | MG_BIT(0); // Enable MII, Full-duplex |
| 23609 | //EMAC->TXINTMASKSET = 1; // Enable TX interrupt |
| 23610 | EMAC->RXINTMASKSET = 1; // Enable RX interrupt |
| 23611 | //EMAC_CTRL->C0TXEN = 1; // TX completion interrupt |
| 23612 | EMAC_CTRL->C0RXEN = 1; // RX completion interrupt |
| 23613 | EMAC->TXCONTROL = 1; // TXEN |
| 23614 | EMAC->RXCONTROL = 1; // RXEN |
| 23615 | EMAC->RXHDP[0] = (uint32_t) &s_rxdesc[0][0]; |
| 23616 | return true; |
| 23617 | } |
| 23618 | static uint32_t s_txno; |
| 23619 | static size_t mg_tcpip_driver_tms570_tx(const void *buf, size_t len, |
| 23620 | struct mg_tcpip_if *ifp) { |
| 23621 | if (len > sizeof(s_txbuf[s_txno])) { |
| 23622 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 23623 | len = 0; // fail |
| 23624 | } else if ((s_txdesc[s_txno][3] & SWAP32(MG_BIT(29)))) { |
| 23625 | ifp->nerr++; |
| 23626 | MG_ERROR(("No descriptors available")); |
| 23627 | len = 0; // fail |
| 23628 | } else { |
| 23629 | memcpy(s_txbuf[s_txno], buf, len); // Copy data |
| 23630 | if (len < 128) len = 128; |
| 23631 | s_txdesc[s_txno][2] = SWAP32((uint32_t) len); // Set data len |
| 23632 | s_txdesc[s_txno][3] = |
| 23633 | SWAP32(MG_BIT(31) | MG_BIT(30) | MG_BIT(29) | len); // SOP, EOP, OWN, length |
| 23634 | |
| 23635 | while(EMAC->TXHDP[0] != 0) (void) 0; |
| 23636 | EMAC->TXHDP[0] = (uint32_t) &s_txdesc[s_txno][0]; |
| 23637 | if(++s_txno == ETH_DESC_CNT) { |
| 23638 | s_txno = 0; |
| 23639 | } |
| 23640 | } |
| 23641 | return len; |
| 23642 | (void) ifp; |
| 23643 | } |
| 23644 | |
| 23645 | static void mg_tcpip_driver_tms570_update_hash_table(struct mg_tcpip_if *ifp) { |
| 23646 | // TODO(): read database, rebuild hash table |
| 23647 | // Setting Hash Index for 01:00:5e:00:00:fb (multicast) |
| 23648 | // using TMS570 XOR method (32.5.37). |
| 23649 | // computed hash is 55, which means bit 23 (55 - 32) in |
| 23650 | // HASH2 register must be set |
| 23651 | EMAC->MACHASH2 = MG_BIT(23); |
| 23652 | EMAC->RXMBPENABLE = MG_BIT(5); // enable hash filtering |
| 23653 | (void) ifp; |
| 23654 | } |
| 23655 | |
| 23656 | static bool mg_tcpip_driver_tms570_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 23657 | if (ifp->update_mac_hash_table) { |
| 23658 | mg_tcpip_driver_tms570_update_hash_table(ifp); |
| 23659 | ifp->update_mac_hash_table = false; |
| 23660 | } |
| 23661 | if (!s1) return false; |
| 23662 | struct mg_tcpip_driver_tms570_data *d = |
| 23663 | (struct mg_tcpip_driver_tms570_data *) ifp->driver_data; |
| 23664 | uint8_t speed = MG_PHY_SPEED_10M; |
| 23665 | bool up = false, full_duplex = false; |
| 23666 | struct mg_phy phy = {emac_read_phy, emac_write_phy}; |
| 23667 | if (!s1) return false; |
| 23668 | up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); |
| 23669 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { |
| 23670 | // link state just went up |
| 23671 | MG_DEBUG(("Link is %uM %s-duplex", speed == MG_PHY_SPEED_10M ? 10 : 100, |
| 23672 | full_duplex ? "full" : "half")); |
| 23673 | } |
| 23674 | return up; |
| 23675 | } |
| 23676 | |
| 23677 | #pragma CODE_STATE(EMAC_TX_IRQHandler, 32) |
| 23678 | #pragma INTERRUPT(EMAC_TX_IRQHandler, IRQ) |
| 23679 | void EMAC_TX_IRQHandler(void) { |
| 23680 | uint32_t status = EMAC_CTRL->C0TXSTAT; |
| 23681 | if (status & 1) { // interrupt caused on channel 0 |
| 23682 | while(s_txdesc[s_txno][3] & SWAP32(MG_BIT(29))) (void) 0; |
| 23683 | EMAC->TXCP[0] = (uint32_t) &s_txdesc[s_txno][0]; |
| 23684 | } |
| 23685 | //Write the DMA end of interrupt vector |
| 23686 | EMAC->MACEOIVECTOR = 2; |
| 23687 | } |
| 23688 | static uint32_t s_rxno; |
| 23689 | #pragma CODE_STATE(EMAC_RX_IRQHandler, 32) |
| 23690 | #pragma INTERRUPT(EMAC_RX_IRQHandler, IRQ) |
| 23691 | void EMAC_RX_IRQHandler(void) { |
| 23692 | uint32_t status = EMAC_CTRL->C0RXSTAT; |
| 23693 | if (status & 1) { // Frame received, loop |
| 23694 | uint32_t i; |
| 23695 | //MG_INFO(("RX interrupt")); |
| 23696 | for (i = 0; i < 10; i++) { // read as they arrive but not forever |
| 23697 | if (s_rxdesc[s_rxno][3] & SWAP32(MG_BIT(29))) break; |
| 23698 | uint32_t len = SWAP32(s_rxdesc[s_rxno][3]) & 0xffff; |
| 23699 | //MG_INFO(("recv len: %d", len)); |
| 23700 | //mg_hexdump(s_rxbuf[s_rxno], len); |
| 23701 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); |
| 23702 | uint32_t flags = s_rxdesc[s_rxno][3]; |
| 23703 | s_rxdesc[s_rxno][3] = SWAP32(MG_BIT(29)); |
| 23704 | s_rxdesc[s_rxno][2] = SWAP32(ETH_PKT_SIZE); |
| 23705 | EMAC->RXCP[0] = (uint32_t) &s_rxdesc[s_rxno][0]; |
| 23706 | if (flags & SWAP32(MG_BIT(28))) { |
| 23707 | //MG_INFO(("EOQ detected")); |
| 23708 | EMAC->RXHDP[0] = (uint32_t) &s_rxdesc[0][0]; |
| 23709 | } |
| 23710 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 23711 | } |
| 23712 | } |
| 23713 | //Write the DMA end of interrupt vector |
| 23714 | EMAC->MACEOIVECTOR = 1; |
| 23715 | } |
| 23716 | struct mg_tcpip_driver mg_tcpip_driver_tms570 = {mg_tcpip_driver_tms570_init, |
| 23717 | mg_tcpip_driver_tms570_tx, NULL, |
| 23718 | mg_tcpip_driver_tms570_poll}; |
| 23719 | #endif |
| 23720 | |
| 23721 | |
| 23722 | #ifdef MG_ENABLE_LINES |
| 23723 | #line 1 "src/drivers/w5100.c" |
| 23724 | #endif |
| 23725 | |
| 23726 | |
| 23727 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5100) && MG_ENABLE_DRIVER_W5100 |
| 23728 | |
| 23729 | static void w5100_txn(struct mg_tcpip_spi *s, uint16_t addr, bool wr, void *buf, |
| 23730 | size_t len) { |
| 23731 | size_t i; |
| 23732 | uint8_t *p = (uint8_t *) buf; |
| 23733 | uint8_t control = wr ? 0xF0 : 0x0F; |
| 23734 | uint8_t cmd[] = {control, (uint8_t) (addr >> 8), (uint8_t) (addr & 255)}; |
| 23735 | s->begin(s->spi); |
| 23736 | for (i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]); |
| 23737 | for (i = 0; i < len; i++) { |
| 23738 | uint8_t r = s->txn(s->spi, p[i]); |
| 23739 | if (!wr) p[i] = r; |
| 23740 | } |
| 23741 | s->end(s->spi); |
| 23742 | } |
| 23743 | |
| 23744 | // clang-format off |
| 23745 | static void w5100_wn(struct mg_tcpip_spi *s, uint16_t addr, void *buf, size_t len) { w5100_txn(s, addr, true, buf, len); } |
| 23746 | static void w5100_w1(struct mg_tcpip_spi *s, uint16_t addr, uint8_t val) { w5100_wn(s, addr, &val, 1); } |
| 23747 | static void w5100_w2(struct mg_tcpip_spi *s, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5100_wn(s, addr, buf, sizeof(buf)); } |
| 23748 | static void w5100_rn(struct mg_tcpip_spi *s, uint16_t addr, void *buf, size_t len) { w5100_txn(s, addr, false, buf, len); } |
| 23749 | static uint8_t w5100_r1(struct mg_tcpip_spi *s, uint16_t addr) { uint8_t r = 0; w5100_rn(s, addr, &r, 1); return r; } |
| 23750 | static uint16_t w5100_r2(struct mg_tcpip_spi *s, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5100_rn(s, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); } |
| 23751 | // clang-format on |
| 23752 | |
| 23753 | static size_t w5100_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) { |
| 23754 | struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23755 | uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len |
| 23756 | while ((n2 = w5100_r2(s, 0x426)) > n) n = n2; // Until it is stable |
| 23757 | if (n > 0) { |
| 23758 | uint16_t ptr = w5100_r2(s, 0x428); // Get read pointer |
| 23759 | if (n <= len + 2 && n > 1) { |
| 23760 | r = (uint16_t) (n - 2); |
| 23761 | } |
| 23762 | uint16_t rxbuf_size = (1 << (w5100_r1(s, 0x1a) & 3)) * 1024; |
| 23763 | uint16_t rxbuf_addr = 0x6000; |
| 23764 | uint16_t ptr_ofs = (ptr + 2) & (rxbuf_size - 1); |
| 23765 | if (ptr_ofs + r < rxbuf_size) { |
| 23766 | w5100_rn(s, rxbuf_addr + ptr_ofs, buf, r); |
| 23767 | } else { |
| 23768 | uint16_t remaining_len = rxbuf_size - ptr_ofs; |
| 23769 | w5100_rn(s, rxbuf_addr + ptr_ofs, buf, remaining_len); |
| 23770 | w5100_rn(s, rxbuf_addr, buf + remaining_len, n - remaining_len); |
| 23771 | } |
| 23772 | w5100_w2(s, 0x428, (uint16_t) (ptr + n)); |
| 23773 | w5100_w1(s, 0x401, 0x40); // Sock0 CR -> RECV |
| 23774 | } |
| 23775 | return r; |
| 23776 | } |
| 23777 | |
| 23778 | static size_t w5100_tx(const void *buf, size_t buflen, |
| 23779 | struct mg_tcpip_if *ifp) { |
| 23780 | struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23781 | uint16_t i, n = 0, ptr = 0, len = (uint16_t) buflen; |
| 23782 | while (n < len) n = w5100_r2(s, 0x420); // Wait for space |
| 23783 | ptr = w5100_r2(s, 0x424); // Get write pointer |
| 23784 | uint16_t txbuf_size = (1 << (w5100_r1(s, 0x1b) & 3)) * 1024; |
| 23785 | uint16_t ptr_ofs = ptr & (txbuf_size - 1); |
| 23786 | uint16_t txbuf_addr = 0x4000; |
| 23787 | if (ptr_ofs + len > txbuf_size) { |
| 23788 | uint16_t size = txbuf_size - ptr_ofs; |
| 23789 | w5100_wn(s, txbuf_addr + ptr_ofs, (char *) buf, size); |
| 23790 | w5100_wn(s, txbuf_addr, (char *) buf + size, len - size); |
| 23791 | } else { |
| 23792 | w5100_wn(s, txbuf_addr + ptr_ofs, (char *) buf, len); |
| 23793 | } |
| 23794 | w5100_w2(s, 0x424, (uint16_t) (ptr + len)); // Advance write pointer |
| 23795 | w5100_w1(s, 0x401, 0x20); // Sock0 CR -> SEND |
| 23796 | for (i = 0; i < 40; i++) { |
| 23797 | uint8_t ir = w5100_r1(s, 0x402); // Read S0 IR |
| 23798 | if (ir == 0) continue; |
| 23799 | // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr); |
| 23800 | w5100_w1(s, 0x402, ir); // Write S0 IR: clear it! |
| 23801 | if (ir & 8) len = 0; // Timeout. Report error |
| 23802 | if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout |
| 23803 | } |
| 23804 | return len; |
| 23805 | } |
| 23806 | |
| 23807 | static bool w5100_init(struct mg_tcpip_if *ifp) { |
| 23808 | struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23809 | s->end(s->spi); |
| 23810 | w5100_w1(s, 0, 0x80); // Reset chip: CR -> 0x80 |
| 23811 | w5100_w1(s, 0x72, 0x53); // CR PHYLCKR -> unlock PHY |
| 23812 | w5100_w1(s, 0x46, 0); // CR PHYCR0 -> autonegotiation |
| 23813 | w5100_w1(s, 0x47, 0); // CR PHYCR1 -> reset |
| 23814 | w5100_w1(s, 0x72, 0x00); // CR PHYLCKR -> lock PHY |
| 23815 | w5100_wn(s, 0x09, ifp->mac, 6); // SHAR |
| 23816 | w5100_w1(s, 0x1a, 6); // Sock0 RX buf size - 4KB |
| 23817 | w5100_w1(s, 0x1b, 6); // Sock0 TX buf size - 4KB |
| 23818 | w5100_w1(s, 0x400, 0x44); // Sock0 MR -> MACRAW, MAC filter |
| 23819 | w5100_w1(s, 0x401, 1); // Sock0 CR -> OPEN |
| 23820 | return w5100_r1(s, 0x403) == 0x42; // Sock0 SR == MACRAW |
| 23821 | } |
| 23822 | |
| 23823 | static bool w5100_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 23824 | struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23825 | return s1 ? w5100_r1(spi, 0x3c /* PHYSR */) & 1 |
| 23826 | : false; // Bit 0 of PHYSR is LNK (0 - down, 1 - up) |
| 23827 | } |
| 23828 | |
| 23829 | struct mg_tcpip_driver mg_tcpip_driver_w5100 = {w5100_init, w5100_tx, w5100_rx, |
| 23830 | w5100_poll}; |
| 23831 | #endif |
| 23832 | |
| 23833 | #ifdef MG_ENABLE_LINES |
| 23834 | #line 1 "src/drivers/w5500.c" |
| 23835 | #endif |
| 23836 | |
| 23837 | |
| 23838 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500 |
| 23839 | |
| 23840 | enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 }; |
| 23841 | |
| 23842 | static void w5500_txn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, |
| 23843 | bool wr, void *buf, size_t len) { |
| 23844 | size_t i; |
| 23845 | uint8_t *p = (uint8_t *) buf; |
| 23846 | uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255), |
| 23847 | (uint8_t) ((block << 3) | (wr ? 4 : 0))}; |
| 23848 | s->begin(s->spi); |
| 23849 | for (i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]); |
| 23850 | for (i = 0; i < len; i++) { |
| 23851 | uint8_t r = s->txn(s->spi, p[i]); |
| 23852 | if (!wr) p[i] = r; |
| 23853 | } |
| 23854 | s->end(s->spi); |
| 23855 | } |
| 23856 | |
| 23857 | // clang-format off |
| 23858 | static void w5500_wn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, true, buf, len); } |
| 23859 | static void w5500_w1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint8_t val) { w5500_wn(s, block, addr, &val, 1); } |
| 23860 | static void w5500_w2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5500_wn(s, block, addr, buf, sizeof(buf)); } |
| 23861 | static void w5500_rn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, false, buf, len); } |
| 23862 | static uint8_t w5500_r1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t r = 0; w5500_rn(s, block, addr, &r, 1); return r; } |
| 23863 | static uint16_t w5500_r2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5500_rn(s, block, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); } |
| 23864 | // clang-format on |
| 23865 | |
| 23866 | static size_t w5500_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) { |
| 23867 | struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23868 | uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len |
| 23869 | while ((n2 = w5500_r2(s, W5500_S0, 0x26)) > n) n = n2; // Until it is stable |
| 23870 | // printf("RSR: %d\n", (int) n); |
| 23871 | if (n > 0) { |
| 23872 | uint16_t ptr = w5500_r2(s, W5500_S0, 0x28); // Get read pointer |
| 23873 | n = w5500_r2(s, W5500_RX0, ptr); // Read frame length |
| 23874 | if (n <= len + 2 && n > 1) { |
| 23875 | r = (uint16_t) (n - 2); |
| 23876 | w5500_rn(s, W5500_RX0, (uint16_t) (ptr + 2), buf, r); |
| 23877 | } |
| 23878 | w5500_w2(s, W5500_S0, 0x28, (uint16_t) (ptr + n)); // Advance read pointer |
| 23879 | w5500_w1(s, W5500_S0, 1, 0x40); // Sock0 CR -> RECV |
| 23880 | // printf(" RX_RD: tot=%u n=%u r=%u\n", n2, n, r); |
| 23881 | } |
| 23882 | return r; |
| 23883 | } |
| 23884 | |
| 23885 | static size_t w5500_tx(const void *buf, size_t buflen, |
| 23886 | struct mg_tcpip_if *ifp) { |
| 23887 | struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23888 | uint16_t i, ptr, n = 0, len = (uint16_t) buflen; |
| 23889 | while (n < len) n = w5500_r2(s, W5500_S0, 0x20); // Wait for space |
| 23890 | ptr = w5500_r2(s, W5500_S0, 0x24); // Get write pointer |
| 23891 | w5500_wn(s, W5500_TX0, ptr, (void *) buf, len); // Write data |
| 23892 | w5500_w2(s, W5500_S0, 0x24, (uint16_t) (ptr + len)); // Advance write pointer |
| 23893 | w5500_w1(s, W5500_S0, 1, 0x20); // Sock0 CR -> SEND |
| 23894 | for (i = 0; i < 40; i++) { |
| 23895 | uint8_t ir = w5500_r1(s, W5500_S0, 2); // Read S0 IR |
| 23896 | if (ir == 0) continue; |
| 23897 | // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr); |
| 23898 | w5500_w1(s, W5500_S0, 2, ir); // Write S0 IR: clear it! |
| 23899 | if (ir & 8) len = 0; // Timeout. Report error |
| 23900 | if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout |
| 23901 | } |
| 23902 | return len; |
| 23903 | } |
| 23904 | |
| 23905 | static bool w5500_init(struct mg_tcpip_if *ifp) { |
| 23906 | struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23907 | s->end(s->spi); |
| 23908 | w5500_w1(s, W5500_CR, 0, 0x80); // Reset chip: CR -> 0x80 |
| 23909 | w5500_w1(s, W5500_CR, 0x2e, 0); // CR PHYCFGR -> reset |
| 23910 | w5500_w1(s, W5500_CR, 0x2e, 0xf8); // CR PHYCFGR -> set |
| 23911 | // w5500_wn(s, W5500_CR, 9, s->mac, 6); // Set source MAC |
| 23912 | w5500_w1(s, W5500_S0, 0x1e, 16); // Sock0 RX buf size |
| 23913 | w5500_w1(s, W5500_S0, 0x1f, 16); // Sock0 TX buf size |
| 23914 | w5500_w1(s, W5500_S0, 0, 4); // Sock0 MR -> MACRAW |
| 23915 | w5500_w1(s, W5500_S0, 1, 1); // Sock0 CR -> OPEN |
| 23916 | return w5500_r1(s, W5500_S0, 3) == 0x42; // Sock0 SR == MACRAW |
| 23917 | } |
| 23918 | |
| 23919 | static bool w5500_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 23920 | struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data; |
| 23921 | return s1 ? w5500_r1(spi, W5500_CR, 0x2e /* PHYCFGR */) & 1 |
| 23922 | : false; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up) |
| 23923 | } |
| 23924 | |
| 23925 | struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, |
| 23926 | w5500_poll}; |
| 23927 | #endif |
| 23928 | |
| 23929 | #ifdef MG_ENABLE_LINES |
| 23930 | #line 1 "src/drivers/xmc.c" |
| 23931 | #endif |
| 23932 | |
| 23933 | |
| 23934 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC |
| 23935 | |
| 23936 | struct ETH_GLOBAL_TypeDef { |
| 23937 | volatile uint32_t MAC_CONFIGURATION, MAC_FRAME_FILTER, HASH_TABLE_HIGH, |
| 23938 | HASH_TABLE_LOW, GMII_ADDRESS, GMII_DATA, FLOW_CONTROL, VLAN_TAG, VERSION, |
| 23939 | DEBUG, REMOTE_WAKE_UP_FRAME_FILTER, PMT_CONTROL_STATUS, RESERVED[2], |
| 23940 | INTERRUPT_STATUS, INTERRUPT_MASK, MAC_ADDRESS0_HIGH, MAC_ADDRESS0_LOW, |
| 23941 | MAC_ADDRESS1_HIGH, MAC_ADDRESS1_LOW, MAC_ADDRESS2_HIGH, MAC_ADDRESS2_LOW, |
| 23942 | MAC_ADDRESS3_HIGH, MAC_ADDRESS3_LOW, RESERVED1[40], MMC_CONTROL, |
| 23943 | MMC_RECEIVE_INTERRUPT, MMC_TRANSMIT_INTERRUPT, MMC_RECEIVE_INTERRUPT_MASK, |
| 23944 | MMC_TRANSMIT_INTERRUPT_MASK, TX_STATISTICS[26], RESERVED2, |
| 23945 | RX_STATISTICS_1[26], RESERVED3[6], MMC_IPC_RECEIVE_INTERRUPT_MASK, |
| 23946 | RESERVED4, MMC_IPC_RECEIVE_INTERRUPT, RESERVED5, RX_STATISTICS_2[30], |
| 23947 | RESERVED7[286], TIMESTAMP_CONTROL, SUB_SECOND_INCREMENT, |
| 23948 | SYSTEM_TIME_SECONDS, SYSTEM_TIME_NANOSECONDS, SYSTEM_TIME_SECONDS_UPDATE, |
| 23949 | SYSTEM_TIME_NANOSECONDS_UPDATE, TIMESTAMP_ADDEND, TARGET_TIME_SECONDS, |
| 23950 | TARGET_TIME_NANOSECONDS, SYSTEM_TIME_HIGHER_WORD_SECONDS, |
| 23951 | TIMESTAMP_STATUS, PPS_CONTROL, RESERVED8[564], BUS_MODE, |
| 23952 | TRANSMIT_POLL_DEMAND, RECEIVE_POLL_DEMAND, |
| 23953 | RECEIVE_DESCRIPTOR_LIST_ADDRESS, TRANSMIT_DESCRIPTOR_LIST_ADDRESS, STATUS, |
| 23954 | OPERATION_MODE, INTERRUPT_ENABLE, |
| 23955 | MISSED_FRAME_AND_BUFFER_OVERFLOW_COUNTER, |
| 23956 | RECEIVE_INTERRUPT_WATCHDOG_TIMER, RESERVED9, AHB_STATUS, RESERVED10[6], |
| 23957 | CURRENT_HOST_TRANSMIT_DESCRIPTOR, CURRENT_HOST_RECEIVE_DESCRIPTOR, |
| 23958 | CURRENT_HOST_TRANSMIT_BUFFER_ADDRESS, CURRENT_HOST_RECEIVE_BUFFER_ADDRESS, |
| 23959 | HW_FEATURE; |
| 23960 | }; |
| 23961 | |
| 23962 | #undef ETH0 |
| 23963 | #define ETH0 ((struct ETH_GLOBAL_TypeDef *) 0x5000C000UL) |
| 23964 | |
| 23965 | #define ETH_PKT_SIZE 1536 // Max frame size |
| 23966 | #define ETH_DESC_CNT 4 // Descriptors count |
| 23967 | #define ETH_DS 4 // Descriptor size (words) |
| 23968 | |
| 23969 | #ifndef ETH_RAM_SECTION |
| 23970 | // if no section is specified, then the data will be placed in the default |
| 23971 | // bss section |
| 23972 | #define ETH_RAM_SECTION |
| 23973 | #endif |
| 23974 | |
| 23975 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] ETH_RAM_SECTION; |
| 23976 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] ETH_RAM_SECTION; |
| 23977 | static uint32_t s_rxdesc[ETH_DESC_CNT] |
| 23978 | [ETH_DS] ETH_RAM_SECTION; // RX descriptors |
| 23979 | static uint32_t s_txdesc[ETH_DESC_CNT] |
| 23980 | [ETH_DS] ETH_RAM_SECTION; // TX descriptors |
| 23981 | static uint8_t s_txno; // Current TX descriptor |
| 23982 | static uint8_t s_rxno; // Current RX descriptor |
| 23983 | |
| 23984 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 23985 | enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; |
| 23986 | |
| 23987 | static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { |
| 23988 | ETH0->GMII_ADDRESS = (ETH0->GMII_ADDRESS & 0x3c) | ((uint32_t) addr << 11) | |
| 23989 | ((uint32_t) reg << 6) | 1; |
| 23990 | while ((ETH0->GMII_ADDRESS & 1) != 0) (void) 0; |
| 23991 | return (uint16_t) (ETH0->GMII_DATA & 0xffff); |
| 23992 | } |
| 23993 | |
| 23994 | static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 23995 | ETH0->GMII_DATA = val; |
| 23996 | ETH0->GMII_ADDRESS = (ETH0->GMII_ADDRESS & 0x3c) | ((uint32_t) addr << 11) | |
| 23997 | ((uint32_t) reg << 6) | 3; |
| 23998 | while ((ETH0->GMII_ADDRESS & 1) != 0) (void) 0; |
| 23999 | } |
| 24000 | |
| 24001 | static uint32_t get_clock_rate(struct mg_tcpip_driver_xmc_data *d) { |
| 24002 | if (d->mdc_cr == -1) { |
| 24003 | // assume ETH clock is 60MHz by default |
| 24004 | // then according to 13.2.8.1, we need to set value 3 |
| 24005 | return 3; |
| 24006 | } |
| 24007 | |
| 24008 | return d->mdc_cr; |
| 24009 | } |
| 24010 | |
| 24011 | static bool mg_tcpip_driver_xmc_init(struct mg_tcpip_if *ifp) { |
| 24012 | struct mg_tcpip_driver_xmc_data *d = |
| 24013 | (struct mg_tcpip_driver_xmc_data *) ifp->driver_data; |
| 24014 | s_ifp = ifp; |
| 24015 | |
| 24016 | // reset MAC |
| 24017 | ETH0->BUS_MODE |= 1; |
| 24018 | while (ETH0->BUS_MODE & 1) (void) 0; |
| 24019 | |
| 24020 | // set clock rate |
| 24021 | ETH0->GMII_ADDRESS = get_clock_rate(d) << 2; |
| 24022 | |
| 24023 | // init phy |
| 24024 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 24025 | mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); |
| 24026 | |
| 24027 | // configure MAC: DO, DM, FES, TC |
| 24028 | ETH0->MAC_CONFIGURATION = MG_BIT(13) | MG_BIT(11) | MG_BIT(14) | MG_BIT(24); |
| 24029 | |
| 24030 | // set the MAC address |
| 24031 | ETH0->MAC_ADDRESS0_HIGH = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]); |
| 24032 | ETH0->MAC_ADDRESS0_LOW = |
| 24033 | MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]); |
| 24034 | |
| 24035 | // Configure the receive filter |
| 24036 | ETH0->MAC_FRAME_FILTER = MG_BIT(10); // Perfect filter |
| 24037 | // Disable flow control |
| 24038 | ETH0->FLOW_CONTROL = 0; |
| 24039 | // Enable store and forward mode |
| 24040 | ETH0->OPERATION_MODE = MG_BIT(25) | MG_BIT(21); // RSF, TSF |
| 24041 | |
| 24042 | // Configure DMA bus mode (AAL, USP, RPBL, PBL) |
| 24043 | ETH0->BUS_MODE = MG_BIT(25) | MG_BIT(23) | (32 << 17) | (32 << 8); |
| 24044 | |
| 24045 | // init RX descriptors |
| 24046 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 24047 | s_rxdesc[i][0] = MG_BIT(31); // OWN descriptor |
| 24048 | s_rxdesc[i][1] = MG_BIT(14) | ETH_PKT_SIZE; |
| 24049 | s_rxdesc[i][2] = (uint32_t) s_rxbuf[i]; |
| 24050 | if (i == ETH_DESC_CNT - 1) { |
| 24051 | s_rxdesc[i][3] = (uint32_t) &s_rxdesc[0][0]; |
| 24052 | } else { |
| 24053 | s_rxdesc[i][3] = (uint32_t) &s_rxdesc[i + 1][0]; |
| 24054 | } |
| 24055 | } |
| 24056 | ETH0->RECEIVE_DESCRIPTOR_LIST_ADDRESS = (uint32_t) &s_rxdesc[0][0]; |
| 24057 | |
| 24058 | // init TX descriptors |
| 24059 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 24060 | s_txdesc[i][0] = MG_BIT(30) | MG_BIT(20); |
| 24061 | s_txdesc[i][2] = (uint32_t) s_txbuf[i]; |
| 24062 | if (i == ETH_DESC_CNT - 1) { |
| 24063 | s_txdesc[i][3] = (uint32_t) &s_txdesc[0][0]; |
| 24064 | } else { |
| 24065 | s_txdesc[i][3] = (uint32_t) &s_txdesc[i + 1][0]; |
| 24066 | } |
| 24067 | } |
| 24068 | ETH0->TRANSMIT_DESCRIPTOR_LIST_ADDRESS = (uint32_t) &s_txdesc[0][0]; |
| 24069 | |
| 24070 | // Clear interrupts |
| 24071 | ETH0->STATUS = 0xFFFFFFFF; |
| 24072 | |
| 24073 | // Disable MAC interrupts |
| 24074 | ETH0->MMC_TRANSMIT_INTERRUPT_MASK = 0xFFFFFFFF; |
| 24075 | ETH0->MMC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF; |
| 24076 | ETH0->MMC_IPC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF; |
| 24077 | ETH0->INTERRUPT_MASK = MG_BIT(9) | MG_BIT(3); // TSIM, PMTIM |
| 24078 | |
| 24079 | // Enable interrupts (NIE, RIE, TIE) |
| 24080 | ETH0->INTERRUPT_ENABLE = MG_BIT(16) | MG_BIT(6) | MG_BIT(0); |
| 24081 | |
| 24082 | // Enable MAC transmission and reception (TE, RE) |
| 24083 | ETH0->MAC_CONFIGURATION |= MG_BIT(3) | MG_BIT(2); |
| 24084 | // Enable DMA transmission and reception (ST, SR) |
| 24085 | ETH0->OPERATION_MODE |= MG_BIT(13) | MG_BIT(1); |
| 24086 | return true; |
| 24087 | } |
| 24088 | |
| 24089 | static size_t mg_tcpip_driver_xmc_tx(const void *buf, size_t len, |
| 24090 | struct mg_tcpip_if *ifp) { |
| 24091 | if (len > sizeof(s_txbuf[s_txno])) { |
| 24092 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 24093 | len = 0; // Frame is too big |
| 24094 | } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { |
| 24095 | ifp->nerr++; |
| 24096 | MG_ERROR(("No free descriptors")); |
| 24097 | len = 0; // All descriptors are busy, fail |
| 24098 | } else { |
| 24099 | memcpy(s_txbuf[s_txno], buf, len); |
| 24100 | s_txdesc[s_txno][1] = len; |
| 24101 | // Table 13-19 Transmit Descriptor Word 0 (IC, LS, FS, TCH) |
| 24102 | s_txdesc[s_txno][0] = MG_BIT(30) | MG_BIT(29) | MG_BIT(28) | MG_BIT(20); |
| 24103 | s_txdesc[s_txno][0] |= MG_BIT(31); // OWN bit: handle control to DMA |
| 24104 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 24105 | } |
| 24106 | |
| 24107 | // Resume processing |
| 24108 | ETH0->STATUS = MG_BIT(2); // clear Transmit unavailable |
| 24109 | ETH0->TRANSMIT_POLL_DEMAND = 0; |
| 24110 | return len; |
| 24111 | } |
| 24112 | |
| 24113 | static void mg_tcpip_driver_xmc_update_hash_table(struct mg_tcpip_if *ifp) { |
| 24114 | // TODO(): read database, rebuild hash table |
| 24115 | // set the multicast address filter |
| 24116 | ETH0->MAC_ADDRESS1_HIGH = |
| 24117 | MG_U32(0, 0, mcast_addr[5], mcast_addr[4]) | MG_BIT(31); |
| 24118 | ETH0->MAC_ADDRESS1_LOW = |
| 24119 | MG_U32(mcast_addr[3], mcast_addr[2], mcast_addr[1], mcast_addr[0]); |
| 24120 | (void) ifp; |
| 24121 | } |
| 24122 | |
| 24123 | static bool mg_tcpip_driver_xmc_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 24124 | if (ifp->update_mac_hash_table) { |
| 24125 | mg_tcpip_driver_xmc_update_hash_table(ifp); |
| 24126 | ifp->update_mac_hash_table = false; |
| 24127 | } |
| 24128 | if (!s1) return false; |
| 24129 | struct mg_tcpip_driver_xmc_data *d = |
| 24130 | (struct mg_tcpip_driver_xmc_data *) ifp->driver_data; |
| 24131 | uint8_t speed = MG_PHY_SPEED_10M; |
| 24132 | bool up = false, full_duplex = false; |
| 24133 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 24134 | up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); |
| 24135 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 24136 | MG_DEBUG(("Link is %uM %s-duplex", speed == MG_PHY_SPEED_10M ? 10 : 100, |
| 24137 | full_duplex ? "full" : "half")); |
| 24138 | } |
| 24139 | return up; |
| 24140 | } |
| 24141 | |
| 24142 | void ETH0_0_IRQHandler(void); |
| 24143 | void ETH0_0_IRQHandler(void) { |
| 24144 | uint32_t irq_status = ETH0->STATUS; |
| 24145 | |
| 24146 | // check if a frame was received |
| 24147 | if (irq_status & MG_BIT(6)) { |
| 24148 | for (uint8_t i = 0; i < 10; i++) { // read as they arrive, but not forever |
| 24149 | if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; |
| 24150 | size_t len = (s_rxdesc[s_rxno][0] & 0x3fff0000) >> 16; |
| 24151 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); |
| 24152 | s_rxdesc[s_rxno][0] = MG_BIT(31); // OWN bit: handle control to DMA |
| 24153 | // Resume processing |
| 24154 | ETH0->STATUS = MG_BIT(7) | MG_BIT(6); // clear RU and RI |
| 24155 | ETH0->RECEIVE_POLL_DEMAND = 0; |
| 24156 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 24157 | } |
| 24158 | ETH0->STATUS = MG_BIT(6); |
| 24159 | } |
| 24160 | |
| 24161 | // clear Successful transmission interrupt |
| 24162 | if (irq_status & 1) { |
| 24163 | ETH0->STATUS = 1; |
| 24164 | } |
| 24165 | |
| 24166 | // clear normal interrupt |
| 24167 | if (irq_status & MG_BIT(16)) { |
| 24168 | ETH0->STATUS = MG_BIT(16); |
| 24169 | } |
| 24170 | } |
| 24171 | |
| 24172 | struct mg_tcpip_driver mg_tcpip_driver_xmc = {mg_tcpip_driver_xmc_init, |
| 24173 | mg_tcpip_driver_xmc_tx, NULL, |
| 24174 | mg_tcpip_driver_xmc_poll}; |
| 24175 | #endif |
| 24176 | |
| 24177 | #ifdef MG_ENABLE_LINES |
| 24178 | #line 1 "src/drivers/xmc7.c" |
| 24179 | #endif |
| 24180 | |
| 24181 | |
| 24182 | #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 |
| 24183 | |
| 24184 | struct ETH_Type { |
| 24185 | volatile uint32_t CTL, STATUS, RESERVED[1022], NETWORK_CONTROL, |
| 24186 | NETWORK_CONFIG, NETWORK_STATUS, USER_IO_REGISTER, DMA_CONFIG, |
| 24187 | TRANSMIT_STATUS, RECEIVE_Q_PTR, TRANSMIT_Q_PTR, RECEIVE_STATUS, |
| 24188 | INT_STATUS, INT_ENABLE, INT_DISABLE, INT_MASK, PHY_MANAGEMENT, PAUSE_TIME, |
| 24189 | TX_PAUSE_QUANTUM, PBUF_TXCUTTHRU, PBUF_RXCUTTHRU, JUMBO_MAX_LENGTH, |
| 24190 | EXTERNAL_FIFO_INTERFACE, RESERVED1, AXI_MAX_PIPELINE, RSC_CONTROL, |
| 24191 | INT_MODERATION, SYS_WAKE_TIME, RESERVED2[7], HASH_BOTTOM, HASH_TOP, |
| 24192 | SPEC_ADD1_BOTTOM, SPEC_ADD1_TOP, SPEC_ADD2_BOTTOM, SPEC_ADD2_TOP, |
| 24193 | SPEC_ADD3_BOTTOM, SPEC_ADD3_TOP, SPEC_ADD4_BOTTOM, SPEC_ADD4_TOP, |
| 24194 | SPEC_TYPE1, SPEC_TYPE2, SPEC_TYPE3, SPEC_TYPE4, WOL_REGISTER, |
| 24195 | STRETCH_RATIO, STACKED_VLAN, TX_PFC_PAUSE, MASK_ADD1_BOTTOM, |
| 24196 | MASK_ADD1_TOP, DMA_ADDR_OR_MASK, RX_PTP_UNICAST, TX_PTP_UNICAST, |
| 24197 | TSU_NSEC_CMP, TSU_SEC_CMP, TSU_MSB_SEC_CMP, TSU_PTP_TX_MSB_SEC, |
| 24198 | TSU_PTP_RX_MSB_SEC, TSU_PEER_TX_MSB_SEC, TSU_PEER_RX_MSB_SEC, |
| 24199 | DPRAM_FILL_DBG, REVISION_REG, OCTETS_TXED_BOTTOM, OCTETS_TXED_TOP, |
| 24200 | FRAMES_TXED_OK, BROADCAST_TXED, MULTICAST_TXED, PAUSE_FRAMES_TXED, |
| 24201 | FRAMES_TXED_64, FRAMES_TXED_65, FRAMES_TXED_128, FRAMES_TXED_256, |
| 24202 | FRAMES_TXED_512, FRAMES_TXED_1024, FRAMES_TXED_1519, TX_UNDERRUNS, |
| 24203 | SINGLE_COLLISIONS, MULTIPLE_COLLISIONS, EXCESSIVE_COLLISIONS, |
| 24204 | LATE_COLLISIONS, DEFERRED_FRAMES, CRS_ERRORS, OCTETS_RXED_BOTTOM, |
| 24205 | OCTETS_RXED_TOP, FRAMES_RXED_OK, BROADCAST_RXED, MULTICAST_RXED, |
| 24206 | PAUSE_FRAMES_RXED, FRAMES_RXED_64, FRAMES_RXED_65, FRAMES_RXED_128, |
| 24207 | FRAMES_RXED_256, FRAMES_RXED_512, FRAMES_RXED_1024, FRAMES_RXED_1519, |
| 24208 | UNDERSIZE_FRAMES, EXCESSIVE_RX_LENGTH, RX_JABBERS, FCS_ERRORS, |
| 24209 | RX_LENGTH_ERRORS, RX_SYMBOL_ERRORS, ALIGNMENT_ERRORS, RX_RESOURCE_ERRORS, |
| 24210 | RX_OVERRUNS, RX_IP_CK_ERRORS, RX_TCP_CK_ERRORS, RX_UDP_CK_ERRORS, |
| 24211 | AUTO_FLUSHED_PKTS, RESERVED3, TSU_TIMER_INCR_SUB_NSEC, TSU_TIMER_MSB_SEC, |
| 24212 | TSU_STROBE_MSB_SEC, TSU_STROBE_SEC, TSU_STROBE_NSEC, TSU_TIMER_SEC, |
| 24213 | TSU_TIMER_NSEC, TSU_TIMER_ADJUST, TSU_TIMER_INCR, TSU_PTP_TX_SEC, |
| 24214 | TSU_PTP_TX_NSEC, TSU_PTP_RX_SEC, TSU_PTP_RX_NSEC, TSU_PEER_TX_SEC, |
| 24215 | TSU_PEER_TX_NSEC, TSU_PEER_RX_SEC, TSU_PEER_RX_NSEC, PCS_CONTROL, |
| 24216 | PCS_STATUS, RESERVED4[2], PCS_AN_ADV, PCS_AN_LP_BASE, PCS_AN_EXP, |
| 24217 | PCS_AN_NP_TX, PCS_AN_LP_NP, RESERVED5[6], PCS_AN_EXT_STATUS, RESERVED6[8], |
| 24218 | TX_PAUSE_QUANTUM1, TX_PAUSE_QUANTUM2, TX_PAUSE_QUANTUM3, RESERVED7, |
| 24219 | RX_LPI, RX_LPI_TIME, TX_LPI, TX_LPI_TIME, DESIGNCFG_DEBUG1, |
| 24220 | DESIGNCFG_DEBUG2, DESIGNCFG_DEBUG3, DESIGNCFG_DEBUG4, DESIGNCFG_DEBUG5, |
| 24221 | DESIGNCFG_DEBUG6, DESIGNCFG_DEBUG7, DESIGNCFG_DEBUG8, DESIGNCFG_DEBUG9, |
| 24222 | DESIGNCFG_DEBUG10, RESERVED8[22], SPEC_ADD5_BOTTOM, SPEC_ADD5_TOP, |
| 24223 | RESERVED9[60], SPEC_ADD36_BOTTOM, SPEC_ADD36_TOP, INT_Q1_STATUS, |
| 24224 | INT_Q2_STATUS, INT_Q3_STATUS, RESERVED10[11], INT_Q15_STATUS, RESERVED11, |
| 24225 | TRANSMIT_Q1_PTR, TRANSMIT_Q2_PTR, TRANSMIT_Q3_PTR, RESERVED12[11], |
| 24226 | TRANSMIT_Q15_PTR, RESERVED13, RECEIVE_Q1_PTR, RECEIVE_Q2_PTR, |
| 24227 | RECEIVE_Q3_PTR, RESERVED14[3], RECEIVE_Q7_PTR, RESERVED15, |
| 24228 | DMA_RXBUF_SIZE_Q1, DMA_RXBUF_SIZE_Q2, DMA_RXBUF_SIZE_Q3, RESERVED16[3], |
| 24229 | DMA_RXBUF_SIZE_Q7, CBS_CONTROL, CBS_IDLESLOPE_Q_A, CBS_IDLESLOPE_Q_B, |
| 24230 | UPPER_TX_Q_BASE_ADDR, TX_BD_CONTROL, RX_BD_CONTROL, UPPER_RX_Q_BASE_ADDR, |
| 24231 | RESERVED17[2], HIDDEN_REG0, HIDDEN_REG1, HIDDEN_REG2, HIDDEN_REG3, |
| 24232 | RESERVED18[2], HIDDEN_REG4, HIDDEN_REG5; |
| 24233 | }; |
| 24234 | |
| 24235 | #define ETH0 ((struct ETH_Type *) 0x40490000) |
| 24236 | |
| 24237 | #define ETH_PKT_SIZE 1536 // Max frame size |
| 24238 | #define ETH_DESC_CNT 4 // Descriptors count |
| 24239 | #define ETH_DS 2 // Descriptor size (words) |
| 24240 | |
| 24241 | // TODO(): handle these in a portable compiler-independent CMSIS-friendly way |
| 24242 | #define MG_8BYTE_ALIGNED __attribute__((aligned((8U)))) |
| 24243 | |
| 24244 | static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; |
| 24245 | static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; |
| 24246 | static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; |
| 24247 | static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; |
| 24248 | static uint8_t s_txno MG_8BYTE_ALIGNED; // Current TX descriptor |
| 24249 | static uint8_t s_rxno MG_8BYTE_ALIGNED; // Current RX descriptor |
| 24250 | |
| 24251 | static struct mg_tcpip_if *s_ifp; // MIP interface |
| 24252 | enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; |
| 24253 | |
| 24254 | static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { |
| 24255 | // WRITE1, READ OPERATION, PHY, REG, WRITE10 |
| 24256 | ETH0->PHY_MANAGEMENT = MG_BIT(30) | MG_BIT(29) | ((addr & 0xf) << 24) | |
| 24257 | ((reg & 0x1f) << 18) | MG_BIT(17); |
| 24258 | while ((ETH0->NETWORK_STATUS & MG_BIT(2)) == 0) (void) 0; |
| 24259 | return ETH0->PHY_MANAGEMENT & 0xffff; |
| 24260 | } |
| 24261 | |
| 24262 | static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { |
| 24263 | ETH0->PHY_MANAGEMENT = MG_BIT(30) | MG_BIT(28) | ((addr & 0xf) << 24) | |
| 24264 | ((reg & 0x1f) << 18) | MG_BIT(17) | val; |
| 24265 | while ((ETH0->NETWORK_STATUS & MG_BIT(2)) == 0) (void) 0; |
| 24266 | } |
| 24267 | |
| 24268 | static uint32_t get_clock_rate(struct mg_tcpip_driver_xmc7_data *d) { |
| 24269 | // see ETH0 -> NETWORK_CONFIG register |
| 24270 | (void) d; |
| 24271 | return 3; |
| 24272 | } |
| 24273 | |
| 24274 | static bool mg_tcpip_driver_xmc7_init(struct mg_tcpip_if *ifp) { |
| 24275 | struct mg_tcpip_driver_xmc7_data *d = |
| 24276 | (struct mg_tcpip_driver_xmc7_data *) ifp->driver_data; |
| 24277 | s_ifp = ifp; |
| 24278 | |
| 24279 | // enable controller, set RGMII mode |
| 24280 | ETH0->CTL = MG_BIT(31) | (4 << 8) | 2; |
| 24281 | |
| 24282 | uint32_t cr = get_clock_rate(d); |
| 24283 | // set NSP change, ignore RX FCS, data bus width, clock rate |
| 24284 | // frame length 1536, full duplex, speed |
| 24285 | ETH0->NETWORK_CONFIG = MG_BIT(29) | MG_BIT(26) | MG_BIT(21) | |
| 24286 | ((cr & 7) << 18) | MG_BIT(8) | MG_BIT(1) | MG_BIT(0); |
| 24287 | |
| 24288 | // config DMA settings: Force TX burst, Discard on Error, set RX buffer size |
| 24289 | // to 1536, TX_PBUF_SIZE, RX_PBUF_SIZE, AMBA_BURST_LENGTH |
| 24290 | ETH0->DMA_CONFIG = |
| 24291 | MG_BIT(26) | MG_BIT(24) | (0x18 << 16) | MG_BIT(10) | (3 << 8) | 4; |
| 24292 | |
| 24293 | // initialize descriptors |
| 24294 | for (int i = 0; i < ETH_DESC_CNT; i++) { |
| 24295 | s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; |
| 24296 | if (i == ETH_DESC_CNT - 1) { |
| 24297 | s_rxdesc[i][0] |= MG_BIT(1); // mark last descriptor |
| 24298 | } |
| 24299 | |
| 24300 | s_txdesc[i][0] = (uint32_t) s_txbuf[i]; |
| 24301 | s_txdesc[i][1] = MG_BIT(31); // OWN descriptor |
| 24302 | if (i == ETH_DESC_CNT - 1) { |
| 24303 | s_txdesc[i][1] |= MG_BIT(30); // mark last descriptor |
| 24304 | } |
| 24305 | } |
| 24306 | ETH0->RECEIVE_Q_PTR = (uint32_t) s_rxdesc; |
| 24307 | ETH0->TRANSMIT_Q_PTR = (uint32_t) s_txdesc; |
| 24308 | |
| 24309 | // disable other queues |
| 24310 | ETH0->TRANSMIT_Q2_PTR = 1; |
| 24311 | ETH0->TRANSMIT_Q1_PTR = 1; |
| 24312 | ETH0->RECEIVE_Q2_PTR = 1; |
| 24313 | ETH0->RECEIVE_Q1_PTR = 1; |
| 24314 | |
| 24315 | // enable interrupts (RX complete) |
| 24316 | ETH0->INT_ENABLE = MG_BIT(1); |
| 24317 | |
| 24318 | // set MAC address |
| 24319 | ETH0->SPEC_ADD1_BOTTOM = |
| 24320 | ifp->mac[3] << 24 | ifp->mac[2] << 16 | ifp->mac[1] << 8 | ifp->mac[0]; |
| 24321 | ETH0->SPEC_ADD1_TOP = ifp->mac[5] << 8 | ifp->mac[4]; |
| 24322 | |
| 24323 | // enable MDIO, TX, RX |
| 24324 | ETH0->NETWORK_CONTROL = MG_BIT(4) | MG_BIT(3) | MG_BIT(2); |
| 24325 | |
| 24326 | // start transmission |
| 24327 | ETH0->NETWORK_CONTROL |= MG_BIT(9); |
| 24328 | |
| 24329 | // init phy |
| 24330 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 24331 | mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); |
| 24332 | |
| 24333 | (void) d; |
| 24334 | return true; |
| 24335 | } |
| 24336 | |
| 24337 | static size_t mg_tcpip_driver_xmc7_tx(const void *buf, size_t len, |
| 24338 | struct mg_tcpip_if *ifp) { |
| 24339 | if (len > sizeof(s_txbuf[s_txno])) { |
| 24340 | MG_ERROR(("Frame too big, %ld", (long) len)); |
| 24341 | len = 0; // Frame is too big |
| 24342 | } else if (((s_txdesc[s_txno][1] & MG_BIT(31)) == 0)) { |
| 24343 | ifp->nerr++; |
| 24344 | MG_ERROR(("No free descriptors")); |
| 24345 | len = 0; // All descriptors are busy, fail |
| 24346 | } else { |
| 24347 | memcpy(s_txbuf[s_txno], buf, len); |
| 24348 | s_txdesc[s_txno][1] = (s_txno == ETH_DESC_CNT - 1 ? MG_BIT(30) : 0) | |
| 24349 | MG_BIT(15) | len; // Last buffer and length |
| 24350 | |
| 24351 | ETH0->NETWORK_CONTROL |= MG_BIT(9); // enable transmission |
| 24352 | if (++s_txno >= ETH_DESC_CNT) s_txno = 0; |
| 24353 | } |
| 24354 | |
| 24355 | MG_DSB(); |
| 24356 | ETH0->TRANSMIT_STATUS = ETH0->TRANSMIT_STATUS; |
| 24357 | ETH0->NETWORK_CONTROL |= MG_BIT(9); // enable transmission |
| 24358 | |
| 24359 | return len; |
| 24360 | } |
| 24361 | |
| 24362 | static void mg_tcpip_driver_xmc7_update_hash_table(struct mg_tcpip_if *ifp) { |
| 24363 | // TODO(): read database, rebuild hash table |
| 24364 | // set multicast MAC address |
| 24365 | ETH0->SPEC_ADD2_BOTTOM = mcast_addr[3] << 24 | mcast_addr[2] << 16 | |
| 24366 | mcast_addr[1] << 8 | mcast_addr[0]; |
| 24367 | ETH0->SPEC_ADD2_TOP = mcast_addr[5] << 8 | mcast_addr[4]; |
| 24368 | (void) ifp; |
| 24369 | } |
| 24370 | |
| 24371 | static bool mg_tcpip_driver_xmc7_poll(struct mg_tcpip_if *ifp, bool s1) { |
| 24372 | if (ifp->update_mac_hash_table) { |
| 24373 | mg_tcpip_driver_xmc7_update_hash_table(ifp); |
| 24374 | ifp->update_mac_hash_table = false; |
| 24375 | } |
| 24376 | if (!s1) return false; |
| 24377 | struct mg_tcpip_driver_xmc7_data *d = |
| 24378 | (struct mg_tcpip_driver_xmc7_data *) ifp->driver_data; |
| 24379 | uint8_t speed = MG_PHY_SPEED_10M; |
| 24380 | bool up = false, full_duplex = false; |
| 24381 | struct mg_phy phy = {eth_read_phy, eth_write_phy}; |
| 24382 | up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); |
| 24383 | if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up |
| 24384 | // tmp = reg with flags set to the most likely situation: 100M full-duplex |
| 24385 | // if(link is slow or half) set flags otherwise |
| 24386 | // reg = tmp |
| 24387 | uint32_t netconf = ETH0->NETWORK_CONFIG; |
| 24388 | MG_SET_BITS(netconf, MG_BIT(10), |
| 24389 | MG_BIT(1) | MG_BIT(0)); // 100M, Full-duplex |
| 24390 | uint32_t ctl = ETH0->CTL; |
| 24391 | MG_SET_BITS(ctl, 0xFF00, 4 << 8); // /5 for 25M clock |
| 24392 | if (speed == MG_PHY_SPEED_1000M) { |
| 24393 | netconf |= MG_BIT(10); // 1000M |
| 24394 | MG_SET_BITS(ctl, 0xFF00, 0); // /1 for 125M clock TODO() IS THIS NEEDED ? |
| 24395 | } else if (speed == MG_PHY_SPEED_10M) { |
| 24396 | netconf &= ~MG_BIT(0); // 10M |
| 24397 | MG_SET_BITS(ctl, 0xFF00, 49); // /50 for 2.5M clock |
| 24398 | } |
| 24399 | if (full_duplex == false) netconf &= ~MG_BIT(1); // Half-duplex |
| 24400 | ETH0->NETWORK_CONFIG = netconf; // IRQ handler does not fiddle with these |
| 24401 | ETH0->CTL = ctl; |
| 24402 | MG_DEBUG(("Link is %uM %s-duplex", |
| 24403 | speed == MG_PHY_SPEED_10M |
| 24404 | ? 10 |
| 24405 | : (speed == MG_PHY_SPEED_100M ? 100 : 1000), |
| 24406 | full_duplex ? "full" : "half")); |
| 24407 | } |
| 24408 | return up; |
| 24409 | } |
| 24410 | |
| 24411 | void ETH_IRQHandler(void) { |
| 24412 | uint32_t irq_status = ETH0->INT_STATUS; |
| 24413 | if (irq_status & MG_BIT(1)) { |
| 24414 | for (uint8_t i = 0; i < 10; i++) { // read as they arrive, but not forever |
| 24415 | if ((s_rxdesc[s_rxno][0] & MG_BIT(0)) == 0) break; |
| 24416 | size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1); |
| 24417 | mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); |
| 24418 | s_rxdesc[s_rxno][0] &= ~MG_BIT(0); // OWN bit: handle control to DMA |
| 24419 | if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; |
| 24420 | } |
| 24421 | } |
| 24422 | |
| 24423 | ETH0->INT_STATUS = irq_status; |
| 24424 | } |
| 24425 | |
| 24426 | struct mg_tcpip_driver mg_tcpip_driver_xmc7 = {mg_tcpip_driver_xmc7_init, |
| 24427 | mg_tcpip_driver_xmc7_tx, NULL, |
| 24428 | mg_tcpip_driver_xmc7_poll}; |
| 24429 | #endif |
| 24430 |