From 8b262031542632159146f4baaabc81e49e03e1ab Mon Sep 17 00:00:00 2001 From: purplerain Date: Thu, 22 Feb 2024 21:37:47 +0000 Subject: [PATCH] sync with OpenBSD -current --- regress/usr.sbin/rpki-client/Makefile.inc | 9 +- .../spl/9X0AhXWTJDl8lJhfOwvnac-42CA.spl | Bin 0 -> 1853 bytes regress/usr.sbin/rpki-client/test-spl.c | 104 ++++ sys/ddb/db_ctf.c | 155 +++++- sys/dev/ic/qwx.c | 101 +++- sys/dev/ic/qwxvar.h | 12 +- sys/dev/pci/if_qwx_pci.c | 293 ++++------- sys/net/route.c | 44 +- sys/net/route.h | 23 +- sys/netinet/in_pcb.c | 7 +- sys/netinet/ip_input.c | 16 +- sys/netinet/ip_output.c | 4 +- sys/netinet6/in6_pcb.c | 5 +- sys/netinet6/in6_src.c | 8 +- sys/netinet6/ip6_forward.c | 5 +- sys/netinet6/ip6_input.c | 14 +- sys/netinet6/ip6_output.c | 4 +- usr.bin/ctfconv/generate.c | 17 +- usr.bin/ctfconv/parse.c | 38 +- usr.bin/ctfdump/ctfdump.c | 13 +- usr.sbin/rpki-client/Makefile | 4 +- usr.sbin/rpki-client/extern.h | 82 ++- usr.sbin/rpki-client/filemode.c | 17 +- usr.sbin/rpki-client/main.c | 35 +- usr.sbin/rpki-client/mft.c | 5 +- usr.sbin/rpki-client/output-bgpd.c | 4 +- usr.sbin/rpki-client/output-bird.c | 8 +- usr.sbin/rpki-client/output-csv.c | 4 +- usr.sbin/rpki-client/output-json.c | 28 +- usr.sbin/rpki-client/output-ometric.c | 16 +- usr.sbin/rpki-client/output.c | 8 +- usr.sbin/rpki-client/parser.c | 51 +- usr.sbin/rpki-client/print.c | 56 +- usr.sbin/rpki-client/repo.c | 26 +- usr.sbin/rpki-client/rpki-client.8 | 13 +- usr.sbin/rpki-client/spl.c | 487 ++++++++++++++++++ usr.sbin/rpki-client/validate.c | 18 +- usr.sbin/rpki-client/x509.c | 7 +- 38 files changed, 1417 insertions(+), 324 deletions(-) create mode 100644 regress/usr.sbin/rpki-client/spl/9X0AhXWTJDl8lJhfOwvnac-42CA.spl create mode 100644 regress/usr.sbin/rpki-client/test-spl.c create mode 100644 usr.sbin/rpki-client/spl.c diff --git a/regress/usr.sbin/rpki-client/Makefile.inc b/regress/usr.sbin/rpki-client/Makefile.inc index d16f78cbc..80326f25f 100644 --- a/regress/usr.sbin/rpki-client/Makefile.inc +++ b/regress/usr.sbin/rpki-client/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.36 2024/01/08 08:26:38 tb Exp $ +# $OpenBSD: Makefile.inc,v 1.37 2024/02/22 12:51:50 job Exp $ .PATH: ${.CURDIR}/../../../../usr.sbin/rpki-client @@ -13,6 +13,7 @@ PROGS += test-tal PROGS += test-rrdp PROGS += test-aspa PROGS += test-tak +PROGS += test-spl .for p in ${PROGS} REGRESS_TARGETS += run-regress-$p @@ -89,6 +90,12 @@ SRCS_test-tak+= test-tak.c tak.c cms.c x509.c ip.c as.c io.c \ run-regress-test-tak: test-tak ./test-tak -v ${.CURDIR}/../tak/*.tak +SRCS_test-spl+= test-spl.c spl.c cms.c x509.c ip.c as.c io.c \ + encoding.c print.c validate.c cert.c crl.c mft.c json.c \ + constraints-dummy.c repo-dummy.c rfc3779.c +run-regress-test-spl: test-spl + ./test-spl -v ${.CURDIR}/../spl/*.spl + SRCS_test-rrdp+= test-rrdp.c rrdp_delta.c rrdp_notification.c cms.c \ rrdp_snapshot.c rrdp_util.c cert.c as.c mft.c io.c \ encoding.c ip.c validate.c crl.c x509.c \ diff --git a/regress/usr.sbin/rpki-client/spl/9X0AhXWTJDl8lJhfOwvnac-42CA.spl b/regress/usr.sbin/rpki-client/spl/9X0AhXWTJDl8lJhfOwvnac-42CA.spl new file mode 100644 index 0000000000000000000000000000000000000000..0fea07fc0f394f9d1470bffa10c921b9e9b19ed5 GIT binary patch literal 1853 zcmbVMX;4#F6n^);mpl^Sp&}X(6`>+XAvYl*1TC_J&7ws_1rafuvIi21P$`92&^l5o zrUJ@HQbiF(Kt<8wf}oV8LsNHXU22h{P^c9bEYJrPtDR1N^v{{^JLk^%?wot>2i1g- z&X}L$pYzNZ5U5s7%!g{i76ll`7#h+U>vH^o9K%rnvzq9Jug)0WcoJ5$_)dsaQI452MjbM@A8fT-aGg#fw&cRJ`nlVK`_*XHi(s8msDA zU_4TJRL{aO9MiK5#xs9K28QE$)+7w4=~-47PS>+MFr3h{GNCgiib6+>09F8JO`uBjE9QPz~Oa2Q&mz0~3VG zGf_1FNagd+A9r=^)(4xcvpinm@UvZ6@u%l9hKnmQXDqE=Xf4QXbv&14)Z#WbaSAE( zT4#6j%#A(Aud6hb7X(U<&~lviGAX}i4l0)KyG zRKKFk{8)&D`A1gL@hRam9?e?c(eEnhdpy@-L2z?3Dx7zLwqNk{)|IsKDe9@d47Xom z?o4w%&Dil#eLzs#ncbRHx_50pZF|R_5j)kBUH4=!mLUzpJ*J2K@_*Rz>`sH@0%22G zXVq1qZ+E&yrTgu+lJ>2QU1{E|s%)CAPP3?{NHFQi+S+U8h4nqx_?LSN6KJ0-}I z*-Ck$LKU5?P^Pg(KE9qS0z=qoNgI5*E*rVQFrKdpUb)&^DM=CWrAxTN4Ng+I63WJ| zHXDzC;V?|QO1mOw`9y1JRGdQYq*6!}$^?Zf`7Z%VjvX8jda;56O zRg`g1F>!Zbh)bauMow^O`2Pfjq0lobbXCY=QJibs;;8i>Y)nZIOC5P!Z%-#xV%$Hz z8nx>Hk-rqh8i~JJ)YN>mDygfrD6nRYWw2QxWXIgF>@(LK*yHEEG(*?zbtvswZqOH* zTOSR7e&9q{^6$UiD&uDC37fN%m&-&=hGx~UUdY{LyEkMlal>!D%)Mp^r~TBsukk(P zL>PT|-_?S%;*_v2AGH%(S?vxsJ+?E}#NLj0bgsUHooE&x6moP*@_>DTKeRpO8JCgz zAlUb|s+TOk>b>dE*JpoU)wb4LbB6R?yxBZ8jj+t08J&ABBB{n>&M@})zP7L;z1Co` zVadnGE^ZSsdm^514|fKR86Vl5t{>=52}tU#u&{RN8am?ARU&#YP<}V?-p+>mGe>vN zj=$>s4uNvipq$$71C;+}{`(%k>B-tyXz|*v7?fkb<$O~|o+*p~fD6@0eCQ4-6)R$UXPHG+6R=0M4)tk>nSre`Xh$xvnIj`#R z`A-Ji*`nOg#*R&-@nN!hZ{P=&`h^)zPt~L0Tes&mYAiP0$!t1so%i&nuH#_o6SmLX zqhZA->vV*h`9sgdgC)b~PX%~w>2Nmmm!3^vmezt)8?SfQ1RaZGVd`(biZ-?})9?EZkQg)EQ}?T@o`yOdm-I z&tJTQH)NdsJUoqzANbY%2z|P7OVP5n!I8Wpy5hr&W|N!!>NX?y7xkX4YyC1v`&|*= xEg~gvS95Bf=98u`e)e?wcJIcFezHBU%L!#1w7;U0hb}+AG%%%LHPIM4=TBo!mstP+ literal 0 HcmV?d00001 diff --git a/regress/usr.sbin/rpki-client/test-spl.c b/regress/usr.sbin/rpki-client/test-spl.c new file mode 100644 index 000000000..bb6019d05 --- /dev/null +++ b/regress/usr.sbin/rpki-client/test-spl.c @@ -0,0 +1,104 @@ +/* $Id: test-spl.c,v 1.1 2024/02/22 12:51:50 job Exp $ */ +/* + * Copyright (c) 2024 Job Snijders + * Copyright (c) 2019 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "extern.h" + +int outformats; +int verbose; +int filemode; + +int +main(int argc, char *argv[]) +{ + int c, i, ppem = 0, verb = 0; + X509 *xp = NULL; + struct spl *p; + unsigned char *buf; + size_t len; + + ERR_load_crypto_strings(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + x509_init_oid(); + + while ((c = getopt(argc, argv, "pv")) != -1) + switch (c) { + case 'p': + if (ppem) + break; + ppem = 1; + break; + case 'v': + verb++; + break; + default: + errx(1, "bad argument %c", c); + } + + argv += optind; + argc -= optind; + + if (argc == 0) + errx(1, "argument missing"); + + for (i = 0; i < argc; i++) { + buf = load_file(argv[i], &len); + if ((p = spl_parse(&xp, argv[i], -1, buf, len)) == NULL) { + free(buf); + break; + } + if (verb) + spl_print(xp, p); + if (ppem) { + if (!PEM_write_X509(stdout, xp)) + errx(1, "PEM_write_X509: unable to write cert"); + } + free(buf); + spl_free(p); + X509_free(xp); + } + + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + + if (i < argc) + errx(1, "test failed for %s", argv[i]); + + printf("OK\n"); + return 0; +} + +time_t +get_current_time(void) +{ + return time(NULL); +} diff --git a/sys/ddb/db_ctf.c b/sys/ddb/db_ctf.c index 1aed046b3..4a490e935 100644 --- a/sys/ddb/db_ctf.c +++ b/sys/ddb/db_ctf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_ctf.c,v 1.33 2022/08/14 14:57:38 millert Exp $ */ +/* $OpenBSD: db_ctf.c,v 1.34 2024/02/22 13:49:17 claudio Exp $ */ /* * Copyright (c) 2016-2017 Martin Pieuchot @@ -55,11 +55,14 @@ static const char *db_ctf_off2name(uint32_t); static Elf_Sym *db_ctf_idx2sym(size_t *, uint8_t); static char *db_ctf_decompress(const char *, size_t, size_t); +uint32_t db_ctf_type_len(const struct ctf_type *); +size_t db_ctf_type_size(const struct ctf_type *); const struct ctf_type *db_ctf_type_by_name(const char *, unsigned int); const struct ctf_type *db_ctf_type_by_symbol(Elf_Sym *); const struct ctf_type *db_ctf_type_by_index(uint16_t); void db_ctf_pprint(const struct ctf_type *, vaddr_t); void db_ctf_pprint_struct(const struct ctf_type *, vaddr_t); +void db_ctf_pprint_enum(const struct ctf_type *, vaddr_t); void db_ctf_pprint_ptr(const struct ctf_type *, vaddr_t); /* @@ -241,6 +244,68 @@ db_ctf_type_len(const struct ctf_type *ctt) return tlen; } +/* + * Return the size of the type. + */ +size_t +db_ctf_type_size(const struct ctf_type *ctt) +{ + vaddr_t taddr = (vaddr_t)ctt; + const struct ctf_type *ref; + const struct ctf_array *arr; + size_t tlen = 0; + uint16_t kind; + uint32_t toff; + uint64_t size; + + kind = CTF_INFO_KIND(ctt->ctt_info); + + if (ctt->ctt_size <= CTF_MAX_SIZE) { + size = ctt->ctt_size; + toff = sizeof(struct ctf_stype); + } else { + size = CTF_TYPE_LSIZE(ctt); + toff = sizeof(struct ctf_type); + } + + switch (kind) { + case CTF_K_UNKNOWN: + case CTF_K_FORWARD: + break; + case CTF_K_INTEGER: + case CTF_K_FLOAT: + tlen = size; + break; + case CTF_K_ARRAY: + arr = (struct ctf_array *)(taddr + toff); + ref = db_ctf_type_by_index(arr->cta_contents); + tlen = arr->cta_nelems * db_ctf_type_size(ref); + break; + case CTF_K_FUNCTION: + tlen = 0; + break; + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + tlen = size; + break; + case CTF_K_POINTER: + tlen = sizeof(void *); + break; + case CTF_K_TYPEDEF: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + ref = db_ctf_type_by_index(ctt->ctt_type); + tlen = db_ctf_type_size(ref); + break; + default: + return 0; + } + + return tlen; +} + /* * Return the CTF type associated to an ELF symbol. */ @@ -347,8 +412,14 @@ db_ctf_pprint(const struct ctf_type *ctt, vaddr_t addr) { vaddr_t taddr = (vaddr_t)ctt; const struct ctf_type *ref; + const struct ctf_array *arr; uint16_t kind; - uint32_t eob, toff; + uint32_t eob, toff, i; + db_expr_t val; + size_t elm_size; + + if (ctt == NULL) + return; kind = CTF_INFO_KIND(ctt->ctt_info); if (ctt->ctt_size <= CTF_MAX_SIZE) @@ -357,20 +428,58 @@ db_ctf_pprint(const struct ctf_type *ctt, vaddr_t addr) toff = sizeof(struct ctf_type); switch (kind) { - case CTF_K_FLOAT: - case CTF_K_ENUM: case CTF_K_ARRAY: + arr = (struct ctf_array *)(taddr + toff); + ref = db_ctf_type_by_index(arr->cta_contents); + elm_size = db_ctf_type_size(ref); + db_printf("["); + for (i = 0; i < arr->cta_nelems; i++) { + db_ctf_pprint(ref, addr + i * elm_size); + if (i + 1 < arr->cta_nelems) + db_printf(","); + } + db_printf("]"); + break; + case CTF_K_ENUM: + db_ctf_pprint_enum(ctt, addr); + break; + case CTF_K_FLOAT: case CTF_K_FUNCTION: - db_printf("%lu", *((unsigned long *)addr)); + val = db_get_value(addr, sizeof(val), 0); + db_printf("%lx", (unsigned long)val); break; case CTF_K_INTEGER: eob = db_get_value((taddr + toff), sizeof(eob), 0); switch (CTF_INT_BITS(eob)) { - case 64: - db_printf("0x%llx", *((long long *)addr)); +#ifndef __LP64__ + case 64: { + uint64_t val64; +#if BYTE_ORDER == LITTLE_ENDIAN + val64 = db_get_value(addr + 4, CTF_INT_BITS(eob) / 8, + CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); + val64 <<= 32; + val64 |= db_get_value(addr, CTF_INT_BITS(eob) / 8, 0); +#else + val64 = db_get_value(addr, CTF_INT_BITS(eob) / 8, + CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); + val64 <<= 32; + val64 |= db_get_value(addr + 4, CTF_INT_BITS(eob) / 8, + 0); +#endif + if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED) + db_printf("%lld", val64); + else + db_printf("%llu", val64); break; + } +#endif default: - db_printf("0x%x", *((int *)addr)); + val = db_get_value(addr, CTF_INT_BITS(eob) / 8, + CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); + if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED) + db_printf("%ld", val); + else + db_printf("%lu", val); break; } break; @@ -416,7 +525,6 @@ db_ctf_pprint_struct(const struct ctf_type *ctt, vaddr_t addr) db_printf("{"); if (size < CTF_LSTRUCT_THRESH) { - for (i = 0; i < vlen; i++) { struct ctf_member *ctm; @@ -451,6 +559,35 @@ db_ctf_pprint_struct(const struct ctf_type *ctt, vaddr_t addr) db_printf("}"); } +void +db_ctf_pprint_enum(const struct ctf_type *ctt, vaddr_t addr) +{ + const char *name = NULL, *p = (const char *)ctt; + struct ctf_enum *cte; + uint32_t toff; + int32_t val; + uint16_t i, vlen; + + vlen = CTF_INFO_VLEN(ctt->ctt_info); + toff = sizeof(struct ctf_stype); + + val = (int32_t)db_get_value(addr, sizeof(val), 1); + for (i = 0; i < vlen; i++) { + cte = (struct ctf_enum *)(p + toff); + toff += sizeof(*cte); + + if (val == cte->cte_value) { + name = db_ctf_off2name(cte->cte_name); + break; + } + } + + if (name != NULL) + db_printf("%s", name); + else + db_printf("#%d", val); +} + void db_ctf_pprint_ptr(const struct ctf_type *ctt, vaddr_t addr) { diff --git a/sys/dev/ic/qwx.c b/sys/dev/ic/qwx.c index 4d5ae2a57..4f56acbbf 100644 --- a/sys/dev/ic/qwx.c +++ b/sys/dev/ic/qwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qwx.c,v 1.48 2024/02/20 11:48:19 stsp Exp $ */ +/* $OpenBSD: qwx.c,v 1.50 2024/02/22 09:08:08 stsp Exp $ */ /* * Copyright 2023 Stefan Sperling @@ -299,6 +299,18 @@ qwx_stop(struct ifnet *ifp) splx(s); } +void +qwx_free_firmware(struct qwx_softc *sc) +{ + int i; + + for (i = 0; i < nitems(sc->fw_img); i++) { + free(sc->fw_img[i].data, M_DEVBUF, sc->fw_img[i].size); + sc->fw_img[i].data = NULL; + sc->fw_img[i].size = 0; + } +} + int qwx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -322,7 +334,7 @@ qwx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (ifp->if_flags & IFF_UP) { if (!(ifp->if_flags & IFF_RUNNING)) { /* Force reload of firmware image from disk. */ - sc->have_firmware = 0; + qwx_free_firmware(sc); err = qwx_init(ifp); } } else { @@ -8374,20 +8386,34 @@ err_free_req: int qwx_qmi_load_bdf_qmi(struct qwx_softc *sc, int regdb) { - u_char *data; + u_char *data = NULL; const u_char *boardfw; - size_t len, boardfw_len; + size_t len = 0, boardfw_len; uint32_t fw_size; int ret = 0, bdf_type; #ifdef notyet const uint8_t *tmp; uint32_t file_type; #endif + int fw_idx = regdb ? QWX_FW_REGDB : QWX_FW_BOARD; - ret = qwx_core_fetch_bdf(sc, &data, &len, &boardfw, &boardfw_len, - regdb ? ATH11K_REGDB_FILE : ATH11K_BOARD_API2_FILE); - if (ret) - return ret; + if (sc->fw_img[fw_idx].data) { + boardfw = sc->fw_img[fw_idx].data; + boardfw_len = sc->fw_img[fw_idx].size; + } else { + ret = qwx_core_fetch_bdf(sc, &data, &len, + &boardfw, &boardfw_len, + regdb ? ATH11K_REGDB_FILE : ATH11K_BOARD_API2_FILE); + if (ret) + return ret; + + sc->fw_img[fw_idx].data = malloc(boardfw_len, M_DEVBUF, + M_NOWAIT); + if (sc->fw_img[fw_idx].data) { + memcpy(sc->fw_img[fw_idx].data, boardfw, boardfw_len); + sc->fw_img[fw_idx].size = boardfw_len; + } + } if (regdb) bdf_type = ATH11K_QMI_BDF_TYPE_REGDB; @@ -8506,16 +8532,24 @@ qwx_qmi_m3_load(struct qwx_softc *sc) char path[PATH_MAX]; int ret; - ret = snprintf(path, sizeof(path), "%s-%s-%s", - ATH11K_FW_DIR, sc->hw_params.fw.dir, ATH11K_M3_FILE); - if (ret < 0 || ret >= sizeof(path)) - return ENOSPC; + if (sc->fw_img[QWX_FW_M3].data) { + data = sc->fw_img[QWX_FW_M3].data; + len = sc->fw_img[QWX_FW_M3].size; + } else { + ret = snprintf(path, sizeof(path), "%s-%s-%s", + ATH11K_FW_DIR, sc->hw_params.fw.dir, ATH11K_M3_FILE); + if (ret < 0 || ret >= sizeof(path)) + return ENOSPC; - ret = loadfirmware(path, &data, &len); - if (ret) { - printf("%s: could not read %s (error %d)\n", - sc->sc_dev.dv_xname, path, ret); - return ret; + ret = loadfirmware(path, &data, &len); + if (ret) { + printf("%s: could not read %s (error %d)\n", + sc->sc_dev.dv_xname, path, ret); + return ret; + } + + sc->fw_img[QWX_FW_M3].data = data; + sc->fw_img[QWX_FW_M3].size = len; } if (sc->m3_mem == NULL || QWX_DMA_LEN(sc->m3_mem) < len) { @@ -8531,7 +8565,6 @@ qwx_qmi_m3_load(struct qwx_softc *sc) } memcpy(QWX_DMA_KVA(sc->m3_mem), data, len); - free(data, M_DEVBUF, len); return 0; } @@ -24709,6 +24742,8 @@ qwx_detach(struct qwx_softc *sc) qwx_dmamem_free(sc->sc_dmat, sc->m3_mem); sc->m3_mem = NULL; } + + qwx_free_firmware(sc); } struct qwx_dmamem * @@ -24762,3 +24797,33 @@ qwx_dmamem_free(bus_dma_tag_t dmat, struct qwx_dmamem *adm) bus_dmamap_destroy(dmat, adm->map); free(adm, M_DEVBUF, sizeof(*adm)); } + +int +qwx_activate(struct device *self, int act) +{ + struct qwx_softc *sc = (struct qwx_softc *)self; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int err = 0; + + switch (act) { + case DVACT_QUIESCE: + if (ifp->if_flags & IFF_RUNNING) { + rw_enter_write(&sc->ioctl_rwl); + qwx_stop(ifp); + rw_exit(&sc->ioctl_rwl); + } + break; + case DVACT_RESUME: + break; + case DVACT_WAKEUP: + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) { + err = qwx_init(ifp); + if (err) + printf("%s: could not initialize hardware\n", + sc->sc_dev.dv_xname); + } + break; + } + + return 0; +} diff --git a/sys/dev/ic/qwxvar.h b/sys/dev/ic/qwxvar.h index 95d007071..f7ced75ec 100644 --- a/sys/dev/ic/qwxvar.h +++ b/sys/dev/ic/qwxvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: qwxvar.h,v 1.20 2024/02/16 14:13:45 stsp Exp $ */ +/* $OpenBSD: qwxvar.h,v 1.22 2024/02/22 09:08:08 stsp Exp $ */ /* * Copyright (c) 2018-2019 The Linux Foundation. @@ -1782,7 +1782,14 @@ struct qwx_softc { struct qwx_survey_info survey[IEEE80211_CHAN_MAX]; int attached; - int have_firmware; + struct { + u_char *data; + size_t size; + } fw_img[4]; +#define QWX_FW_AMSS 0 +#define QWX_FW_BOARD 1 +#define QWX_FW_M3 2 +#define QWX_FW_REGDB 3 int sc_tx_timer; uint32_t qfullmsk; @@ -1901,6 +1908,7 @@ int qwx_dp_service_srng(struct qwx_softc *, int); int qwx_init_hw_params(struct qwx_softc *); int qwx_attach(struct qwx_softc *); void qwx_detach(struct qwx_softc *); +int qwx_activate(struct device *, int); void qwx_core_deinit(struct qwx_softc *); void qwx_ce_cleanup_pipes(struct qwx_softc *); diff --git a/sys/dev/pci/if_qwx_pci.c b/sys/dev/pci/if_qwx_pci.c index 5ce1905ba..a4f8241f2 100644 --- a/sys/dev/pci/if_qwx_pci.c +++ b/sys/dev/pci/if_qwx_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_qwx_pci.c,v 1.10 2024/02/16 16:37:42 stsp Exp $ */ +/* $OpenBSD: if_qwx_pci.c,v 1.14 2024/02/22 09:15:34 stsp Exp $ */ /* * Copyright 2023 Stefan Sperling @@ -323,16 +323,6 @@ struct qwx_pci_cmd_ring { struct qwx_pci_ops; struct qwx_msi_config; -struct qwx_mhi_newstate { - struct { - int mhi_state; - int ee; - } queue[4]; - int cur; - int tail; - int queued; -}; - #define QWX_NUM_MSI_VEC 32 struct qwx_pci_softc { @@ -366,12 +356,8 @@ struct qwx_pci_softc { uint64_t wake_db; - struct qwx_mhi_newstate mhi_newstate; - struct task mhi_newstate_task; - struct taskq *mhi_taskq; - /* - * DMA memory for AMMS.bin firmware image. + * DMA memory for AMSS.bin firmware image. * This memory must remain available to the device until * the device is powered down. */ @@ -402,7 +388,6 @@ int qwx_pci_match(struct device *, void *, void *); void qwx_pci_attach(struct device *, struct device *, void *); int qwx_pci_detach(struct device *, int); void qwx_pci_attach_hook(struct device *); -int qwx_pci_activate(struct device *, int); void qwx_pci_free_xfer_rings(struct qwx_pci_softc *); int qwx_pci_alloc_xfer_ring(struct qwx_softc *, struct qwx_pci_xfer_ring *, uint32_t, uint32_t, uint32_t, size_t); @@ -463,7 +448,6 @@ int qwx_mhi_fw_load_handler(struct qwx_pci_softc *); int qwx_mhi_await_device_reset(struct qwx_softc *); int qwx_mhi_await_device_ready(struct qwx_softc *); void qwx_mhi_ready_state_transition(struct qwx_pci_softc *); -void qwx_mhi_ee_amss_state_transition(struct qwx_pci_softc *); void qwx_mhi_mission_mode_state_transition(struct qwx_pci_softc *); void qwx_mhi_low_power_mode_state_transition(struct qwx_pci_softc *); void qwx_mhi_set_state(struct qwx_softc *, uint32_t); @@ -473,8 +457,6 @@ int qwx_mhi_fw_load_bhie(struct qwx_pci_softc *, uint8_t *, size_t); void qwx_rddm_prepare(struct qwx_pci_softc *); void qwx_rddm_task(void *); void * qwx_pci_event_ring_get_elem(struct qwx_pci_event_ring *, uint64_t); -void qwx_mhi_queue_state_change(struct qwx_pci_softc *, int, int); -void qwx_mhi_state_change(void *); void qwx_pci_intr_ctrl_event_mhi(struct qwx_pci_softc *, uint32_t); void qwx_pci_intr_ctrl_event_ee(struct qwx_pci_softc *, uint32_t); void qwx_pci_intr_ctrl_event_cmd_complete(struct qwx_pci_softc *, @@ -526,7 +508,7 @@ const struct cfattach qwx_pci_ca = { qwx_pci_match, qwx_pci_attach, qwx_pci_detach, - qwx_pci_activate + qwx_activate }; /* XXX pcidev */ @@ -1037,10 +1019,6 @@ unsupported_wcn6855_soc: if (sc->sc_nswq == NULL) goto err_ce_free; - psc->mhi_taskq = taskq_create("qwxmhi", 1, IPL_NET, 0); - if (psc->mhi_taskq == NULL) - goto err_ce_free; - qwx_pci_init_qmi_ce_config(sc); error = qwx_pcic_config_irq(sc, pa); @@ -1067,7 +1045,6 @@ unsupported_wcn6855_soc: goto err_irq_affinity_cleanup; } #endif - task_set(&psc->mhi_newstate_task, qwx_mhi_state_change, psc); task_set(&psc->rddm_task, qwx_rddm_task, psc); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -1204,19 +1181,6 @@ qwx_pci_attach_hook(struct device *self) splx(s); } -int -qwx_pci_activate(struct device *self, int act) -{ - switch (act) { - case DVACT_SUSPEND: - break; - case DVACT_WAKEUP: - break; - } - - return 0; -} - void qwx_pci_free_xfer_rings(struct qwx_pci_softc *psc) { @@ -2203,12 +2167,8 @@ int qwx_pci_power_up(struct qwx_softc *sc) { struct qwx_pci_softc *psc = (struct qwx_pci_softc *)sc; - struct qwx_mhi_newstate *ns = &psc->mhi_newstate; int error; - task_del(psc->mhi_taskq, &psc->mhi_newstate_task); - memset(ns, 0, sizeof(*ns)); - psc->register_window = 0; clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, sc->sc_flags); @@ -2234,12 +2194,6 @@ qwx_pci_power_up(struct qwx_softc *sc) void qwx_pci_power_down(struct qwx_softc *sc) { - struct qwx_pci_softc *psc = (struct qwx_pci_softc *)sc; - struct qwx_mhi_newstate *ns = &psc->mhi_newstate; - - task_del(psc->mhi_taskq, &psc->mhi_newstate_task); - memset(ns, 0, sizeof(*ns)); - /* restore aspm in case firmware bootup fails */ qwx_pci_aspm_restore(sc); @@ -2951,6 +2905,10 @@ qwx_mhi_start(struct qwx_pci_softc *psc) ret = qwx_mhi_fw_load_handler(psc); if (ret) return ret; + + /* XXX without this delay starting the channels may fail */ + delay(1000); + qwx_mhi_start_channels(psc); } else { /* XXX Handle partially initialized device...?!? */ ee = qwx_pci_read(sc, psc->bhi_off + MHI_BHI_EXECENV); @@ -3046,23 +3004,31 @@ qwx_mhi_fw_load_handler(struct qwx_pci_softc *psc) u_char *data; size_t len; - ret = snprintf(amss_path, sizeof(amss_path), "%s-%s-%s", - ATH11K_FW_DIR, sc->hw_params.fw.dir, ATH11K_AMSS_FILE); - if (ret < 0 || ret >= sizeof(amss_path)) - return ENOSPC; + if (sc->fw_img[QWX_FW_AMSS].data) { + data = sc->fw_img[QWX_FW_AMSS].data; + len = sc->fw_img[QWX_FW_AMSS].size; + } else { + ret = snprintf(amss_path, sizeof(amss_path), "%s-%s-%s", + ATH11K_FW_DIR, sc->hw_params.fw.dir, ATH11K_AMSS_FILE); + if (ret < 0 || ret >= sizeof(amss_path)) + return ENOSPC; - ret = loadfirmware(amss_path, &data, &len); - if (ret) { - printf("%s: could not read %s (error %d)\n", - sc->sc_dev.dv_xname, amss_path, ret); - return ret; - } + ret = loadfirmware(amss_path, &data, &len); + if (ret) { + printf("%s: could not read %s (error %d)\n", + sc->sc_dev.dv_xname, amss_path, ret); + return ret; + } - if (len < MHI_DMA_VEC_CHUNK_SIZE) { - printf("%s: %s is too short, have only %zu bytes\n", - sc->sc_dev.dv_xname, amss_path, len); - free(data, M_DEVBUF, len); - return EINVAL; + if (len < MHI_DMA_VEC_CHUNK_SIZE) { + printf("%s: %s is too short, have only %zu bytes\n", + sc->sc_dev.dv_xname, amss_path, len); + free(data, M_DEVBUF, len); + return EINVAL; + } + + sc->fw_img[QWX_FW_AMSS].data = data; + sc->fw_img[QWX_FW_AMSS].size = len; } /* Second-stage boot loader sits in the first 512 KB of image. */ @@ -3070,7 +3036,6 @@ qwx_mhi_fw_load_handler(struct qwx_pci_softc *psc) if (ret != 0) { printf("%s: could not load firmware %s\n", sc->sc_dev.dv_xname, amss_path); - free(data, M_DEVBUF, len); return ret; } @@ -3079,6 +3044,7 @@ qwx_mhi_fw_load_handler(struct qwx_pci_softc *psc) if (ret != 0) { printf("%s: could not load firmware %s\n", sc->sc_dev.dv_xname, amss_path); + return ret; } while (psc->bhi_ee < MHI_EE_AMSS) { @@ -3090,11 +3056,8 @@ qwx_mhi_fw_load_handler(struct qwx_pci_softc *psc) if (ret != 0) { printf("%s: device failed to enter AMSS EE\n", sc->sc_dev.dv_xname); - free(data, M_DEVBUF, len); - return ret; } - free(data, M_DEVBUF, len); return ret; } @@ -3182,15 +3145,6 @@ qwx_mhi_ready_state_transition(struct qwx_pci_softc *psc) qwx_mhi_set_state(sc, MHI_STATE_M0); } -void -qwx_mhi_ee_amss_state_transition(struct qwx_pci_softc *psc) -{ - /* XXX without this delay starting the channels may fail */ - delay(1000); - - qwx_mhi_start_channels(psc); -} - void qwx_mhi_mission_mode_state_transition(struct qwx_pci_softc *psc) { @@ -3627,120 +3581,87 @@ qwx_pci_event_ring_get_elem(struct qwx_pci_event_ring *ring, uint64_t rp) } void -qwx_mhi_state_change(void *arg) +qwx_mhi_state_change(struct qwx_pci_softc *psc, int ee, int mhi_state) { - struct qwx_pci_softc *psc = arg; struct qwx_softc *sc = &psc->sc_sc; - struct qwx_mhi_newstate *ns = &psc->mhi_newstate; - int s = splnet(); + uint32_t old_ee = psc->bhi_ee; + uint32_t old_mhi_state = psc->mhi_state; - while (ns->tail != ns->cur) { - int mhi_state = ns->queue[ns->tail].mhi_state; - int ee = ns->queue[ns->tail].ee; - uint32_t old_ee = psc->bhi_ee; - uint32_t old_mhi_state = psc->mhi_state; - - KASSERT(ns->queued > 0); - - if (ee != -1 && psc->bhi_ee != ee) { - switch (ee) { - case MHI_EE_PBL: - DNPRINTF(QWX_D_MHI, "%s: new EE PBL\n", - sc->sc_dev.dv_xname); - psc->bhi_ee = ee; - break; - case MHI_EE_SBL: - psc->bhi_ee = ee; - DNPRINTF(QWX_D_MHI, "%s: new EE SBL\n", - sc->sc_dev.dv_xname); - break; - case MHI_EE_AMSS: - DNPRINTF(QWX_D_MHI, "%s: new EE AMSS\n", - sc->sc_dev.dv_xname); - psc->bhi_ee = ee; - qwx_mhi_ee_amss_state_transition(psc); - /* Wake thread loading the full AMSS image. */ - wakeup(&psc->bhie_off); - break; - case MHI_EE_WFW: - DNPRINTF(QWX_D_MHI, "%s: new EE WFW\n", - sc->sc_dev.dv_xname); - psc->bhi_ee = ee; - break; - default: - printf("%s: unhandled EE change to %x\n", - sc->sc_dev.dv_xname, ee); - break; - } + if (ee != -1 && psc->bhi_ee != ee) { + switch (ee) { + case MHI_EE_PBL: + DNPRINTF(QWX_D_MHI, "%s: new EE PBL\n", + sc->sc_dev.dv_xname); + psc->bhi_ee = ee; + break; + case MHI_EE_SBL: + psc->bhi_ee = ee; + DNPRINTF(QWX_D_MHI, "%s: new EE SBL\n", + sc->sc_dev.dv_xname); + break; + case MHI_EE_AMSS: + DNPRINTF(QWX_D_MHI, "%s: new EE AMSS\n", + sc->sc_dev.dv_xname); + psc->bhi_ee = ee; + /* Wake thread loading the full AMSS image. */ + wakeup(&psc->bhie_off); + break; + case MHI_EE_WFW: + DNPRINTF(QWX_D_MHI, "%s: new EE WFW\n", + sc->sc_dev.dv_xname); + psc->bhi_ee = ee; + break; + default: + printf("%s: unhandled EE change to %x\n", + sc->sc_dev.dv_xname, ee); + break; } - - if (mhi_state != -1 && psc->mhi_state != mhi_state) { - switch (mhi_state) { - case -1: - break; - case MHI_STATE_RESET: - DNPRINTF(QWX_D_MHI, "%s: new MHI state RESET\n", - sc->sc_dev.dv_xname); - psc->mhi_state = mhi_state; - break; - case MHI_STATE_READY: - DNPRINTF(QWX_D_MHI, "%s: new MHI state READY\n", - sc->sc_dev.dv_xname); - psc->mhi_state = mhi_state; - qwx_mhi_ready_state_transition(psc); - break; - case MHI_STATE_M0: - DNPRINTF(QWX_D_MHI, "%s: new MHI state M0\n", - sc->sc_dev.dv_xname); - psc->mhi_state = mhi_state; - qwx_mhi_mission_mode_state_transition(psc); - break; - case MHI_STATE_M1: - DNPRINTF(QWX_D_MHI, "%s: new MHI state M1\n", - sc->sc_dev.dv_xname); - psc->mhi_state = mhi_state; - qwx_mhi_low_power_mode_state_transition(psc); - break; - case MHI_STATE_SYS_ERR: - DNPRINTF(QWX_D_MHI, - "%s: new MHI state SYS ERR\n", - sc->sc_dev.dv_xname); - psc->mhi_state = mhi_state; - break; - default: - printf("%s: unhandled MHI state change to %x\n", - sc->sc_dev.dv_xname, mhi_state); - break; - } - } - - if (old_ee != psc->bhi_ee) - wakeup(&psc->bhi_ee); - if (old_mhi_state != psc->mhi_state) - wakeup(&psc->mhi_state); - - ns->tail = (ns->tail + 1) % nitems(ns->queue); - ns->queued--; } - splx(s); -} - -void -qwx_mhi_queue_state_change(struct qwx_pci_softc *psc, int ee, int mhi_state) -{ - struct qwx_mhi_newstate *ns = &psc->mhi_newstate; - - if (ns->queued >= nitems(ns->queue)) { - printf("%s: event queue full, dropping event\n", __func__); - return; + if (mhi_state != -1 && psc->mhi_state != mhi_state) { + switch (mhi_state) { + case -1: + break; + case MHI_STATE_RESET: + DNPRINTF(QWX_D_MHI, "%s: new MHI state RESET\n", + sc->sc_dev.dv_xname); + psc->mhi_state = mhi_state; + break; + case MHI_STATE_READY: + DNPRINTF(QWX_D_MHI, "%s: new MHI state READY\n", + sc->sc_dev.dv_xname); + psc->mhi_state = mhi_state; + qwx_mhi_ready_state_transition(psc); + break; + case MHI_STATE_M0: + DNPRINTF(QWX_D_MHI, "%s: new MHI state M0\n", + sc->sc_dev.dv_xname); + psc->mhi_state = mhi_state; + qwx_mhi_mission_mode_state_transition(psc); + break; + case MHI_STATE_M1: + DNPRINTF(QWX_D_MHI, "%s: new MHI state M1\n", + sc->sc_dev.dv_xname); + psc->mhi_state = mhi_state; + qwx_mhi_low_power_mode_state_transition(psc); + break; + case MHI_STATE_SYS_ERR: + DNPRINTF(QWX_D_MHI, + "%s: new MHI state SYS ERR\n", + sc->sc_dev.dv_xname); + psc->mhi_state = mhi_state; + break; + default: + printf("%s: unhandled MHI state change to %x\n", + sc->sc_dev.dv_xname, mhi_state); + break; + } } - ns->queue[ns->cur].ee = ee; - ns->queue[ns->cur].mhi_state = mhi_state; - ns->queued++; - ns->cur = (ns->cur + 1) % nitems(ns->queue); - task_add(psc->mhi_taskq, &psc->mhi_newstate_task); + if (old_ee != psc->bhi_ee) + wakeup(&psc->bhi_ee); + if (old_mhi_state != psc->mhi_state) + wakeup(&psc->mhi_state); } void @@ -3750,7 +3671,7 @@ qwx_pci_intr_ctrl_event_mhi(struct qwx_pci_softc *psc, uint32_t mhi_state) psc->mhi_state, mhi_state); if (psc->mhi_state != mhi_state) - qwx_mhi_queue_state_change(psc, -1, mhi_state); + qwx_mhi_state_change(psc, -1, mhi_state); } void @@ -3760,7 +3681,7 @@ qwx_pci_intr_ctrl_event_ee(struct qwx_pci_softc *psc, uint32_t ee) psc->bhi_ee, ee); if (psc->bhi_ee != ee) - qwx_mhi_queue_state_change(psc, ee, -1); + qwx_mhi_state_change(psc, ee, -1); } void @@ -4169,7 +4090,7 @@ qwx_pci_intr(void *arg) new_mhi_state = state; if (new_ee != -1 || new_mhi_state != -1) - qwx_mhi_queue_state_change(psc, new_ee, new_mhi_state); + qwx_mhi_state_change(psc, new_ee, new_mhi_state); ret = 1; } diff --git a/sys/net/route.c b/sys/net/route.c index f9915cdf7..9188b6c4c 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.432 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: route.c,v 1.433 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* @@ -202,7 +202,8 @@ route_init(void) } int -route_cache(struct route *ro, struct in_addr addr, u_int rtableid) +route_cache(struct route *ro, const struct in_addr *dst, + const struct in_addr *src, u_int rtableid) { u_long gen; @@ -213,28 +214,35 @@ route_cache(struct route *ro, struct in_addr addr, u_int rtableid) ro->ro_generation == gen && ro->ro_tableid == rtableid && ro->ro_dstsa.sa_family == AF_INET && - ro->ro_dstsin.sin_addr.s_addr == addr.s_addr) { - ipstat_inc(ips_rtcachehit); - return (0); + ro->ro_dstsin.sin_addr.s_addr == dst->s_addr) { + if (src == NULL || !ipmultipath || + !ISSET(ro->ro_rt->rt_flags, RTF_MPATH) || + (ro->ro_srcin.s_addr != INADDR_ANY && + ro->ro_srcin.s_addr == src->s_addr)) { + ipstat_inc(ips_rtcachehit); + return (0); + } } ipstat_inc(ips_rtcachemiss); rtfree(ro->ro_rt); - ro->ro_rt = NULL; + memset(ro, 0, sizeof(*ro)); ro->ro_generation = gen; ro->ro_tableid = rtableid; - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); ro->ro_dstsin.sin_family = AF_INET; ro->ro_dstsin.sin_len = sizeof(struct sockaddr_in); - ro->ro_dstsin.sin_addr = addr; + ro->ro_dstsin.sin_addr = *dst; + if (src != NULL) + ro->ro_srcin = *src; return (ESRCH); } #ifdef INET6 int -route6_cache(struct route *ro, const struct in6_addr *addr, u_int rtableid) +route6_cache(struct route *ro, const struct in6_addr *dst, + const struct in6_addr *src, u_int rtableid) { u_long gen; @@ -245,21 +253,27 @@ route6_cache(struct route *ro, const struct in6_addr *addr, u_int rtableid) ro->ro_generation == gen && ro->ro_tableid == rtableid && ro->ro_dstsa.sa_family == AF_INET6 && - IN6_ARE_ADDR_EQUAL(&ro->ro_dstsin6.sin6_addr, addr)) { - ip6stat_inc(ip6s_rtcachehit); - return (0); + IN6_ARE_ADDR_EQUAL(&ro->ro_dstsin6.sin6_addr, dst)) { + if (src == NULL || !ip6_multipath || + !ISSET(ro->ro_rt->rt_flags, RTF_MPATH) || + (!IN6_IS_ADDR_UNSPECIFIED(&ro->ro_srcin6) && + IN6_ARE_ADDR_EQUAL(&ro->ro_srcin6, src))) { + ip6stat_inc(ip6s_rtcachehit); + return (0); + } } ip6stat_inc(ip6s_rtcachemiss); rtfree(ro->ro_rt); - ro->ro_rt = NULL; + memset(ro, 0, sizeof(*ro)); ro->ro_generation = gen; ro->ro_tableid = rtableid; - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); ro->ro_dstsin6.sin6_family = AF_INET6; ro->ro_dstsin6.sin6_len = sizeof(struct sockaddr_in6); - ro->ro_dstsin6.sin6_addr = *addr; + ro->ro_dstsin6.sin6_addr = *dst; + if (src != NULL) + ro->ro_srcin6 = *src; return (ESRCH); } diff --git a/sys/net/route.h b/sys/net/route.h index 7833f7ca9..fe652bd09 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.206 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: route.h,v 1.207 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -393,13 +393,14 @@ struct route { u_long ro_generation; u_long ro_tableid; /* u_long because of alignment */ union { - struct sockaddr rod_sa; - struct sockaddr_in rod_sin; - struct sockaddr_in6 rod_sin6; - } ro_dst; -#define ro_dstsa ro_dst.rod_sa -#define ro_dstsin ro_dst.rod_sin -#define ro_dstsin6 ro_dst.rod_sin6 + struct sockaddr ro_dstsa; + struct sockaddr_in ro_dstsin; + struct sockaddr_in6 ro_dstsin6; + }; + union { + struct in_addr ro_srcin; + struct in6_addr ro_srcin6; + }; }; #endif /* __BSD_VISIBLE */ @@ -462,8 +463,10 @@ struct if_ieee80211_data; struct bfd_config; void route_init(void); -int route_cache(struct route *, struct in_addr, u_int); -int route6_cache(struct route *, const struct in6_addr *, u_int); +int route_cache(struct route *, const struct in_addr *, + const struct in_addr *, u_int); +int route6_cache(struct route *, const struct in6_addr *, + const struct in6_addr *, u_int); void rtm_ifchg(struct ifnet *); void rtm_ifannounce(struct ifnet *, int); void rtm_bfd(struct bfd_config *); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 87241c03e..cc08e6292 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.293 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.294 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -919,7 +919,8 @@ in_pcbrtentry(struct inpcb *inp) if (inp->inp_faddr.s_addr == INADDR_ANY) return (NULL); - if (route_cache(ro, inp->inp_faddr, inp->inp_rtableid)) { + if (route_cache(ro, &inp->inp_faddr, &inp->inp_laddr, + inp->inp_rtableid)) { ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, &inp->inp_laddr.s_addr, ro->ro_tableid); } @@ -982,7 +983,7 @@ in_pcbselsrc(struct in_addr *insrc, struct sockaddr_in *sin, * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ - if (route_cache(ro, sin->sin_addr, rtableid)) { + if (route_cache(ro, &sin->sin_addr, NULL, rtableid)) { /* No route yet, so try to acquire one */ ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid); } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 60c6e6a42..d8709c94c 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.389 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip_input.c,v 1.390 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -118,7 +118,6 @@ const struct sysctl_bounded_args ipctl_vars[] = { { IPCTL_IPPORT_HILASTAUTO, &ipport_hilastauto, 0, 65535 }, { IPCTL_IPPORT_MAXQUEUE, &ip_maxqueue, 0, 10000 }, { IPCTL_MFORWARDING, &ipmforwarding, 0, 1 }, - { IPCTL_MULTIPATH, &ipmultipath, 0, 1 }, { IPCTL_ARPTIMEOUT, &arpt_keep, 0, INT_MAX }, { IPCTL_ARPDOWN, &arpt_down, 0, INT_MAX }, }; @@ -1491,7 +1490,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) } ro.ro_rt = NULL; - route_cache(&ro, ip->ip_dst, m->m_pkthdr.ph_rtableid); + route_cache(&ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); if (!rtisvalid(rt)) { rtfree(rt); rt = rtalloc_mpath(&ro.ro_dstsa, &ip->ip_src.s_addr, @@ -1633,10 +1632,10 @@ int ip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - int error; #ifdef MROUTING extern struct mrtstat mrtstat; #endif + int oldval, error; /* Almost all sysctl names at this level are terminal. */ if (namelen != 1 && name[0] != IPCTL_IFQUEUE && @@ -1721,6 +1720,15 @@ ip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, case IPCTL_MRTVIF: return (EOPNOTSUPP); #endif + case IPCTL_MULTIPATH: + NET_LOCK(); + oldval = ipmultipath; + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, + &ipmultipath, 0, 1); + if (oldval != ipmultipath) + atomic_inc_long(&rtgeneration); + NET_UNLOCK(); + return (error); default: NET_LOCK(); error = sysctl_bounded_arr(ipctl_vars, nitems(ipctl_vars), diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 561b690c7..0a6069603 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.395 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip_output.c,v 1.396 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -166,7 +166,7 @@ reroute: * If there is a cached route, check that it is to the same * destination and is still up. If not, free it and try again. */ - route_cache(ro, ip->ip_dst, m->m_pkthdr.ph_rtableid); + route_cache(ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); dst = &ro->ro_dstsin; if ((IN_MULTICAST(ip->ip_dst.s_addr) || diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index d622c5dcc..cea4415c1 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.138 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.139 2024/02/22 14:25:58 bluhm Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -565,7 +565,8 @@ in6_pcbrtentry(struct inpcb *inp) if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) return (NULL); - if (route6_cache(ro, &inp->inp_faddr6, inp->inp_rtableid)) { + if (route6_cache(ro, &inp->inp_faddr6, &inp->inp_laddr6, + inp->inp_rtableid)) { ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, &inp->inp_laddr6.s6_addr32[0], ro->ro_tableid); } diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 470ad67eb..ac35960a0 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_src.c,v 1.94 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: in6_src.c,v 1.95 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: in6_src.c,v 1.36 2001/02/06 04:08:17 itojun Exp $ */ /* @@ -179,8 +179,8 @@ in6_pcbselsrc(const struct in6_addr **in6src, struct sockaddr_in6 *dstsock, * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ - if (route6_cache(ro, dst, rtableid)) { - ro->ro_rt = rtalloc(&ro->ro_dstsa, RT_RESOLVE, ro->ro_tableid); + if (route6_cache(ro, dst, NULL, rtableid)) { + ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid); } /* @@ -304,7 +304,7 @@ in6_selectroute(const struct in6_addr *dst, struct ip6_pktopts *opts, * a new one. */ if (ro) { - if (route6_cache(ro, dst, rtableid)) { + if (route6_cache(ro, dst, NULL, rtableid)) { /* No route yet, so try to acquire one */ ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid); diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index cdb2fb417..65a51d52d 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_forward.c,v 1.114 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip6_forward.c,v 1.115 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ /* @@ -166,7 +166,8 @@ reroute: #endif /* IPSEC */ ro.ro_rt = NULL; - route6_cache(&ro, &ip6->ip6_dst, m->m_pkthdr.ph_rtableid); + route6_cache(&ro, &ip6->ip6_dst, &ip6->ip6_src, + m->m_pkthdr.ph_rtableid); dst = &ro.ro_dstsa; if (!rtisvalid(rt)) { rtfree(rt); diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 21bd2848c..5d7840744 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.257 2023/12/03 20:36:24 bluhm Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.258 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -1451,7 +1451,6 @@ const struct sysctl_bounded_args ipv6ctl_vars[] = { { IPV6CTL_USE_DEPRECATED, &ip6_use_deprecated, 0, 1 }, { IPV6CTL_MAXFRAGS, &ip6_maxfrags, 0, 1000 }, { IPV6CTL_MFORWARDING, &ip6_mforwarding, 0, 1 }, - { IPV6CTL_MULTIPATH, &ip6_multipath, 0, 1 }, { IPV6CTL_MCAST_PMTU, &ip6_mcast_pmtu, 0, 1 }, { IPV6CTL_NEIGHBORGCTHRESH, &ip6_neighborgcthresh, -1, 5 * 2048 }, { IPV6CTL_MAXDYNROUTES, &ip6_maxdynroutes, -1, 5 * 4096 }, @@ -1499,7 +1498,7 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, #ifdef MROUTING extern struct mrt6stat mrt6stat; #endif - int error; + int oldval, error; /* Almost all sysctl names at this level are terminal. */ if (namelen != 1 && name[0] != IPV6CTL_IFQUEUE) @@ -1551,6 +1550,15 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, oldp, oldlenp, newp, newlen, &ip6intrq)); case IPV6CTL_SOIIKEY: return (ip6_sysctl_soiikey(oldp, oldlenp, newp, newlen)); + case IPV6CTL_MULTIPATH: + NET_LOCK(); + oldval = ip6_multipath; + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, + &ip6_multipath, 0, 1); + if (oldval != ip6_multipath) + atomic_inc_long(&rtgeneration); + NET_UNLOCK(); + return (error); default: NET_LOCK(); error = sysctl_bounded_arr(ipv6ctl_vars, nitems(ipv6ctl_vars), diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index adb5f3055..e277d4959 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_output.c,v 1.286 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip6_output.c,v 1.287 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -480,7 +480,7 @@ reroute: goto bad; } } else { - route6_cache(ro, &ip6->ip6_dst, m->m_pkthdr.ph_rtableid); + route6_cache(ro, &ip6->ip6_dst, NULL, m->m_pkthdr.ph_rtableid); } if (rt && (rt->rt_flags & RTF_GATEWAY) && diff --git a/usr.bin/ctfconv/generate.c b/usr.bin/ctfconv/generate.c index c2911f59c..fdbaa0ea3 100644 --- a/usr.bin/ctfconv/generate.c +++ b/usr.bin/ctfconv/generate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: generate.c,v 1.5 2022/08/14 14:54:13 millert Exp $ */ +/* $OpenBSD: generate.c,v 1.6 2024/02/22 13:15:17 claudio Exp $ */ /* * Copyright (c) 2017 Martin Pieuchot @@ -196,7 +196,20 @@ imcs_add_type(struct imcs *imcs, struct itype *it) ctt.ctt_type = it->it_refp->it_idx; ctsz = sizeof(struct ctf_stype); } else if (size <= CTF_MAX_SIZE) { - ctt.ctt_size = size; + if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) { + assert(size <= 64); + if (size == 0) + ctt.ctt_size = 0; + else if (size <= 8) + ctt.ctt_size = 1; + else if (size <= 16) + ctt.ctt_size = 2; + else if (size <= 32) + ctt.ctt_size = 4; + else + ctt.ctt_size = 8; + } else + ctt.ctt_size = size; ctsz = sizeof(struct ctf_stype); } else { ctt.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size); diff --git a/usr.bin/ctfconv/parse.c b/usr.bin/ctfconv/parse.c index 1b271c8d2..ef483f914 100644 --- a/usr.bin/ctfconv/parse.c +++ b/usr.bin/ctfconv/parse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.c,v 1.19 2024/02/21 13:24:37 claudio Exp $ */ +/* $OpenBSD: parse.c,v 1.20 2024/02/22 13:17:18 claudio Exp $ */ /* * Copyright (c) 2016-2017 Martin Pieuchot @@ -323,20 +323,30 @@ it_free(struct itype *it) int it_cmp(struct itype *a, struct itype *b) { - int diff; + if (a->it_type > b->it_type) + return 1; + if (a->it_type < b->it_type) + return -1; - if ((diff = (a->it_type - b->it_type)) != 0) - return diff; - - /* Basic types need to have the same size. */ - if ((a->it_type == CTF_K_INTEGER || a->it_type == CTF_K_FLOAT) && - (diff = (a->it_size - b->it_size) != 0)) - return diff; + /* Basic types need to have the same encoding and size. */ + if ((a->it_type == CTF_K_INTEGER || a->it_type == CTF_K_FLOAT)) { + if (a->it_enc > b->it_enc) + return 1; + if (a->it_enc < b->it_enc) + return -1; + if (a->it_size > b->it_size) + return 1; + if (a->it_size < b->it_size) + return -1; + } /* Arrays need to have same number of elements */ - if ((a->it_type == CTF_K_ARRAY) && - (diff = (a->it_nelems - b->it_nelems) != 0)) - return diff; + if (a->it_type == CTF_K_ARRAY) { + if (a->it_nelems > b->it_nelems) + return 1; + if (a->it_nelems < b->it_nelems) + return -1; + } /* Match by name */ if (!(a->it_flags & ITF_ANON) && !(b->it_flags & ITF_ANON)) @@ -349,6 +359,10 @@ it_cmp(struct itype *a, struct itype *b) /* Match by reference */ if ((a->it_refp != NULL) && (b->it_refp != NULL)) return it_cmp(a->it_refp, b->it_refp); + if (a->it_refp == NULL) + return -1; + if (b->it_refp == NULL) + return 1; return 0; } diff --git a/usr.bin/ctfdump/ctfdump.c b/usr.bin/ctfdump/ctfdump.c index d23e73717..58a79071a 100644 --- a/usr.bin/ctfdump/ctfdump.c +++ b/usr.bin/ctfdump/ctfdump.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ctfdump.c,v 1.27 2022/08/14 15:01:18 millert Exp $ */ +/* $OpenBSD: ctfdump.c,v 1.28 2024/02/22 13:21:03 claudio Exp $ */ /* * Copyright (c) 2016 Martin Pieuchot @@ -490,16 +490,16 @@ ctf_dump_type(struct ctf_header *cth, const char *data, size_t dlen, case CTF_K_INTEGER: eob = *((uint32_t *)(p + toff)); toff += sizeof(uint32_t); - printf(" encoding=%s offset=%u bits=%u", + printf(" encoding=%s offset=%u bits=%u (%llu bytes)", ctf_enc2name(CTF_INT_ENCODING(eob)), CTF_INT_OFFSET(eob), - CTF_INT_BITS(eob)); + CTF_INT_BITS(eob), size); break; case CTF_K_FLOAT: eob = *((uint32_t *)(p + toff)); toff += sizeof(uint32_t); - printf(" encoding=%s offset=%u bits=%u", + printf(" encoding=%s offset=%u bits=%u (%llu bytes)", ctf_fpenc2name(CTF_FP_ENCODING(eob)), CTF_FP_OFFSET(eob), - CTF_FP_BITS(eob)); + CTF_FP_BITS(eob), size); break; case CTF_K_ARRAY: cta = (struct ctf_array *)(p + toff); @@ -563,7 +563,8 @@ ctf_dump_type(struct ctf_header *cth, const char *data, size_t dlen, } break; case CTF_K_ENUM: - printf("\n"); + printf(" (%llu bytes)\n", size); + for (i = 0; i < vlen; i++) { struct ctf_enum *cte; diff --git a/usr.sbin/rpki-client/Makefile b/usr.sbin/rpki-client/Makefile index edb66b697..25db84691 100644 --- a/usr.sbin/rpki-client/Makefile +++ b/usr.sbin/rpki-client/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.33 2023/10/13 12:06:49 job Exp $ +# $OpenBSD: Makefile,v 1.34 2024/02/22 12:49:42 job Exp $ PROG= rpki-client SRCS= as.c aspa.c cert.c cms.c constraints.c crl.c encoding.c filemode.c \ @@ -6,7 +6,7 @@ SRCS= as.c aspa.c cert.c cms.c constraints.c crl.c encoding.c filemode.c \ output.c output-bgpd.c output-bird.c output-csv.c output-json.c \ output-ometric.c parser.c print.c repo.c rfc3779.c roa.c \ rrdp.c rrdp_delta.c rrdp_notification.c rrdp_snapshot.c rrdp_util.c \ - rsc.c rsync.c tak.c tal.c validate.c x509.c + rsc.c rsync.c spl.c tak.c tal.c validate.c x509.c MAN= rpki-client.8 LDADD+= -lexpat -ltls -lssl -lcrypto -lutil -lz diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 10235441c..0aedd75ab 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.207 2024/02/21 12:48:25 tb Exp $ */ +/* $OpenBSD: extern.h,v 1.208 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -178,6 +178,7 @@ enum rtype { RTYPE_ASPA, RTYPE_TAK, RTYPE_GEOFEED, + RTYPE_SPL, }; enum location { @@ -280,6 +281,34 @@ struct rsc { time_t expires; /* when the signature path expires */ }; +/* + * An IP address prefix in a given SignedPrefixList. + */ +struct spl_pfx { + enum afi afi; + struct ip_addr prefix; +}; + +/* + * An SPL, draft-ietf-sidrops-rpki-prefixlist + * This consists of an ASID and its IP prefixes. + */ +struct spl { + uint32_t asid; + struct spl_pfx *pfxs; + size_t pfxsz; + int talid; + char *aia; + char *aki; + char *sia; + char *ski; + time_t signtime; /* CMS signing-time attribute */ + time_t notbefore; /* EE cert's Not Before */ + time_t notafter; /* EE cert's Not After */ + time_t expires; /* when the certification path expires */ + int valid; +}; + /* * Datastructure representing the TAKey sequence inside TAKs. */ @@ -409,6 +438,26 @@ struct vrp { RB_HEAD(vrp_tree, vrp); RB_PROTOTYPE(vrp_tree, vrp, entry, vrpcmp); +/* + * Validated SignedPrefixList Payload + * A single VSP element (including ASID) + * draft-ietf-sidrops-rpki-prefixlist + */ +struct vsp { + RB_ENTRY(vsp) entry; + uint32_t asid; + struct spl_pfx *prefixes; + size_t prefixesz; + time_t expires; + int talid; + unsigned int repoid; +}; +/* + * Tree of VSP sorted by asid + */ +RB_HEAD(vsp_tree, vsp); +RB_PROTOTYPE(vsp_tree, vsp, entry, vspcmp); + /* * A single BGPsec Router Key (including ASID) */ @@ -561,6 +610,11 @@ struct repotalstats { uint32_t vaps_pas; /* total number of providers */ uint32_t vrps; /* total number of Validated ROA Payloads */ uint32_t vrps_uniqs; /* number of unique vrps */ + uint32_t spls; /* signed prefix list */ + uint32_t spls_fail; /* failing syntactic parse */ + uint32_t spls_invalid; /* invalid asid */ + uint32_t vsps; /* total number of Validated SPL Payloads */ + uint32_t vsps_uniqs; /* number of unique vsps */ }; struct repostats { @@ -637,6 +691,14 @@ struct roa *roa_read(struct ibuf *); void roa_insert_vrps(struct vrp_tree *, struct roa *, struct repo *); +void spl_buffer(struct ibuf *, const struct spl *); +void spl_free(struct spl *); +struct spl *spl_parse(X509 **, const char *, int, const unsigned char *, + size_t); +struct spl *spl_read(struct ibuf *); +void spl_insert_vsps(struct vsp_tree *, struct spl *, + struct repo *); + void gbr_free(struct gbr *); struct gbr *gbr_parse(X509 **, const char *, int, const unsigned char *, size_t); @@ -690,6 +752,7 @@ int valid_aspa(const char *, struct cert *, struct aspa *); int valid_geofeed(const char *, struct cert *, struct geofeed *); int valid_uuid(const char *); int valid_ca_pkey(const char *, EVP_PKEY *); +int valid_spl(const char *, struct cert *, struct spl *); /* Working with CMS. */ unsigned char *cms_parse_validate(X509 **, const char *, @@ -870,6 +933,7 @@ void rsc_print(const X509 *, const struct rsc *); void aspa_print(const X509 *, const struct aspa *); void tak_print(const X509 *, const struct tak *); void geofeed_print(const X509 *, const struct geofeed *); +void spl_print(const X509 *, const struct spl *); /* Missing RFC 3779 API */ IPAddrBlocks *IPAddrBlocks_new(void); @@ -885,22 +949,22 @@ extern int outformats; #define FORMAT_OMETRIC 0x10 int outputfiles(struct vrp_tree *v, struct brk_tree *b, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int outputheader(FILE *, struct stats *); int output_bgpd(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int output_bird1v4(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int output_bird1v6(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int output_bird2(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int output_csv(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int output_json(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); int output_ometric(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); void logx(const char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/usr.sbin/rpki-client/filemode.c b/usr.sbin/rpki-client/filemode.c index 7532b68c3..5daf03b72 100644 --- a/usr.sbin/rpki-client/filemode.c +++ b/usr.sbin/rpki-client/filemode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filemode.c,v 1.37 2024/01/23 09:32:57 job Exp $ */ +/* $OpenBSD: filemode.c,v 1.38 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -296,6 +296,7 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) struct mft *mft = NULL; struct roa *roa = NULL; struct rsc *rsc = NULL; + struct spl *spl = NULL; struct tak *tak = NULL; struct tal *tal = NULL; char *aia = NULL, *aki = NULL; @@ -422,6 +423,15 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) expires = &rsc->expires; notafter = &rsc->notafter; break; + case RTYPE_SPL: + spl = spl_parse(&x509, file, -1, buf, len); + if (spl == NULL) + break; + aia = spl->aia; + aki = spl->aki; + expires = &spl->expires; + notafter = &spl->notafter; + break; case RTYPE_TAK: tak = tak_parse(&x509, file, -1, buf, len); if (tak == NULL) @@ -464,6 +474,8 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) case RTYPE_RSC: status = rsc->valid; break; + case RTYPE_SPL: + status = spl->valid; default: break; } @@ -523,6 +535,9 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) case RTYPE_RSC: rsc_print(x509, rsc); break; + case RTYPE_SPL: + spl_print(x509, spl); + break; case RTYPE_TAK: tak_print(x509, tak); break; diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index 6f51e0fac..933494a25 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.250 2024/02/21 12:48:25 tb Exp $ */ +/* $OpenBSD: main.c,v 1.251 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -557,7 +557,8 @@ queue_add_from_cert(const struct cert *cert) */ static void entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, - struct brk_tree *brktree, struct vap_tree *vaptree) + struct brk_tree *brktree, struct vap_tree *vaptree, + struct vsp_tree *vsptree) { enum rtype type; struct tal *tal; @@ -565,6 +566,7 @@ entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, struct mft *mft; struct roa *roa; struct aspa *aspa; + struct spl *spl; struct repo *rp; char *file; time_t mtime; @@ -665,6 +667,19 @@ entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, repo_stat_inc(rp, talid, type, STYPE_INVALID); aspa_free(aspa); break; + case RTYPE_SPL: + io_read_buf(b, &c, sizeof(c)); + if (c == 0) { + repo_stat_inc(rp, talid, type, STYPE_FAIL); + break; + } + spl = spl_read(b); + if (spl->valid) + spl_insert_vsps(vsptree, spl, rp); + else + repo_stat_inc(rp, talid, type, STYPE_INVALID); + spl_free(spl); + break; case RTYPE_TAK: break; case RTYPE_FILE: @@ -755,6 +770,11 @@ sum_stats(const struct repo *rp, const struct repotalstats *in, void *arg) out->vaps += in->vaps; out->vaps_uniqs += in->vaps_uniqs; out->vaps_pas += in->vaps_pas; + out->spls += in->spls; + out->spls_fail += in->spls_fail; + out->spls_invalid += in->spls_invalid; + out->vsps += in->vsps; + out->vsps_uniqs += in->vsps_uniqs; } static void @@ -947,6 +967,7 @@ main(int argc, char *argv[]) const char *errs, *name; const char *skiplistfile = NULL; struct vrp_tree vrps = RB_INITIALIZER(&vrps); + struct vsp_tree vsps = RB_INITIALIZER(&vsps); struct brk_tree brks = RB_INITIALIZER(&brks); struct vap_tree vaps = RB_INITIALIZER(&vaps); struct rusage ru; @@ -1341,7 +1362,8 @@ main(int argc, char *argv[]) if ((pfd[0].revents & POLLIN)) { b = io_buf_read(proc, &procbuf); if (b != NULL) { - entity_process(b, &stats, &vrps, &brks, &vaps); + entity_process(b, &stats, &vrps, &brks, &vaps, + &vsps); ibuf_free(b); } } @@ -1434,7 +1456,7 @@ main(int argc, char *argv[]) } repo_stats_collect(sum_repostats, &stats.repo_stats); - if (outputfiles(&vrps, &brks, &vaps, &stats)) + if (outputfiles(&vrps, &brks, &vaps, &vsps, &stats)) rc = 1; printf("Processing time %lld seconds " @@ -1451,6 +1473,9 @@ main(int argc, char *argv[]) "invalid)\n", stats.repo_tal_stats.aspas, stats.repo_tal_stats.aspas_fail, stats.repo_tal_stats.aspas_invalid); + printf("Signed Prefix Lists: %u (%u failed parse, %u invalid)\n", + stats.repo_tal_stats.spls, stats.repo_tal_stats.spls_fail, + stats.repo_tal_stats.spls_invalid); printf("BGPsec Router Certificates: %u\n", stats.repo_tal_stats.brks); printf("Certificates: %u (%u invalid)\n", stats.repo_tal_stats.certs, stats.repo_tal_stats.certs_fail); @@ -1470,6 +1495,8 @@ main(int argc, char *argv[]) stats.repo_tal_stats.vrps_uniqs); printf("VAP Entries: %u (%u unique)\n", stats.repo_tal_stats.vaps, stats.repo_tal_stats.vaps_uniqs); + printf("VSP Entries: %u (%u unique)\n", stats.repo_tal_stats.vsps, + stats.repo_tal_stats.vsps_uniqs); /* Memory cleanup. */ repo_free(); diff --git a/usr.sbin/rpki-client/mft.c b/usr.sbin/rpki-client/mft.c index bc3fb930b..8f48a881d 100644 --- a/usr.sbin/rpki-client/mft.c +++ b/usr.sbin/rpki-client/mft.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mft.c,v 1.111 2024/02/21 09:17:06 tb Exp $ */ +/* $OpenBSD: mft.c,v 1.112 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2019 Kristaps Dzonsons @@ -121,6 +121,8 @@ rtype_from_file_extension(const char *fn) return RTYPE_TAK; if (strcasecmp(fn + sz - 4, ".csv") == 0) return RTYPE_GEOFEED; + if (strcasecmp(fn + sz - 4, ".spl") == 0) + return RTYPE_SPL; return RTYPE_INVALID; } @@ -162,6 +164,7 @@ rtype_from_mftfile(const char *fn) case RTYPE_GBR: case RTYPE_ROA: case RTYPE_ASPA: + case RTYPE_SPL: case RTYPE_TAK: return type; default: diff --git a/usr.sbin/rpki-client/output-bgpd.c b/usr.sbin/rpki-client/output-bgpd.c index 1207f46d5..7bf47d304 100644 --- a/usr.sbin/rpki-client/output-bgpd.c +++ b/usr.sbin/rpki-client/output-bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-bgpd.c,v 1.28 2023/06/26 18:39:53 job Exp $ */ +/* $OpenBSD: output-bgpd.c,v 1.29 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -21,7 +21,7 @@ int output_bgpd(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { struct vrp *vrp; struct vap *vap; diff --git a/usr.sbin/rpki-client/output-bird.c b/usr.sbin/rpki-client/output-bird.c index 344f28d27..fca660507 100644 --- a/usr.sbin/rpki-client/output-bird.c +++ b/usr.sbin/rpki-client/output-bird.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-bird.c,v 1.18 2023/05/30 12:14:48 claudio Exp $ */ +/* $OpenBSD: output-bird.c,v 1.19 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * Copyright (c) 2020 Robert Scheck @@ -22,7 +22,7 @@ int output_bird1v4(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { extern const char *bird_tablename; struct vrp *v; @@ -51,7 +51,7 @@ output_bird1v4(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, int output_bird1v6(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { extern const char *bird_tablename; struct vrp *v; @@ -80,7 +80,7 @@ output_bird1v6(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, int output_bird2(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { extern const char *bird_tablename; struct vrp *v; diff --git a/usr.sbin/rpki-client/output-csv.c b/usr.sbin/rpki-client/output-csv.c index 6338b7cad..7e46c44d4 100644 --- a/usr.sbin/rpki-client/output-csv.c +++ b/usr.sbin/rpki-client/output-csv.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-csv.c,v 1.13 2022/08/30 18:56:49 job Exp $ */ +/* $OpenBSD: output-csv.c,v 1.14 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * @@ -21,7 +21,7 @@ int output_csv(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { struct vrp *v; diff --git a/usr.sbin/rpki-client/output-json.c b/usr.sbin/rpki-client/output-json.c index 9c8f3f2ba..8ff1e7f62 100644 --- a/usr.sbin/rpki-client/output-json.c +++ b/usr.sbin/rpki-client/output-json.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-json.c,v 1.42 2024/02/13 20:41:22 job Exp $ */ +/* $OpenBSD: output-json.c,v 1.43 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * @@ -47,6 +47,9 @@ outputheader_json(struct stats *st) json_do_int("roas", st->repo_tal_stats.roas); json_do_int("failedroas", st->repo_tal_stats.roas_fail); json_do_int("invalidroas", st->repo_tal_stats.roas_invalid); + json_do_int("spls", st->repo_tal_stats.spls); + json_do_int("failedspls", st->repo_tal_stats.spls_fail); + json_do_int("invalidspls", st->repo_tal_stats.spls_invalid); json_do_int("aspas", st->repo_tal_stats.aspas); json_do_int("failedaspas", st->repo_tal_stats.aspas_fail); json_do_int("invalidaspas", st->repo_tal_stats.aspas_invalid); @@ -69,6 +72,8 @@ outputheader_json(struct stats *st) json_do_int("repositories", st->repos); json_do_int("vrps", st->repo_tal_stats.vrps); json_do_int("uniquevrps", st->repo_tal_stats.vrps_uniqs); + json_do_int("vsps", st->repo_tal_stats.vsps); + json_do_int("uniquevsps", st->repo_tal_stats.vsps_uniqs); json_do_int("vaps", st->repo_tal_stats.vaps); json_do_int("uniquevaps", st->repo_tal_stats.vaps_uniqs); json_do_int("cachedir_del_files", st->repo_stats.del_files); @@ -109,11 +114,13 @@ output_aspa(struct vap_tree *vaps) int output_json(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { char buf[64]; struct vrp *v; struct brk *b; + struct vsp *vsp; + size_t i; json_do_start(out); outputheader_json(st); @@ -147,5 +154,22 @@ output_json(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, if (!excludeaspa) output_aspa(vaps); + json_do_array("signedprefixlists"); + RB_FOREACH(vsp, vsp_tree, vsps) { + json_do_object("vsp", 1); + json_do_int("origin_as", vsp->asid); + json_do_array("prefixes"); + for (i = 0; i < vsp->prefixesz; i++) { + ip_addr_print(&vsp->prefixes[i].prefix, + vsp->prefixes[i].afi, buf, sizeof(buf)); + json_do_string("prefix", buf); + } + json_do_end(); + json_do_int("expires", vsp->expires); + json_do_string("ta", taldescs[vsp->talid]); + json_do_end(); + } + json_do_end(); + return json_do_finish(); } diff --git a/usr.sbin/rpki-client/output-ometric.c b/usr.sbin/rpki-client/output-ometric.c index 1addf1672..b2775e159 100644 --- a/usr.sbin/rpki-client/output-ometric.c +++ b/usr.sbin/rpki-client/output-ometric.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-ometric.c,v 1.7 2024/02/13 20:41:22 job Exp $ */ +/* $OpenBSD: output-ometric.c,v 1.8 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2022 Claudio Jeker * @@ -82,6 +82,18 @@ set_common_stats(const struct repotalstats *in, struct ometric *metric, OKV("type", "state"), OKV("vap", "unique"), ol); ometric_set_int_with_labels(metric, in->vaps_pas, OKV("type", "state"), OKV("vap providers", "total"), ol); + + ometric_set_int_with_labels(metric, in->spls, + OKV("type", "state"), OKV("spl", "valid"), ol); + ometric_set_int_with_labels(metric, in->spls_fail, + OKV("type", "state"), OKV("spl", "failed parse"), ol); + ometric_set_int_with_labels(metric, in->spls_invalid, + OKV("type", "state"), OKV("spl", "invalid"), ol); + + ometric_set_int_with_labels(metric, in->vsps, + OKV("type", "state"), OKV("vsp", "total"), ol); + ometric_set_int_with_labels(metric, in->vsps_uniqs, + OKV("type", "state"), OKV("vsp", "unique"), ol); } static void @@ -146,7 +158,7 @@ repo_stats(const struct repo *rp, const struct repostats *in, void *arg) int output_ometric(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, - struct vap_tree *vaps, struct stats *st) + struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st) { struct olabels *ol; const char *keys[4] = { "nodename", "domainname", "release", NULL }; diff --git a/usr.sbin/rpki-client/output.c b/usr.sbin/rpki-client/output.c index e875698eb..e4725d66a 100644 --- a/usr.sbin/rpki-client/output.c +++ b/usr.sbin/rpki-client/output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output.c,v 1.32 2024/02/03 14:30:47 job Exp $ */ +/* $OpenBSD: output.c,v 1.33 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Theo de Raadt * @@ -64,7 +64,7 @@ static const struct outputs { int format; char *name; int (*fn)(FILE *, struct vrp_tree *, struct brk_tree *, - struct vap_tree *, struct stats *); + struct vap_tree *, struct vsp_tree *, struct stats *); } outputs[] = { { FORMAT_OPENBGPD, "openbgpd", output_bgpd }, { FORMAT_BIRD, "bird1v4", output_bird1v4 }, @@ -84,7 +84,7 @@ static void set_signal_handler(void); int outputfiles(struct vrp_tree *v, struct brk_tree *b, struct vap_tree *a, - struct stats *st) + struct vsp_tree *p, struct stats *st) { int i, rc = 0; @@ -103,7 +103,7 @@ outputfiles(struct vrp_tree *v, struct brk_tree *b, struct vap_tree *a, rc = 1; continue; } - if ((*outputs[i].fn)(fout, v, b, a, st) != 0) { + if ((*outputs[i].fn)(fout, v, b, a, p, st) != 0) { warn("output for %s format failed", outputs[i].name); fclose(fout); output_cleantmp(); diff --git a/usr.sbin/rpki-client/parser.c b/usr.sbin/rpki-client/parser.c index e1ef9b973..62ebcade6 100644 --- a/usr.sbin/rpki-client/parser.c +++ b/usr.sbin/rpki-client/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.128 2024/02/03 14:30:47 job Exp $ */ +/* $OpenBSD: parser.c,v 1.129 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -157,6 +157,41 @@ proc_parser_roa(char *file, const unsigned char *der, size_t len, return roa; } +/* + * Parse and validate a draft-ietf-sidrops-rpki-prefixlist SPL. + * Returns the spl on success, NULL on failure. + */ +static struct spl * +proc_parser_spl(char *file, const unsigned char *der, size_t len, + const struct entity *entp) +{ + struct spl *spl; + struct auth *a; + struct crl *crl; + X509 *x509; + const char *errstr; + + if ((spl = spl_parse(&x509, file, entp->talid, der, len)) == NULL) + return NULL; + + a = valid_ski_aki(file, &auths, spl->ski, spl->aki, entp->mftaki); + crl = crl_get(&crlt, a); + + if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { + warnx("%s: %s", file, errstr); + X509_free(x509); + spl_free(spl); + return NULL; + } + X509_free(x509); + + spl->talid = a->cert->talid; + + spl->expires = x509_find_expires(spl->notafter, a, &crlt); + + return spl; +} + /* * Check all files and their hashes in a MFT structure. * Return zero on failure, non-zero on success. @@ -681,6 +716,7 @@ parse_entity(struct entityq *q, struct msgbuf *msgq) struct aspa *aspa; struct gbr *gbr; struct tak *tak; + struct spl *spl; struct ibuf *b; unsigned char *f; time_t mtime, crlmtime; @@ -822,6 +858,19 @@ parse_entity(struct entityq *q, struct msgbuf *msgq) io_simple_buffer(b, &mtime, sizeof(mtime)); tak_free(tak); break; + case RTYPE_SPL: + file = parse_load_file(entp, &f, &flen); + io_str_buffer(b, file); + spl = proc_parser_spl(file, f, flen, entp); + if (spl != NULL) + mtime = spl->signtime; + io_simple_buffer(b, &mtime, sizeof(mtime)); + c = (spl != NULL); + io_simple_buffer(b, &c, sizeof(int)); + if (spl != NULL) + spl_buffer(b, spl); + spl_free(spl); + break; case RTYPE_CRL: default: file = parse_filepath(entp->repoid, entp->path, diff --git a/usr.sbin/rpki-client/print.c b/usr.sbin/rpki-client/print.c index 1e5503b2a..bb92910c1 100644 --- a/usr.sbin/rpki-client/print.c +++ b/usr.sbin/rpki-client/print.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print.c,v 1.49 2024/02/16 05:18:29 tb Exp $ */ +/* $OpenBSD: print.c,v 1.51 2024/02/22 19:29:55 tb Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -507,6 +507,60 @@ roa_print(const X509 *x, const struct roa *p) json_do_end(); } +void +spl_print(const X509 *x, const struct spl *s) +{ + char buf[128]; + size_t i; + + if (outformats & FORMAT_JSON) { + json_do_string("type", "spl"); + json_do_string("ski", pretty_key_id(s->ski)); + x509_print(x); + json_do_string("aki", pretty_key_id(s->aki)); + json_do_string("aia", s->aia); + json_do_string("sia", s->sia); + if (s->signtime != 0) + json_do_int("signing_time", s->signtime); + json_do_int("valid_since", s->notbefore); + json_do_int("valid_until", s->notafter); + if (s->expires) + json_do_int("expires", s->expires); + json_do_int("asid", s->asid); + } else { + printf("Subject key identifier: %s\n", pretty_key_id(s->ski)); + x509_print(x); + printf("Authority key identifier: %s\n", pretty_key_id(s->aki)); + printf("Authority info access: %s\n", s->aia); + printf("Subject info access: %s\n", s->sia); + if (s->signtime != 0) + printf("Signing time: %s\n", + time2str(s->signtime)); + printf("SPL not before: %s\n", + time2str(s->notbefore)); + printf("SPL not after: %s\n", time2str(s->notafter)); + printf("asID: %u\n", s->asid); + printf("Originated IP Prefixes: "); + } + + if (outformats & FORMAT_JSON) + json_do_array("prefixes"); + for (i = 0; i < s->pfxsz; i++) { + ip_addr_print(&s->pfxs[i].prefix, s->pfxs[i].afi, buf, + sizeof(buf)); + + if (outformats & FORMAT_JSON) { + json_do_string("prefix", buf); + } else { + if (i > 0) + printf("%26s", ""); + printf("%s\n", buf); + } + } + if (outformats & FORMAT_JSON) + json_do_end(); +} + void gbr_print(const X509 *x, const struct gbr *p) { diff --git a/usr.sbin/rpki-client/repo.c b/usr.sbin/rpki-client/repo.c index f1bf22ba5..60354de7f 100644 --- a/usr.sbin/rpki-client/repo.c +++ b/usr.sbin/rpki-client/repo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: repo.c,v 1.52 2024/02/03 14:30:47 job Exp $ */ +/* $OpenBSD: repo.c,v 1.53 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -1480,6 +1480,30 @@ repo_stat_inc(struct repo *rp, int talid, enum rtype type, enum stype subtype) break; } break; + case RTYPE_SPL: + switch (subtype) { + case STYPE_OK: + rp->stats[talid].spls++; + break; + case STYPE_FAIL: + rp->stats[talid].spls_fail++; + break; + case STYPE_INVALID: + rp->stats[talid].spls_invalid++; + break; + case STYPE_TOTAL: + rp->stats[talid].vsps++; + break; + case STYPE_UNIQUE: + rp->stats[talid].vsps_uniqs++; + break; + case STYPE_DEC_UNIQUE: + rp->stats[talid].vsps_uniqs--; + break; + default: + break; + } + break; case RTYPE_CRL: rp->stats[talid].crls++; break; diff --git a/usr.sbin/rpki-client/rpki-client.8 b/usr.sbin/rpki-client/rpki-client.8 index a7d2d0e27..057eff62d 100644 --- a/usr.sbin/rpki-client/rpki-client.8 +++ b/usr.sbin/rpki-client/rpki-client.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rpki-client.8,v 1.100 2024/01/31 17:19:02 job Exp $ +.\" $OpenBSD: rpki-client.8,v 1.102 2024/02/22 17:54:08 tb Exp $ .\" .\" Copyright (c) 2019 Kristaps Dzonsons .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 31 2024 $ +.Dd $Mdocdate: February 22 2024 $ .Dt RPKI-CLIENT 8 .Os .Sh NAME @@ -269,7 +269,8 @@ file imposes constraints on the Trust Anchor reachable via the same-named .Em .tal file. One entry per line. -Entries can be IP prefixes, IP address ranges, AS identifiers, or AS identifier ranges. +Entries can be IP prefixes, IP address ranges, +AS identifiers, or AS identifier ranges. Ranges are a minimum and maximum separated by a hyphen .Pq Sq - . Comments can be put anywhere in the file using a hash mark @@ -451,6 +452,12 @@ agreement regarding ARIN service restrictions. .%U https://datatracker.ietf.org/doc/html/draft-spaghetti-sidrops-rrdp-desynchronization-00 .%D Jan, 2024 .Re +.Pp +.Rs +.%T A profile for Signed Prefix Lists for Use in the Resource Public Key Infrastructure (RPKI) +.%U https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-rpki-prefixlist-02 +.%D Jan, 2024 +.Re .Sh HISTORY .Nm first appeared in diff --git a/usr.sbin/rpki-client/spl.c b/usr.sbin/rpki-client/spl.c new file mode 100644 index 000000000..4a8f397e3 --- /dev/null +++ b/usr.sbin/rpki-client/spl.c @@ -0,0 +1,487 @@ +/* $OpenBSD: spl.c,v 1.2 2024/02/22 19:29:55 tb Exp $ */ +/* + * Copyright (c) 2024 Job Snijders + * Copyright (c) 2022 Theo Buehler + * Copyright (c) 2019 Kristaps Dzonsons + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +extern ASN1_OBJECT *spl_oid; + +/* + * Types and templates for the SPL eContent. + */ + +ASN1_ITEM_EXP AddressFamilyPrefixes_it; +ASN1_ITEM_EXP SignedPrefixList_it; + +DECLARE_STACK_OF(ASN1_BIT_STRING); + +typedef struct { + ASN1_OCTET_STRING *addressFamily; + STACK_OF(ASN1_BIT_STRING) *addressPrefixes; +} AddressFamilyPrefixes; + +DECLARE_STACK_OF(AddressFamilyPrefixes); + +ASN1_SEQUENCE(AddressFamilyPrefixes) = { + ASN1_SIMPLE(AddressFamilyPrefixes, addressFamily, ASN1_OCTET_STRING), + ASN1_SEQUENCE_OF(AddressFamilyPrefixes, addressPrefixes, + ASN1_BIT_STRING), +} ASN1_SEQUENCE_END(AddressFamilyPrefixes); + +#ifndef DEFINE_STACK_OF +#define sk_ASN1_BIT_STRING_num(st) SKM_sk_num(ASN1_BIT_STRING, (st)) +#define sk_ASN1_BIT_STRING_value(st, i) SKM_sk_value(ASN1_BIT_STRING, (st), (i)) + +#define sk_AddressFamilyPrefixes_num(st) \ + SKM_sk_num(AddressFamilyPrefixes, (st)) +#define sk_AddressFamilyPrefixes_value(st, i) \ + SKM_sk_value(AddressFamilyPrefixes, (st), (i)) +#endif + +typedef struct { + ASN1_INTEGER *version; + ASN1_INTEGER *asid; + STACK_OF(AddressFamilyPrefixes) *prefixBlocks; +} SignedPrefixList; + +ASN1_SEQUENCE(SignedPrefixList) = { + ASN1_EXP_OPT(SignedPrefixList, version, ASN1_INTEGER, 0), + ASN1_SIMPLE(SignedPrefixList, asid, ASN1_INTEGER), + ASN1_SEQUENCE_OF(SignedPrefixList, prefixBlocks, AddressFamilyPrefixes) +} ASN1_SEQUENCE_END(SignedPrefixList); + +DECLARE_ASN1_FUNCTIONS(SignedPrefixList); +IMPLEMENT_ASN1_FUNCTIONS(SignedPrefixList); + +/* + * Comparator to help sorting elements in SPL prefixBlocks and VSPs. + * Returns -1 if 'a' should precede 'b', 1 if 'b' should precede 'a', + * or '0' if a and b are equal. + */ +static int +prefix_cmp(enum afi afi, const struct ip_addr *a, const struct ip_addr *b) +{ + int cmp; + + switch (afi) { + case AFI_IPV4: + cmp = memcmp(&a->addr, &b->addr, 4); + if (cmp < 0) + return -1; + if (cmp > 0) + return 1; + break; + case AFI_IPV6: + cmp = memcmp(&a->addr, &b->addr, 16); + if (cmp < 0) + return -1; + if (cmp > 0) + return 1; + break; + default: + break; + } + + if (a->prefixlen < b->prefixlen) + return -1; + if (a->prefixlen > b->prefixlen) + return 1; + + return 0; +} + +/* + * Parses the eContent section of a SPL file, + * draft-ietf-sidrops-rpki-prefixlist-02 section 3. + * Returns zero on failure, non-zero on success. + */ +static int +spl_parse_econtent(const char *fn, struct spl *spl, const unsigned char *d, + size_t dsz) +{ + const unsigned char *oder; + SignedPrefixList *spl_asn1; + const AddressFamilyPrefixes *afp; + const STACK_OF(ASN1_BIT_STRING) *prefixes; + const ASN1_BIT_STRING *prefix_asn1; + int afpsz, prefixesz; + enum afi afi; + struct ip_addr ip_addr; + struct spl_pfx *prefix; + int ipv4_seen = 0, ipv6_seen = 0; + int i, j, rc = 0; + + oder = d; + if ((spl_asn1 = d2i_SignedPrefixList(NULL, &d, dsz)) == NULL) { + warnx("%s: RFC 6482 section 3: failed to parse " + "SignedPrefixList", fn); + goto out; + } + if (d != oder + dsz) { + warnx("%s: %td bytes trailing garbage in eContent", fn, + oder + dsz - d); + goto out; + } + + if (!valid_econtent_version(fn, spl_asn1->version, 0)) + goto out; + + if (!as_id_parse(spl_asn1->asid, &spl->asid)) { + warnx("%s: asid: malformed AS identifier", fn); + goto out; + } + + afpsz = sk_AddressFamilyPrefixes_num(spl_asn1->prefixBlocks); + if (afpsz < 0 || afpsz > 2) { + warnx("%s: unexpected number of AddressFamilyAddressPrefixes" + "(got %d, expected 0, 1, or 2)", fn, afpsz); + goto out; + } + + for (i = 0; i < afpsz; i++) { + struct ip_addr *prev_ip_addr = NULL; + + afp = sk_AddressFamilyPrefixes_value(spl_asn1->prefixBlocks, i); + prefixes = afp->addressPrefixes; + prefixesz = sk_ASN1_BIT_STRING_num(afp->addressPrefixes); + + if (prefixesz == 0) { + warnx("%s: empty AddressFamilyAddressPrefixes", fn); + goto out; + } + if (spl->pfxsz + prefixesz >= MAX_IP_SIZE) { + warnx("%s: too many addressPrefixes entries", fn); + goto out; + } + + if (!ip_addr_afi_parse(fn, afp->addressFamily, &afi)) + goto out; + + switch (afi) { + case AFI_IPV4: + if (ipv4_seen++ > 0) { + warnx("%s: addressFamilyIPv4 appeared twice", + fn); + goto out; + } + if (ipv6_seen > 0) { + warnx("%s: invalid sorting, IPv6 before IPv4", + fn); + goto out; + } + break; + case AFI_IPV6: + if (ipv6_seen++ > 0) { + warnx("%s: addressFamilyIPv6 appeared twice", + fn); + goto out; + } + } + + spl->pfxs = recallocarray(spl->pfxs, spl->pfxsz, + spl->pfxsz + prefixesz, sizeof(struct spl_pfx)); + if (spl->pfxs == NULL) + err(1, NULL); + + for (j = 0; j < prefixesz; j++) { + prefix_asn1 = sk_ASN1_BIT_STRING_value(prefixes, j); + + if (!ip_addr_parse(prefix_asn1, afi, fn, &ip_addr)) + goto out; + + if (j > 0 && + prefix_cmp(afi, prev_ip_addr, &ip_addr) != -1) { + warnx("%s: invalid addressPrefixes sorting", fn); + goto out; + } + + prefix = &spl->pfxs[spl->pfxsz++]; + prefix->prefix = ip_addr; + prefix->afi = afi; + prev_ip_addr = &prefix->prefix; + } + } + + rc = 1; + out: + SignedPrefixList_free(spl_asn1); + return rc; +} + +/* + * Parse a full Signed Prefix List file. + * Returns the SPL, or NULL if the object was malformed. + */ +struct spl * +spl_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, + size_t len) +{ + struct spl *spl; + size_t cmsz; + unsigned char *cms; + struct cert *cert = NULL; + time_t signtime = 0; + int rc = 0; + + cms = cms_parse_validate(x509, fn, der, len, spl_oid, &cmsz, &signtime); + if (cms == NULL) + return NULL; + + if ((spl = calloc(1, sizeof(*spl))) == NULL) + err(1, NULL); + spl->signtime = signtime; + + if (!x509_get_aia(*x509, fn, &spl->aia)) + goto out; + if (!x509_get_aki(*x509, fn, &spl->aki)) + goto out; + if (!x509_get_sia(*x509, fn, &spl->sia)) + goto out; + if (!x509_get_ski(*x509, fn, &spl->ski)) + goto out; + if (spl->aia == NULL || spl->aki == NULL || spl->sia == NULL || + spl->ski == NULL) { + warnx("%s: RFC 6487 section 4.8: " + "missing AIA, AKI, SIA, or SKI X509 extension", fn); + goto out; + } + + if (!x509_get_notbefore(*x509, fn, &spl->notbefore)) + goto out; + if (!x509_get_notafter(*x509, fn, &spl->notafter)) + goto out; + + if (!spl_parse_econtent(fn, spl, cms, cmsz)) + goto out; + + if (x509_any_inherits(*x509)) { + warnx("%s: inherit elements not allowed in EE cert", fn); + goto out; + } + + if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) + goto out; + + if (cert->asz == 0) { + warnx("%s: AS Resources extension missing", fn); + goto out; + } + + if (cert->ipsz > 0) { + warnx("%s: superfluous IP Resources extension present", fn); + goto out; + } + + /* + * If the SPL isn't valid, we accept it anyway and depend upon + * the code around spl_read() to check the "valid" field itself. + */ + spl->valid = valid_spl(fn, cert, spl); + + rc = 1; + out: + if (rc == 0) { + spl_free(spl); + spl = NULL; + X509_free(*x509); + *x509 = NULL; + } + cert_free(cert); + free(cms); + return spl; +} + +void +spl_free(struct spl *s) +{ + if (s == NULL) + return; + + free(s->aia); + free(s->aki); + free(s->sia); + free(s->ski); + free(s->pfxs); + free(s); +} + +/* + * Serialize parsed SPL content. + * See spl_read() for reader. + */ +void +spl_buffer(struct ibuf *b, const struct spl *s) +{ + io_simple_buffer(b, &s->valid, sizeof(s->valid)); + io_simple_buffer(b, &s->asid, sizeof(s->asid)); + io_simple_buffer(b, &s->talid, sizeof(s->talid)); + io_simple_buffer(b, &s->pfxsz, sizeof(s->pfxsz)); + io_simple_buffer(b, &s->expires, sizeof(s->expires)); + + io_simple_buffer(b, s->pfxs, s->pfxsz * sizeof(s->pfxs[0])); + + io_str_buffer(b, s->aia); + io_str_buffer(b, s->aki); + io_str_buffer(b, s->ski); +} + +/* + * Read parsed SPL content from descriptor. + * See spl_buffer() for writer. + * Result must be passed to spl_free(). + */ +struct spl * +spl_read(struct ibuf *b) +{ + struct spl *s; + + if ((s = calloc(1, sizeof(struct spl))) == NULL) + err(1, NULL); + + io_read_buf(b, &s->valid, sizeof(s->valid)); + io_read_buf(b, &s->asid, sizeof(s->asid)); + io_read_buf(b, &s->talid, sizeof(s->talid)); + io_read_buf(b, &s->pfxsz, sizeof(s->pfxsz)); + io_read_buf(b, &s->expires, sizeof(s->expires)); + + if ((s->pfxs = calloc(s->pfxsz, sizeof(struct spl_pfx))) == NULL) + err(1, NULL); + io_read_buf(b, s->pfxs, s->pfxsz * sizeof(s->pfxs[0])); + + io_read_str(b, &s->aia); + io_read_str(b, &s->aki); + io_read_str(b, &s->ski); + assert(s->aia && s->aki && s->ski); + + return s; +} + +static int +spl_pfx_cmp(const struct spl_pfx *a, const struct spl_pfx *b) +{ + if (a->afi > b->afi) + return 1; + if (a->afi < b->afi) + return -1; + + return prefix_cmp(a->afi, &a->prefix, &b->prefix); +} + +static void +insert_vsp(struct vsp *vsp, size_t idx, struct spl_pfx *pfx) +{ + if (idx < vsp->prefixesz) + memmove(vsp->prefixes + idx + 1, vsp->prefixes + idx, + (vsp->prefixesz - idx) * sizeof(*vsp->prefixes)); + vsp->prefixes[idx] = *pfx; + vsp->prefixesz++; +} + +/* + * Add each prefix in the SPL into the VSP tree. + * Updates "vsps" to be the number of VSPs and "uniqs" to be the unique + * number of prefixes. + */ +void +spl_insert_vsps(struct vsp_tree *tree, struct spl *spl, struct repo *rp) +{ + struct vsp *vsp, *found; + size_t i, j; + int cmp; + + if ((vsp = calloc(1, sizeof(*vsp))) == NULL) + err(1, NULL); + + vsp->asid = spl->asid; + vsp->talid = spl->talid; + vsp->expires = spl->expires; + if (rp != NULL) + vsp->repoid = repo_id(rp); + + if ((found = RB_INSERT(vsp_tree, tree, vsp)) != NULL) { + /* already exists */ + if (found->expires < vsp->expires) { + /* adjust unique count */ + repo_stat_inc(repo_byid(found->repoid), + found->talid, RTYPE_SPL, STYPE_DEC_UNIQUE); + found->expires = vsp->expires; + found->talid = vsp->talid; + found->repoid = vsp->repoid; + repo_stat_inc(rp, vsp->talid, RTYPE_SPL, + STYPE_UNIQUE); + } + free(vsp); + vsp = found; + } else + repo_stat_inc(rp, vsp->talid, RTYPE_SPL, STYPE_UNIQUE); + repo_stat_inc(rp, spl->talid, RTYPE_SPL, STYPE_TOTAL); + + /* merge content of multiple SPLs */ + vsp->prefixes = reallocarray(vsp->prefixes, + vsp->prefixesz + spl->pfxsz, sizeof(struct spl_pfx)); + if (vsp->prefixes == NULL) + err(1, NULL); + + /* + * Merge all data from the new SPL at hand into 'vsp': loop over + * all SPL->pfxs, and insert them in the right place in + * vsp->prefixes while keeping the order of the array. + */ + for (i = 0, j = 0; i < spl->pfxsz; ) { + cmp = -1; + if (j == vsp->prefixesz || + (cmp = spl_pfx_cmp(&spl->pfxs[i], &vsp->prefixes[j])) < 0) { + insert_vsp(vsp, j, &spl->pfxs[i]); + i++; + } else if (cmp == 0) + i++; + + if (j < vsp->prefixesz) + j++; + } +} + +/* + * Comparison function for the RB tree + */ +static inline int +vspcmp(const struct vsp *a, const struct vsp *b) +{ + if (a->asid > b->asid) + return 1; + if (a->asid < b->asid) + return -1; + + return 0; +} + +RB_GENERATE(vsp_tree, vsp, entry, vspcmp); diff --git a/usr.sbin/rpki-client/validate.c b/usr.sbin/rpki-client/validate.c index c0c4ee5e9..5d4656cb5 100644 --- a/usr.sbin/rpki-client/validate.c +++ b/usr.sbin/rpki-client/validate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: validate.c,v 1.71 2024/02/01 15:11:38 tb Exp $ */ +/* $OpenBSD: validate.c,v 1.72 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -194,6 +194,22 @@ valid_roa(const char *fn, struct cert *cert, struct roa *roa) return 1; } +/* + * Validate our SPL: check that the asID is contained in the end-entity + * certificate's resources. + * Returns 1 if valid, 0 otherwise. + */ +int +valid_spl(const char *fn, struct cert *cert, struct spl *spl) +{ + if (as_check_covered(spl->asid, spl->asid, cert->as, cert->asz) > 0) + return 1; + + warnx("%s: SPL: uncovered ASID: %u", fn, spl->asid); + + return 0; +} + /* * Validate a file by verifying the SHA256 hash of that file. * The file to check is passed as a file descriptor. diff --git a/usr.sbin/rpki-client/x509.c b/usr.sbin/rpki-client/x509.c index c9e340b6c..5646eb715 100644 --- a/usr.sbin/rpki-client/x509.c +++ b/usr.sbin/rpki-client/x509.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509.c,v 1.80 2024/02/16 05:18:29 tb Exp $ */ +/* $OpenBSD: x509.c,v 1.81 2024/02/22 12:49:42 job Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2021 Claudio Jeker @@ -44,6 +44,7 @@ ASN1_OBJECT *rsc_oid; /* id-ct-signedChecklist */ ASN1_OBJECT *aspa_oid; /* id-ct-ASPA */ ASN1_OBJECT *tak_oid; /* id-ct-SignedTAL */ ASN1_OBJECT *geofeed_oid; /* id-ct-geofeedCSVwithCRLF */ +ASN1_OBJECT *spl_oid; /* id-ct-signedPrefixList */ static const struct { const char *oid; @@ -117,6 +118,10 @@ static const struct { .oid = "1.2.840.113549.1.9.16.1.50", .ptr = &tak_oid, }, + { + .oid = "1.2.840.113549.1.9.16.1.51", + .ptr = &spl_oid, + }, }; void